[llvm] [AMDGPU] Use S_CMP to lower a copy of a lane mask to SCC (PR #221445)
Jay Foad via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 02:11:22 PDT 2026
================
@@ -5037,6 +5037,106 @@ bool SIInstrInfo::hasVALU32BitEncoding(unsigned Opcode) const {
return pseudoToMCOpcode(Op32) != -1;
}
+/// Return true if \p MI is a VALU comparison, i.e. an instruction that writes
+/// a lane mask with one bit per lane, and zeroes the bits of lanes that were
+/// inactive when it executed. The VOP3 (_e64) encodings are not themselves
+/// marked as VOPC, so also check the VOPC (_e32) equivalent.
+///
+/// TODO: Also handle the sdst result of V_ADD_CO_U32 and V_SUB_CO_U32 amd
+/// V_DIV_SCALE_F32.
+static bool isVCmp(const SIInstrInfo &TII, const MachineInstr &MI) {
+ if (TII.isVOPC(MI))
+ return true;
+ int Op32 = AMDGPU::getVOPe32(MI.getOpcode());
+ return Op32 != -1 && TII.isVOPC(Op32);
+}
+
+/// Worker for SIInstrInfo::isMaskedByExec. Every definition the result depends
+/// on must be in \p MBB, and is added to \p Defs so that the caller can check
+/// that EXEC is not modified between it and the use. Definitions are removed
+/// again when a branch of the search fails, so that on success \p Defs only
+/// holds definitions the result really depends on.
+static bool isMaskedByExecImpl(const SIInstrInfo &TII,
+ const AMDGPU::LaneMaskConstants &LMC,
+ Register Reg, const MachineBasicBlock *MBB,
+ SmallSetVector<const MachineInstr *, 8> &Defs,
+ const MachineRegisterInfo &MRI, unsigned Depth) {
+ // EXEC itself is trivially masked by EXEC.
+ if (Reg == LMC.ExecReg)
+ return true;
+
+ if (Depth == 0 || !Reg.isVirtual())
+ return false;
+
+ // Only look at definitions that can execute under the same EXEC mask as the
+ // use. Note that this also rules out instructions that write EXEC
+ // themselves, such as V_CMPX, since those would be found by the caller's
+ // scan for writes to EXEC.
+ const MachineInstr *Def = MRI.getVRegDef(Reg);
+ if (Def->getParent() != MBB)
+ return false;
+
+ size_t NumDefs = Defs.size();
+ Defs.insert(Def);
+
+ if (isVCmp(TII, *Def))
+ return true;
+
+ // Recurse into an operand, which must be a whole register to say anything
+ // about the whole lane mask. A failed call rolls back its own additions.
+ auto Recurse = [&](unsigned OpIdx) {
+ const MachineOperand &MO = Def->getOperand(OpIdx);
+ return MO.isReg() && !MO.getSubReg() &&
+ isMaskedByExecImpl(TII, LMC, MO.getReg(), MBB, Defs, MRI, Depth - 1);
+ };
+
+ unsigned Opc = Def->getOpcode();
+ if (Opc == AMDGPU::COPY && Recurse(1))
+ return true;
+ // AND only needs one masked operand, because a zero bit in either operand
+ // forces a zero bit in the result.
+ if (Opc == LMC.AndOpc && (Recurse(1) || Recurse(2)))
+ return true;
+ // Likewise ANDN2, but only for its first operand.
+ if (Opc == LMC.AndN2Opc && Recurse(1))
+ return true;
+ if ((Opc == LMC.OrOpc || Opc == LMC.XorOpc) && Recurse(1) && Recurse(2))
+ return true;
+
+ // Roll back, so that a caller that succeeds by another route is not left
+ // depending on definitions it does not actually use.
+ while (Defs.size() > NumDefs)
+ Defs.pop_back();
+ return false;
+}
+
+bool SIInstrInfo::isMaskedByExec(Register Reg, const MachineInstr &Use,
+ const MachineRegisterInfo &MRI) const {
+ assert(MRI.isSSA() && "isMaskedByExec requires SSA form");
+ const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(ST);
+ const MachineBasicBlock *MBB = Use.getParent();
+
+ // Maximum depth of the def-use walk.
+ constexpr unsigned MaxDepth = 6;
+ SmallSetVector<const MachineInstr *, 8> Defs;
+ if (!isMaskedByExecImpl(*this, LMC, Reg, MBB, Defs, MRI, MaxDepth))
+ return false;
+
+ // Walk back from Use, which every definition dominates, and check that all
+ // of them are reached before any write to EXEC. Otherwise the mask may have
+ // been computed under an EXEC that is not a subset of the one in effect at
+ // Use, and so may have bits set for lanes that are now inactive.
+ unsigned NumDefsToFind = Defs.size();
+ for (const MachineInstr &Prev : reverse(
+ make_range(MBB->begin(), MachineBasicBlock::const_iterator(Use)))) {
----------------
jayfoad wrote:
This code was removed anyway.
https://github.com/llvm/llvm-project/pull/221445
More information about the llvm-commits
mailing list