diff options
-rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h | 26 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 59 | ||||
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 61 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll | 33 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll | 51 |
5 files changed, 192 insertions, 38 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index ecd3e5e1e13..94d179f10d6 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -108,6 +108,9 @@ public: /// Set the debug location to \p DL for all the next build instructions. void setDebugLoc(const DebugLoc &DL) { this->DL = DL; } + /// Get the current instruction's debug location. + DebugLoc getDebugLoc() { return DL; } + /// Build and insert <empty> = \p Opcode <empty>. /// The insertion point is the one set by the last call of either /// setBasicBlock or setMI. @@ -127,6 +130,29 @@ public: /// Insert an existing instruction at the insertion point. MachineInstrBuilder insertInstr(MachineInstrBuilder MIB); + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in \p Reg (suitably modified by \p Expr). + MachineInstrBuilder buildDirectDbgValue(unsigned Reg, const MDNode *Variable, + const MDNode *Expr); + + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in memory at \p Reg + \p Offset (suitably + /// modified by \p Expr). + MachineInstrBuilder buildIndirectDbgValue(unsigned Reg, unsigned Offset, + const MDNode *Variable, + const MDNode *Expr); + /// Build and insert a DBG_VALUE instruction expressing the fact that the + /// associated \p Variable lives in the stack slot specified by \p FI + /// (suitably modified by \p Expr). + MachineInstrBuilder buildFIDbgValue(int FI, const MDNode *Variable, + const MDNode *Expr); + + /// Build and insert a DBG_VALUE instructions specifying that \p Variable is + /// given by \p C (suitably modified by \p Expr). + MachineInstrBuilder buildConstDbgValue(const Constant &C, unsigned Offset, + const MDNode *Variable, + const MDNode *Expr); + /// Build and insert \p Res<def> = G_FRAME_INDEX \p Idx /// /// G_FRAME_INDEX materializes the address of an alloca value or other diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index db59d17cae1..4a642f44cb3 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -22,6 +22,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" @@ -522,12 +523,60 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, switch (ID) { default: break; - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: - // FIXME: these obviously need to be supported properly. - if (!TPC->isGlobalISelAbortEnabled()) - MF->getProperties().set(MachineFunctionProperties::Property::FailedISel); + case Intrinsic::dbg_declare: { + const DbgDeclareInst &DI = cast<DbgDeclareInst>(CI); + assert(DI.getVariable() && "Missing variable"); + + const Value *Address = DI.getAddress(); + if (!Address || isa<UndefValue>(Address)) { + DEBUG(dbgs() << "Dropping debug info for " << DI << "\n"); + return true; + } + + unsigned Reg = getOrCreateVReg(*Address); + auto RegDef = MRI->def_instr_begin(Reg); + assert(DI.getVariable()->isValidLocationForIntrinsic( + MIRBuilder.getDebugLoc()) && + "Expected inlined-at fields to agree"); + + if (RegDef != MRI->def_instr_end() && + RegDef->getOpcode() == TargetOpcode::G_FRAME_INDEX) { + MIRBuilder.buildFIDbgValue(RegDef->getOperand(1).getIndex(), + DI.getVariable(), DI.getExpression()); + } else + MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), DI.getExpression()); + return true; + } + case Intrinsic::dbg_value: { + // This form of DBG_VALUE is target-independent. + const DbgValueInst &DI = cast<DbgValueInst>(CI); + const Value *V = DI.getValue(); + assert(DI.getVariable()->isValidLocationForIntrinsic( + MIRBuilder.getDebugLoc()) && + "Expected inlined-at fields to agree"); + if (!V) { + // Currently the optimizer can produce this; insert an undef to + // help debugging. Probably the optimizer should not do this. + MIRBuilder.buildIndirectDbgValue(0, DI.getOffset(), DI.getVariable(), + DI.getExpression()); + } else if (const auto *CI = dyn_cast<Constant>(V)) { + MIRBuilder.buildConstDbgValue(*CI, DI.getOffset(), DI.getVariable(), + DI.getExpression()); + } else { + unsigned Reg = getOrCreateVReg(*V); + // FIXME: This does not handle register-indirect values at offset 0. The + // direct/indirect thing shouldn't really be handled by something as + // implicit as reg+noreg vs reg+imm in the first palce, but it seems + // pretty baked in right now. + if (DI.getOffset() != 0) + MIRBuilder.buildIndirectDbgValue(Reg, DI.getOffset(), DI.getVariable(), + DI.getExpression()); + else + MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), + DI.getExpression()); + } return true; + } case Intrinsic::uadd_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDE, MIRBuilder); case Intrinsic::sadd_with_overflow: diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 70a992d3693..ae1550d0d3d 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -15,6 +15,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetOpcodes.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -82,6 +83,66 @@ MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) { return MIB; } +MachineInstrBuilder MachineIRBuilder::buildDirectDbgValue( + unsigned Reg, const MDNode *Variable, const MDNode *Expr) { + assert(isa<DILocalVariable>(Variable) && "not a variable"); + assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); + assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return buildInstr(TargetOpcode::DBG_VALUE) + .addReg(Reg, RegState::Debug) + .addReg(0, RegState::Debug) + .addMetadata(Variable) + .addMetadata(Expr); +} + +MachineInstrBuilder MachineIRBuilder::buildIndirectDbgValue( + unsigned Reg, unsigned Offset, const MDNode *Variable, const MDNode *Expr) { + assert(isa<DILocalVariable>(Variable) && "not a variable"); + assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); + assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return buildInstr(TargetOpcode::DBG_VALUE) + .addReg(Reg, RegState::Debug) + .addImm(Offset) + .addMetadata(Variable) + .addMetadata(Expr); +} + +MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI, + const MDNode *Variable, + const MDNode *Expr) { + assert(isa<DILocalVariable>(Variable) && "not a variable"); + assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); + assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + return buildInstr(TargetOpcode::DBG_VALUE) + .addFrameIndex(FI) + .addImm(0) + .addMetadata(Variable) + .addMetadata(Expr); +} + +MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C, + unsigned Offset, + const MDNode *Variable, + const MDNode *Expr) { + assert(isa<DILocalVariable>(Variable) && "not a variable"); + assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); + assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && + "Expected inlined-at fields to agree"); + auto MIB = buildInstr(TargetOpcode::DBG_VALUE); + if (auto *CI = dyn_cast<ConstantInt>(&C)) { + if (CI->getBitWidth() > 64) + MIB.addCImm(CI); + else + MIB.addImm(CI->getZExtValue()); + } else + MIB.addFPImm(&cast<ConstantFP>(C)); + + return MIB.addImm(Offset).addMetadata(Variable).addMetadata(Expr); +} + MachineInstrBuilder MachineIRBuilder::buildFrameIndex(unsigned Res, int Idx) { assert(MRI->getType(Res).isPointer() && "invalid operand type"); return buildInstr(TargetOpcode::G_FRAME_INDEX) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll index 8d1dbc246e6..e4a2bb2dbf5 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll @@ -82,36 +82,3 @@ define void @legal_default(i64 %in) { insertvalue [2 x i64] undef, i64 %in, 0 ret void } - -; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for debug_insts -; FALLBACK-WITH-REPORT-LABEL: debug_insts: -define void @debug_insts(i32 %in) #0 !dbg !7 { -entry: - %in.addr = alloca i32, align 4 - store i32 %in, i32* %in.addr, align 4 - call void @llvm.dbg.declare(metadata i32* %in.addr, metadata !11, metadata !12), !dbg !13 - ret void, !dbg !14 -} - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.declare(metadata, metadata, metadata) - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4, !5} -!llvm.ident = !{!6} - -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 289075) (llvm/trunk 289080)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) -!1 = !DIFile(filename: "tmp.c", directory: "/Users/tim/llvm/build") -!2 = !{} -!3 = !{i32 2, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} -!5 = !{i32 1, !"PIC Level", i32 2} -!6 = !{!"clang version 4.0.0 (trunk 289075) (llvm/trunk 289080)"} -!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) -!8 = !DISubroutineType(types: !9) -!9 = !{null, !10} -!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) -!11 = !DILocalVariable(name: "in", arg: 1, scope: !7, file: !1, line: 1, type: !10) -!12 = !DIExpression() -!13 = !DILocation(line: 1, column: 14, scope: !7) -!14 = !DILocation(line: 2, column: 1, scope: !7) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll b/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll new file mode 100644 index 00000000000..fcf17e2d4e0 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/debug-insts.ll @@ -0,0 +1,51 @@ +; RUN: llc -global-isel -mtriple=aarch64 %s -stop-after=irtranslator -o - | FileCheck %s + + +; CHECK-LABEL: name: debug_declare +; CHECK: DBG_VALUE %stack.0.in.addr, 0, !11, !12, debug-location !13 +; CHECK: DBG_VALUE debug-use %0(s32), debug-use _, !11, !12, debug-location !13 +define void @debug_declare(i32 %in) #0 !dbg !7 { +entry: + %in.addr = alloca i32, align 4 + store i32 %in, i32* %in.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %in.addr, metadata !11, metadata !12), !dbg !13 + call void @llvm.dbg.declare(metadata i32 %in, metadata !11, metadata !12), !dbg !13 + ret void, !dbg !14 +} + +; CHECK-LABEL: name: debug_value +; CHECK: [[IN:%[0-9]+]](s32) = COPY %w0 +; CHECK: DBG_VALUE debug-use [[IN]](s32), debug-use _, !11, !12, debug-location !13 +; CHECK: DBG_VALUE debug-use %1(p0), debug-use _, !11, !15, debug-location !13 +define void @debug_value(i32 %in) #0 !dbg !7 { + %addr = alloca i32 + call void @llvm.dbg.value(metadata i32 %in, i64 0, metadata !11, metadata !12), !dbg !13 + store i32 %in, i32* %addr + call void @llvm.dbg.value(metadata i32* %addr, i64 0, metadata !11, metadata !15), !dbg !13 + ret void +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 289075) (llvm/trunk 289080)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "tmp.c", directory: "/Users/tim/llvm/build") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"PIC Level", i32 2} +!6 = !{!"clang version 4.0.0 (trunk 289075) (llvm/trunk 289080)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "in", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!12 = !DIExpression() +!13 = !DILocation(line: 1, column: 14, scope: !7) +!14 = !DILocation(line: 2, column: 1, scope: !7) +!15 = !DIExpression(DW_OP_deref) |