diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -783,7 +783,8 @@ const llvm::Triple::ArchType DebugEntryValueArchs[] = { llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::aarch64, - llvm::Triple::arm, llvm::Triple::armeb}; + llvm::Triple::arm, llvm::Triple::armeb, llvm::Triple::mips, + llvm::Triple::mipsel, llvm::Triple::mips64, llvm::Triple::mips64el}; llvm::Triple T(TargetOpts.Triple); if (Opts.OptimizationLevel > 0 && Opts.hasReducedDebugInfo() && diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -3217,6 +3217,9 @@ // Get a count of how many bytes are to be pushed on the stack. unsigned NextStackOffset = CCInfo.getNextStackOffset(); + // Call site info for function parameters tracking. + MachineFunction::CallSiteInfo CSInfo; + // Check if it's really possible to do a tail call. Restrict it to functions // that are part of this compilation unit. bool InternalLinkage = false; @@ -3343,6 +3346,17 @@ // RegsToPass vector if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + + // If the parameter is passed through reg $D, which splits into + // two physical registers, avoid creating call site info. + if (Mips::AFGR64RegClass.contains(VA.getLocReg())) + continue; + + // Collect CSInfo about which register passes which parameter. + const TargetOptions &Options = DAG.getTarget().Options; + if (Options.SupportsDebugEntryValues) + CSInfo.emplace_back(VA.getLocReg(), i); + continue; } @@ -3447,12 +3461,16 @@ if (IsTailCall) { MF.getFrameInfo().setHasTailCall(); - return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, Ops); + SDValue Ret = DAG.getNode(MipsISD::TailCall, DL, MVT::Other, Ops); + DAG.addCallSiteInfo(Ret.getNode(), std::move(CSInfo)); + return Ret; } Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, Ops); SDValue InFlag = Chain.getValue(1); + DAG.addCallSiteInfo(Chain.getNode(), std::move(CSInfo)); + // Create the CALLSEQ_END node in the case of where it is not a call to // memcpy. if (!(MemcpyInByVal)) { diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp --- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp +++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp @@ -131,6 +131,9 @@ MaybeAlign(Options.StackAlignmentOverride)) { Subtarget = &DefaultSubtarget; initAsmInfo(); + + // Mips supports the debug entry values. + setSupportsDebugEntryValues(true); } MipsTargetMachine::~MipsTargetMachine() = default; diff --git a/llvm/test/CodeGen/Mips/call-site-info-output.ll b/llvm/test/CodeGen/Mips/call-site-info-output.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/Mips/call-site-info-output.ll @@ -0,0 +1,65 @@ +;; Test mips32: +; RUN: llc -mtriple=mips-linux-gnu -emit-call-site-info %s -stop-before=finalize-isel -o -| \ +; RUN: llc -mtriple=mips-linux-gnu -emit-call-site-info -x='mir' -run-pass=finalize-isel -o -| FileCheck %s +;; Test mips64: +; RUN: llc -mtriple=mips64-linux-gnu -emit-call-site-info %s -stop-before=finalize-isel -o -| \ +; RUN: llc -mtriple=mips64-linux-gnu -emit-call-site-info -x='mir' -run-pass=finalize-isel -o -| FileCheck %s --check-prefix=CHECK64 +;; Test mipsel: +; RUN: llc -mtriple=mipsel-linux-gnu -emit-call-site-info %s -stop-before=finalize-isel -o -| \ +; RUN: llc -mtriple=mipsel-linux-gnu -emit-call-site-info -x='mir' -run-pass=finalize-isel -o -| FileCheck %s +;; Test mips64el: +; RUN: llc -mtriple=mips64el-linux-gnu -emit-call-site-info %s -stop-before=finalize-isel -o -| \ +; RUN: llc -mtriple=mips64el-linux-gnu -emit-call-site-info -x='mir' -run-pass=finalize-isel -o -| FileCheck %s --check-prefix=CHECK64 + +;; Test call site info MIR parser and printer. Parser assertions and machine +;; verifier will check the rest. +;; There is no need to verify call instruction location since it will be +;; checked by the MIR parser. +;; Verify that we are able to parse output mir and that we are getting valid call site info. + +;; Source: +;; 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; +;; } + +;; Test mips32 and mips32el: +; CHECK: name: fn2 +; CHECK: callSites: +; CHECK-NEXT: bb: {{.*}}, offset: {{.*}}, fwdArgRegs: +; CHECK-NEXT: arg: 0, reg: '$a0' +; CHECK-NEXT: arg: 1, reg: '$a1' +; CHECK-NEXT: arg: 2, reg: '$a2' + +;; Test mips64 and mips64el: +; CHECK64: name: fn2 +; CHECK64: callSites: +; CHECK64-NEXT: bb: {{.*}}, offset: {{.*}}, fwdArgRegs: +; CHECK64-NEXT: arg: 0, reg: '$a0_64' +; CHECK64-NEXT: arg: 1, reg: '$a1_64' +; CHECK64-NEXT: arg: 2, reg: '$a2_64' + +; ModuleID = 'test/CodeGen/Mips/call-site-info-output.c' +source_filename = "test/CodeGen/Mips/call-site-info-output.c" +target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" +target triple = "mips-unknown-linux-gnu" +; Function Attrs: nounwind +define dso_local i32 @fn2(i32 signext %a, i32 signext %b, i32 signext %c) local_unnamed_addr { +entry: + %add = add nsw i32 %b, %a + %call = tail call i32 @fn1(i32 signext %add, i32 signext %c, i32 signext 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 signext, i32 signext, i32 signext) local_unnamed_addr + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 11.0.0"} diff --git a/llvm/test/CodeGen/Mips/dbg-call-site-info-reg-d-split.ll b/llvm/test/CodeGen/Mips/dbg-call-site-info-reg-d-split.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/Mips/dbg-call-site-info-reg-d-split.ll @@ -0,0 +1,68 @@ +;; Test mips: +; RUN: llc -mtriple=mips-linux-gnu -emit-call-site-info %s -stop-after=finalize-isel -o -| FileCheck %s +;; Test mipsel: +; RUN: llc -mtriple=mipsel-linux-gnu -emit-call-site-info %s -stop-after=finalize-isel -o -| FileCheck %s + +;; Verify that call site info is not emitted for parameter passed through 64-bit register $d +;; which splits into two 32-bit physical regs. +;; Source: +;; extern double bar(double,int); +;; double foo(double self){ +;; int b = 1; +;; double a = bar(self,b); +;; return a; +;; } + +;; Test mips and mipsel: +; CHECK: name: foo +; CHECK: callSites: +; CHECK-NEXT: bb: {{.*}}, offset: {{.*}}, fwdArgRegs: +; CHECK-NOT: arg: 0, reg: '$a0' +; CHECK-NOT: arg: 0, reg: '$d6' +; CHECK-NEXT: arg: 1, reg: '$a2' + +; ModuleID = 'm.c' +source_filename = "m.c" +target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" +target triple = "mips-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local double @foo(double %self) local_unnamed_addr !dbg !13 { +entry: + call void @llvm.dbg.value(metadata double %self, metadata !17, metadata !DIExpression()), !dbg !20 + call void @llvm.dbg.value(metadata i32 1, metadata !18, metadata !DIExpression()), !dbg !20 + %call = tail call double @bar(double %self, i32 signext 1), !dbg !20 + call void @llvm.dbg.value(metadata double %call, metadata !19, metadata !DIExpression()), !dbg !20 + ret double %call, !dbg !20 +} + +declare !dbg !4 dso_local double @bar(double, i32 signext) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "m.c", directory: "/dir") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7, !8} +!7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 11.0.0"} +!13 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !14, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!14 = !DISubroutineType(types: !15) +!15 = !{!7, !7} +!16 = !{!17, !18, !19} +!17 = !DILocalVariable(name: "self", arg: 1, scope: !13, file: !1, line: 3, type: !7) +!18 = !DILocalVariable(name: "b", scope: !13, file: !1, line: 4, type: !8) +!19 = !DILocalVariable(name: "a", scope: !13, file: !1, line: 5, type: !7) +!20 = !DILocation(line: 0, scope: !13) diff --git a/llvm/test/DebugInfo/Mips/dw_op_entry_value_32bit.ll b/llvm/test/DebugInfo/Mips/dw_op_entry_value_32bit.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Mips/dw_op_entry_value_32bit.ll @@ -0,0 +1,76 @@ +;; Test mips32: +; RUN: llc -emit-call-site-info -stop-after=livedebugvalues -mtriple=mips-linux-gnu -o - %s | FileCheck %s +;; Test mipsel: +; RUN: llc -emit-call-site-info -stop-after=livedebugvalues -mtriple=mipsel-linux-gnu -o - %s | FileCheck %s --check-prefix=CHECKel + +;; Built from source: +;; extern long fn1(long,long,long); +;; long fn2(long a, long b, long c) { +;; long local = fn1(a+b, c, b+10); +;; if (local > 10) +;; return local + 10; +;; return b; +;; } +;; Using command: +;; clang -g -O2 -target mips-linux-gnu m.c -c -S -emit-llvm +;; Confirm that info from callSites attribute is used as entry_value in DIExpression. + +;; Test mips32: +; CHECK: $a0 = nsw ADDu $a1, killed renamable $a0, +; CHECK-NEXT: DBG_VALUE $a0, $noreg, !14, !DIExpression(DW_OP_LLVM_entry_value, 1) + +;; Test mipsel: +; CHECKel: $a0 = nsw ADDu $a1, killed renamable $a0, +; CHECKel-NEXT: DBG_VALUE $a0, $noreg, !14, !DIExpression(DW_OP_LLVM_entry_value, 1) + +; ModuleID = 'm.c' +source_filename = "m.c" +target datalayout = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" +target triple = "mips-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local i32 @fn2(i32 signext %a, i32 signext %b, i32 signext %c) local_unnamed_addr !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32 %c, metadata !16, metadata !DIExpression()), !dbg !18 + %add = add nsw i32 %b, %a, !dbg !18 + %add1 = add nsw i32 %b, 10, !dbg !18 + %call = tail call i32 @fn1(i32 signext %add, i32 signext %c, i32 signext %add1), !dbg !18 + call void @llvm.dbg.value(metadata i32 %call, metadata !17, metadata !DIExpression()), !dbg !18 + %cmp = icmp sgt i32 %call, 10, !dbg !22 + %add2 = add nsw i32 %call, 10, !dbg !18 + %retval.0 = select i1 %cmp, i32 %add2, i32 %b, !dbg !18 + ret i32 %retval.0, !dbg !18 +} + +declare !dbg !4 dso_local i32 @fn1(i32 signext, i32 signext, i32 signext) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "m.c", directory: "/dir") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7, !7, !7} +!7 = !DIBasicType(name: "long int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 2, type: !5, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13) +!13 = !{!14, !15, !16, !17} +!14 = !DILocalVariable(name: "a", arg: 1, scope: !12, file: !1, line: 2, type: !7) +!15 = !DILocalVariable(name: "b", arg: 2, scope: !12, file: !1, line: 2, type: !7) +!16 = !DILocalVariable(name: "c", arg: 3, scope: !12, file: !1, line: 2, type: !7) +!17 = !DILocalVariable(name: "local", scope: !12, file: !1, line: 3, type: !7) +!18 = !DILocation(line: 0, scope: !12) +!22 = !DILocation(line: 4, column: 13, scope: !23) +!23 = distinct !DILexicalBlock(scope: !12, file: !1, line: 4, column: 7) diff --git a/llvm/test/DebugInfo/Mips/dw_op_entry_value_64bit.ll b/llvm/test/DebugInfo/Mips/dw_op_entry_value_64bit.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Mips/dw_op_entry_value_64bit.ll @@ -0,0 +1,77 @@ +;; Test mips64: +; RUN: llc -emit-call-site-info -stop-after=livedebugvalues -mtriple=mips64-linux-gnu -o - %s | FileCheck %s --check-prefix=CHECK64 +;; Test mips64el: +; RUN: llc -emit-call-site-info -stop-after=livedebugvalues -mtriple=mips64el-linux-gnu -o - %s | FileCheck %s --check-prefix=CHECK64el + +;; Built from source: +;; extern long fn1(long,long,long); +;; long fn2(long a, long b, long c) { +;; long local = fn1(a+b, c, b+10); +;; if (local > 10) +;; return local + 10; +;; return b; +;; } +;; Using command: +;; clang -g -O2 -target mips64-linux-gnu m.c -c -S -emit-llvm +;; Confirm that info from callSites attribute is used as entry_value in DIExpression. + +;; Test mips64: +; CHECK64: $a0_64 = nsw DADDu $a1_64, killed renamable $a0_64, +; CHECK64-NEXT: DBG_VALUE $a0_64, $noreg, !15, !DIExpression(DW_OP_LLVM_entry_value, 1) + +;; Test mips64el: +; CHECK64el: $a0_64 = nsw DADDu $a1_64, killed renamable $a0_64, +; CHECK64el-NEXT: DBG_VALUE $a0_64, $noreg, !15, !DIExpression(DW_OP_LLVM_entry_value, 1) + +; ModuleID = 'm.c' +source_filename = "m.c" +target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128" +target triple = "mips64-unknown-linux-gnu" + +; Function Attrs: nounwind +define i64 @fn2(i64 signext %a, i64 signext %b, i64 signext %c) local_unnamed_addr !dbg !13 { +entry: + call void @llvm.dbg.value(metadata i64 %a, metadata !15, metadata !DIExpression()), !dbg !19 + call void @llvm.dbg.value(metadata i64 %b, metadata !16, metadata !DIExpression()), !dbg !19 + call void @llvm.dbg.value(metadata i64 %c, metadata !17, metadata !DIExpression()), !dbg !19 + %add = add nsw i64 %b, %a, !dbg !19 + %add1 = add nsw i64 %b, 10, !dbg !19 + %call = tail call i64 @fn1(i64 signext %add, i64 signext %c, i64 signext %add1), !dbg !19 + call void @llvm.dbg.value(metadata i64 %call, metadata !18, metadata !DIExpression()), !dbg !19 + %cmp = icmp sgt i64 %call, 10, !dbg !23 + %add2 = add nsw i64 %call, 10, !dbg !19 + %retval.0 = select i1 %cmp, i64 %add2, i64 %b, !dbg !19 + ret i64 %retval.0, !dbg !19 +} + +declare !dbg !4 i64 @fn1(i64 signext, i64 signext, i64 signext) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "m.c", directory: "/dir") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !7, !7, !7} +!7 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{i32 7, !"PIC Level", i32 1} +!12 = !{!"clang version 11.0.0"} +!13 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 2, type: !5, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14) +!14 = !{!15, !16, !17, !18} +!15 = !DILocalVariable(name: "a", arg: 1, scope: !13, file: !1, line: 2, type: !7) +!16 = !DILocalVariable(name: "b", arg: 2, scope: !13, file: !1, line: 2, type: !7) +!17 = !DILocalVariable(name: "c", arg: 3, scope: !13, file: !1, line: 2, type: !7) +!18 = !DILocalVariable(name: "local", scope: !13, file: !1, line: 3, type: !7) +!19 = !DILocation(line: 0, scope: !13) +!23 = !DILocation(line: 4, column: 13, scope: !24) +!24 = distinct !DILexicalBlock(scope: !13, file: !1, line: 4, column: 7)