On Thu, 30 Jul 2026 05:09:50 +0200 Anton Johansson <[email protected]> wrote:
> Convert llvm.returnaddress arguments to cpu_[ld|st]*() to undef, causing > the LLVM optmizer to discard the intrinsics. Needed as > llvm.returnadress is not representable in TCG, and usually results from > usage of GETPC() in helper functions. > > Signed-off-by: Anton Johansson <[email protected]> > --- > .../PrepareForOptPass/PrepareForOptPass.cpp | 47 +++++++++++++++++++ > 1 file changed, 47 insertions(+) > > diff --git > a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp > b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp > index df6d9eeec8..157f8cd05e 100644 > --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp > +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp > @@ -29,6 +29,7 @@ > #include <llvm/IR/Function.h> > #include <llvm/IR/Instruction.h> > #include <llvm/IR/Instructions.h> > +#include <llvm/IR/Intrinsics.h> > #include <llvm/IR/Module.h> > #include <llvm/Support/Debug.h> > > @@ -241,10 +242,56 @@ static void cullUnusedFunctions(Module &M, > AnnotationMapTy &Annotations) { > } > } > > +struct RetAddrReplaceInfo { > + User *Parent; > + unsigned OpIndex; > + Type *Ty; > +}; > + > +static void replaceRetaddrWithUndef(Module &M) { > + // Replace uses of llvm.returnaddress arguments to cpu_ld* w. undef, > + // and let optimizations remove it. Needed as llvm.returnaddress is > + // not reprensentable in TCG. I'd add a brief comment about what's the use in helpers of `llvm.returnaddress`, possibly with a reference to the part of code emitting it. This way, if someone changes things around that part of the code will (hopefully) `git grep` this. > + SmallVector<RetAddrReplaceInfo, 24> UsesToReplace; > + Function *Retaddr = compat::Intrinsic::getOrInsertDeclaration( > + &M, Intrinsic::returnaddress, {}); > + // Loop over all calls to llvm.returnaddress > + for (auto *CallUser : Retaddr->users()) { > + auto *Call = dyn_cast<CallInst>(CallUser); > + if (!Call) { > + continue; > + } > + for (auto *PtrToIntUser : Call->users()) { > + auto *Cast = dyn_cast<PtrToIntInst>(PtrToIntUser); > + if (!Cast) { > + continue; > + } > + for (Use &U : Cast->uses()) { > + auto *Call = dyn_cast<CallInst>(U.getUser()); > + Function *F = Call->getCalledFunction(); > + if (compat::isFunctionQemuLoadStore(F->getName())) { > + UsesToReplace.push_back({ > + .Parent = U.getUser(), > + .OpIndex = U.getOperandNo(), > + .Ty = U->getType(), > + }); > + } > + } > + } > + } > + > + // Defer replacement to not invalidate iterators > + for (RetAddrReplaceInfo &RI : UsesToReplace) { > + auto *Undef = UndefValue::get(RI.Ty); > + RI.Parent->setOperand(RI.OpIndex, Undef); > + } > +} > + > PreservedAnalyses PrepareForOptPass::run(Module &M, > ModuleAnalysisManager &MAM) { > demangleFunctionNames(M); > collectAnnotations(M, ResultAnnotations); > cullUnusedFunctions(M, ResultAnnotations); > + replaceRetaddrWithUndef(M); > return PreservedAnalyses::none(); > } > -- > 2.52.0 Reviewed-by: Alessandro Di Federico <[email protected]> -- Alessandro Di Federico rev.ng Labs
