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

Reply via email to