diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3692,6 +3692,7 @@ bool IsVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); + MachineFunction::CallSiteInfo CSInfo; bool IsThisReturn = false; AArch64FunctionInfo *FuncInfo = MF.getInfo(); @@ -3889,9 +3890,20 @@ }) ->second; Bits = DAG.getNode(ISD::OR, DL, Bits.getValueType(), Bits, Arg); + // Call site info is used for function's parameter entry value + // tracking. For now we track only simple cases when parameter + // is transferred through whole register. + CSInfo.erase(std::remove_if(CSInfo.begin(), CSInfo.end(), + [&VA](MachineFunction::ArgRegPair ArgReg) { + return ArgReg.Reg == VA.getLocReg(); + }), + CSInfo.end()); } else { RegsToPass.emplace_back(VA.getLocReg(), Arg); RegsUsed.insert(VA.getLocReg()); + const TargetOptions &Options = DAG.getTarget().Options; + if (Options.EnableDebugEntryValues) + CSInfo.emplace_back(VA.getLocReg(), i); } } else { assert(VA.isMemLoc()); @@ -4072,12 +4084,15 @@ // actual call instruction. if (IsTailCall) { MF.getFrameInfo().setHasTailCall(); - return DAG.getNode(AArch64ISD::TC_RETURN, DL, NodeTys, Ops); + SDValue Ret = DAG.getNode(AArch64ISD::TC_RETURN, DL, NodeTys, Ops); + DAG.addCallSiteInfo(Ret.getNode(), std::move(CSInfo)); + return Ret; } // Returns a chain and a flag for retval copy to use. Chain = DAG.getNode(AArch64ISD::CALL, DL, NodeTys, Ops); InFlag = Chain.getValue(1); + DAG.addCallSiteInfo(Chain.getNode(), std::move(CSInfo)); uint64_t CalleePopBytes = DoesCalleeRestoreStack(CallConv, TailCallOpt) ? alignTo(NumBytes, 16) : 0; diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp --- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -1205,8 +1205,11 @@ for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i) NewMI->addOperand(MBBI->getOperand(i)); - // Delete the pseudo instruction TCRETURN. + + // Update call site info and delete the pseudo instruction TCRETURN. + MBB.getParent()->updateCallSiteInfo(&MI, &*NewMI); MBB.erase(MBBI); + MBBI = NewMI; return true; } @@ -1436,6 +1439,7 @@ MIB.cloneMemRefs(MI); TransferImpOps(MI, MIB, MIB); + MI.getMF()->updateCallSiteInfo(&MI, &*MIB); MI.eraseFromParent(); return true; } diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2040,6 +2040,7 @@ bool isVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); + MachineFunction::CallSiteInfo CSInfo; bool isStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet(); bool isThisReturn = false; auto Attr = MF.getFunction().getFnAttribute("disable-tail-calls"); @@ -2164,6 +2165,9 @@ "unexpected use of 'returned'"); isThisReturn = true; } + const TargetOptions &Options = DAG.getTarget().Options; + if (Options.EnableDebugEntryValues) + CSInfo.emplace_back(VA.getLocReg(), i); RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); } else if (isByVal) { assert(VA.isMemLoc()); @@ -2399,12 +2403,15 @@ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); if (isTailCall) { MF.getFrameInfo().setHasTailCall(); - return DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, Ops); + SDValue Ret = DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, Ops); + DAG.addCallSiteInfo(Ret.getNode(), std::move(CSInfo)); + return Ret; } // Returns a chain and a flag for retval copy to use. Chain = DAG.getNode(CallOpc, dl, NodeTys, Ops); InFlag = Chain.getValue(1); + DAG.addCallSiteInfo(Chain.getNode(), std::move(CSInfo)); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, dl, true), DAG.getIntPtrConstant(0, dl, true), InFlag, dl); diff --git a/llvm/test/DebugInfo/AArch64/call-site-info-output.ll b/llvm/test/DebugInfo/AArch64/call-site-info-output.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/AArch64/call-site-info-output.ll @@ -0,0 +1,41 @@ +; RUN: llc -mtriple aarch64-linux-gnu -debug-entry-values %s -o - -stop-before=finalize-isel | FileCheck %s +; Verify that Selection DAG knows how to recognize simple function parameter forwarding registers. +; Produced from: +; extern int fn1(int,int,int); +; int fn2(int a, int b, int c) { +; int local = fn1(a+b, c, 10); +; if (local > 10) +; return local + 10; +; return local; +; } +; clang -g -O2 -target aarch64-linux-gnu -S -emit-llvm %s +; CHECK: callSites: +; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: +; CHECK-NEXT: - { arg: 0, reg: '$w0' } +; CHECK-NEXT: - { arg: 1, reg: '$w1' } +; CHECK-NEXT: - { arg: 2, reg: '$w2' } } + +; ModuleID = 'call-site-info-output.c' +source_filename = "call-site-info-output.c" +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local i32 @fn2(i32 %a, i32 %b, i32 %c) local_unnamed_addr{ +entry: + %add = add nsw i32 %b, %a + %call = tail call i32 @fn1(i32 %add, i32 %c, i32 10) + %cmp = icmp sgt i32 %call, 10 + %add1 = add nsw i32 %call, 10 + %retval.0 = select i1 %cmp, i32 %add1, i32 %call + ret i32 %retval.0 +} + +declare dso_local i32 @fn1(i32, i32, i32) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.ident = !{!0} + +!0 = !{!"clang version 10.0.0"} diff --git a/llvm/test/DebugInfo/ARM/call-site-info-output.ll b/llvm/test/DebugInfo/ARM/call-site-info-output.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/ARM/call-site-info-output.ll @@ -0,0 +1,41 @@ +; RUN: llc -mtriple arm-linux-gnu -debug-entry-values %s -o - -stop-before=finalize-isel | FileCheck %s +; Verify that Selection DAG knows how to recognize simple function parameter forwarding registers. +; Produced from: +; extern int fn1(int,int,int); +; int fn2(int a, int b, int c) { +; int local = fn1(a+b, c, 10); +; if (local > 10) +; return local + 10; +; return local; +; } +; clang -g -O2 -target arm-linux-gnu -S -emit-llvm %s +; CHECK: callSites: +; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: +; CHECK-NEXT: - { arg: 0, reg: '$r0' } +; CHECK-NEXT: - { arg: 1, reg: '$r1' } +; CHECK-NEXT: - { arg: 2, reg: '$r2' } } + +; ModuleID = 'call-site-info-output.c' +source_filename = "call-site-info-output.c" +target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" +target triple = "armv4t-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local arm_aapcscc i32 @fn2(i32 %a, i32 %b, i32 %c) { +entry: + %add = add nsw i32 %b, %a + %call = tail call arm_aapcscc i32 @fn1(i32 %add, i32 %c, i32 10) + %cmp = icmp sgt i32 %call, 10 + %add1 = select i1 %cmp, i32 %c, i32 0 + %retval.0 = add nsw i32 %add1, %call + ret i32 %retval.0 +} + +declare dso_local arm_aapcscc i32 @fn1(i32, i32, i32) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.ident = !{!0} + +!0 = !{!"clang version 10.0.0"}