diff --git a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp --- a/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp +++ b/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp @@ -46,6 +46,7 @@ void checkIR(Module &M); bool adjustIR(Module &M); bool removePassThroughBuiltin(Module &M); + bool serializeCond(Module &M); }; } // End anonymous namespace @@ -120,8 +121,67 @@ return Changed; } +bool BPFCheckAndAdjustIR::serializeCond(Module &M) { + // Forcing to lower an icmp condition if it is used + // in multiple places. + // For: + // icmp1 = ... + // ... + // a = select icmp1, val1, val2 + // ... + // ... icmp1 ... + // Change to: + // icmp1 = ... + // icmp1 = user_asm_barrier(icmp1) + // ... + // a = select icmp1, val1, val2 + // ... + // ... icmp1 ... + SmallVector Candidates; + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + auto *Cond = dyn_cast(&I); + if (!Cond || Cond->use_empty() || Cond->hasOneUse()) + continue; + Candidates.push_back(Cond); + } + + if (Candidates.empty()) + return false; + + bool Changed = false; + for (auto *Cond : Candidates) { + SmallVector Uses; + for (User *U : Cond->users()) { + Instruction *Inst = dyn_cast(U); + if (!Inst || (!isa(Inst) && !isa(Inst))) + continue; + Uses.push_back(Inst); + } + if (Uses.size() < 2) + continue; + + Changed = true; + Instruction *NextI = Cond->getNextNonDebugInstruction(); + assert(NextI); + FunctionType *AsmTy = FunctionType::get(Cond->getType(), {Cond->getType()}, false); + InlineAsm *Asm = InlineAsm::get(AsmTy, StringRef(""), StringRef("=r,0"), true); + auto *CI = CallInst::Create(Asm, {Cond}, "", NextI); + for (Instruction *Inst : Uses) { + Inst->setOperand(0, CI); + } + } + + return Changed; +} + bool BPFCheckAndAdjustIR::adjustIR(Module &M) { - return removePassThroughBuiltin(M); + bool Changed = false; + + Changed = removePassThroughBuiltin(M); + Changed = serializeCond(M) || Changed; + return Changed; } bool BPFCheckAndAdjustIR::runOnModule(Module &M) {