[llvm] [CodeGen] [EarlyIfConversion] Prioritize conversion of hard to predict branches (PR #174457)
Jon Roelofs via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 6 11:22:55 PST 2026
================
@@ -896,6 +908,142 @@ void EarlyIfConverter::invalidateTraces() {
Traces->verifyAnalysis();
}
+/// Check if a register's value comes from a memory load by walking the
+/// def-use chain. Results are cached for virtual registers only.
+bool EarlyIfConverter::doOperandsComeFromMemory(Register Reg) {
+ if (!Reg.isVirtual())
+ return false;
+
+ // Check cache first.
+ auto It = OperandMemoryCache.find(Reg);
+ if (It != OperandMemoryCache.end())
+ return It->second;
+
+ // Walk the def-use chain.
+ SmallPtrSet<const MachineInstr *, 16> Visited;
+ SmallVector<const MachineInstr *, 16> Worklist;
+ SmallVector<Register, 16> VisitedRegs;
+
+ MachineInstr *DefMI = MRI->getVRegDef(Reg);
+ // The operand is defined outside of the function - it does not
+ // come from memory access.
+ if (!DefMI) {
+ OperandMemoryCache[Reg] = false;
+ return false;
+ }
+
+ Worklist.push_back(DefMI);
+ VisitedRegs.push_back(Reg);
+
+ while (!Worklist.empty()) {
+ const MachineInstr *MI = Worklist.pop_back_val();
+ if (!Visited.insert(MI).second)
+ continue;
+
+ // Check if this instruction is a load.
+ if (MI->mayLoad()) {
+ LLVM_DEBUG(dbgs() << "Operand comes from load: " << *MI);
+ // Cache all visited virtual registers as coming from memory.
+ for (Register Reg : VisitedRegs)
+ OperandMemoryCache[Reg] = true;
+ return true;
+ }
+
+ // Walk through all register use operands and find their definitions.
+ for (const MachineOperand &MO : MI->operands()) {
+ if (!MO.isReg() || !MO.isUse())
+ continue;
+ Register UseReg = MO.getReg();
+ if (!UseReg.isVirtual())
+ continue;
+
+ // Check cache for this operand.
+ auto CacheIt = OperandMemoryCache.find(UseReg);
+ if (CacheIt != OperandMemoryCache.end()) {
+ if (CacheIt->second) {
+ for (Register Reg : VisitedRegs)
+ OperandMemoryCache[Reg] = true;
+ return true;
+ }
+ continue;
+ }
+
+ MachineInstr *UseDef = MRI->getVRegDef(UseReg);
+ if (UseDef && !Visited.count(UseDef)) {
+ Worklist.push_back(UseDef);
+ VisitedRegs.push_back(UseReg);
+ }
+ }
+ }
+
+ // No load found, cache all visited virtual registers as not from memory.
+ for (Register Reg : VisitedRegs)
+ OperandMemoryCache[Reg] = false;
+ return false;
+}
+
+/// Check if the branch condition is data-dependent (comes from memory loads).
+bool EarlyIfConverter::isConditionDataDependent() {
+ MachineBasicBlock::iterator BranchIt = IfConv.Head->getFirstTerminator();
+ if (BranchIt == IfConv.Head->end())
+ return false;
+
+ // Get the status flags register from the target. If the target hasn't
+ // implemented this hook, we skip physical register analysis entirely
+ // and fallback to the previous behavior.
+ MCRegister StatusFlagsReg = TRI->getStatusFlagsRegister();
+
+ if (!StatusFlagsReg.isValid())
+ return false;
+
+ for (const MachineOperand &MO : BranchIt->operands()) {
+ if (!MO.isReg() || !MO.isUse())
+ continue;
+ Register Reg = MO.getReg();
+
+ if (Reg.isVirtual()) {
+ if (doOperandsComeFromMemory(Reg)) {
+ LLVM_DEBUG(dbgs() << "Condition is data-dependent (from memory)\n");
+ ++NumDataDependant;
+ return true;
+ }
+ } else if (Reg.isPhysical() && TRI->regsOverlap(Reg, StatusFlagsReg)) {
+ // For the status flags register (e.g., NZCV on AArch64),
+ // search backwards to find the defining instruction.
+ for (auto I = std::prev(BranchIt);; --I) {
+ // Check if this instruction defines the status flags register.
+ bool FoundDef = false;
+ for (const MachineOperand &DefMO : I->operands()) {
+ if (DefMO.isReg() && DefMO.isDef() &&
+ TRI->regsOverlap(DefMO.getReg(), StatusFlagsReg)) {
+ FoundDef = true;
+ break;
+ }
+ }
+
+ if (FoundDef) {
+ for (const MachineOperand &DefMO : I->operands()) {
+ if (!DefMO.isReg() || !DefMO.isUse())
+ continue;
+ Register DefReg = DefMO.getReg();
+ if (DefReg.isVirtual() && doOperandsComeFromMemory(DefReg)) {
+ LLVM_DEBUG(dbgs()
+ << "Condition is data-dependent (from memory)\n");
+ ++NumDataDependant;
+ return true;
+ }
+ }
+ break;
+ }
+
+ if (I == IfConv.Head->begin())
----------------
jroelofs wrote:
should this go in the middle `; ;` of the `for`? feels a bit weird for that to be empty, and this to be here.
https://github.com/llvm/llvm-project/pull/174457
More information about the llvm-commits
mailing list