forked from OSchip/llvm-project
[debug-info] Add support for llvm.dbg.addr in DIBuilder.
I based this off of the API already create for llvm.dbg.value since both intrinsics have the same arguments at the API level. I added some tests exercising the API a little as well as an additional small test that shows how one can use llvm.dbg.addr to limit the PC range where an address value is available in the debugger. This is done by calling llvm.dbg.value with undef and the same metadata info as one used to create the llvm.dbg.addr. rdar://83957028 Reviewed By: aprantl Differential Revision: https://reviews.llvm.org/D117442
This commit is contained in:
parent
ff0b634d97
commit
7ed95d1577
|
@ -23,6 +23,7 @@
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/IR/DebugInfo.h"
|
#include "llvm/IR/DebugInfo.h"
|
||||||
#include "llvm/IR/DebugInfoMetadata.h"
|
#include "llvm/IR/DebugInfoMetadata.h"
|
||||||
|
#include "llvm/IR/Intrinsics.h"
|
||||||
#include "llvm/IR/TrackingMDRef.h"
|
#include "llvm/IR/TrackingMDRef.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -46,6 +47,7 @@ namespace llvm {
|
||||||
Function *DeclareFn; ///< llvm.dbg.declare
|
Function *DeclareFn; ///< llvm.dbg.declare
|
||||||
Function *ValueFn; ///< llvm.dbg.value
|
Function *ValueFn; ///< llvm.dbg.value
|
||||||
Function *LabelFn; ///< llvm.dbg.label
|
Function *LabelFn; ///< llvm.dbg.label
|
||||||
|
Function *AddrFn; ///< llvm.dbg.addr
|
||||||
|
|
||||||
SmallVector<Metadata *, 4> AllEnumTypes;
|
SmallVector<Metadata *, 4> AllEnumTypes;
|
||||||
/// Track the RetainTypes, since they can be updated later on.
|
/// Track the RetainTypes, since they can be updated later on.
|
||||||
|
@ -86,11 +88,34 @@ namespace llvm {
|
||||||
Instruction *insertLabel(DILabel *LabelInfo, const DILocation *DL,
|
Instruction *insertLabel(DILabel *LabelInfo, const DILocation *DL,
|
||||||
BasicBlock *InsertBB, Instruction *InsertBefore);
|
BasicBlock *InsertBB, Instruction *InsertBefore);
|
||||||
|
|
||||||
|
/// Internal helper with common code used by insertDbg{Value,Addr}Intrinsic.
|
||||||
|
Instruction *insertDbgIntrinsic(llvm::Function *Intrinsic, llvm::Value *Val,
|
||||||
|
DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr, const DILocation *DL,
|
||||||
|
BasicBlock *InsertBB,
|
||||||
|
Instruction *InsertBefore);
|
||||||
|
|
||||||
/// Internal helper for insertDbgValueIntrinsic.
|
/// Internal helper for insertDbgValueIntrinsic.
|
||||||
Instruction *
|
Instruction *
|
||||||
insertDbgValueIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo,
|
insertDbgValueIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo,
|
||||||
DIExpression *Expr, const DILocation *DL,
|
DIExpression *Expr, const DILocation *DL,
|
||||||
BasicBlock *InsertBB, Instruction *InsertBefore);
|
BasicBlock *InsertBB, Instruction *InsertBefore) {
|
||||||
|
if (!ValueFn)
|
||||||
|
ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
|
||||||
|
return insertDbgIntrinsic(ValueFn, Val, VarInfo, Expr, DL, InsertBB,
|
||||||
|
InsertBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal helper for insertDbgAddrIntrinsic.
|
||||||
|
Instruction *
|
||||||
|
insertDbgAddrIntrinsic(llvm::Value *Val, DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr, const DILocation *DL,
|
||||||
|
BasicBlock *InsertBB, Instruction *InsertBefore) {
|
||||||
|
if (!AddrFn)
|
||||||
|
AddrFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_addr);
|
||||||
|
return insertDbgIntrinsic(AddrFn, Val, VarInfo, Expr, DL, InsertBB,
|
||||||
|
InsertBefore);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct a builder for a module.
|
/// Construct a builder for a module.
|
||||||
|
@ -929,6 +954,30 @@ namespace llvm {
|
||||||
const DILocation *DL,
|
const DILocation *DL,
|
||||||
Instruction *InsertBefore);
|
Instruction *InsertBefore);
|
||||||
|
|
||||||
|
/// Insert a new llvm.dbg.addr intrinsic call.
|
||||||
|
/// \param Addr llvm::Value of the address
|
||||||
|
/// \param VarInfo Variable's debug info descriptor.
|
||||||
|
/// \param Expr A complex location expression.
|
||||||
|
/// \param DL Debug info location.
|
||||||
|
/// \param InsertAtEnd Location for the new intrinsic.
|
||||||
|
Instruction *insertDbgAddrIntrinsic(llvm::Value *Addr,
|
||||||
|
DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr,
|
||||||
|
const DILocation *DL,
|
||||||
|
BasicBlock *InsertAtEnd);
|
||||||
|
|
||||||
|
/// Insert a new llvm.dbg.addr intrinsic call.
|
||||||
|
/// \param Addr llvm::Value of the address.
|
||||||
|
/// \param VarInfo Variable's debug info descriptor.
|
||||||
|
/// \param Expr A complex location expression.
|
||||||
|
/// \param DL Debug info location.
|
||||||
|
/// \param InsertBefore Location for the new intrinsic.
|
||||||
|
Instruction *insertDbgAddrIntrinsic(llvm::Value *Addr,
|
||||||
|
DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr,
|
||||||
|
const DILocation *DL,
|
||||||
|
Instruction *InsertBefore);
|
||||||
|
|
||||||
/// Replace the vtable holder in the given type.
|
/// Replace the vtable holder in the given type.
|
||||||
///
|
///
|
||||||
/// If this creates a self reference, it may orphan some unresolved cycles
|
/// If this creates a self reference, it may orphan some unresolved cycles
|
||||||
|
|
|
@ -33,7 +33,7 @@ static cl::opt<bool>
|
||||||
|
|
||||||
DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU)
|
DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU)
|
||||||
: M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr),
|
: M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr),
|
||||||
ValueFn(nullptr), LabelFn(nullptr),
|
ValueFn(nullptr), LabelFn(nullptr), AddrFn(nullptr),
|
||||||
AllowUnresolvedNodes(AllowUnresolvedNodes) {
|
AllowUnresolvedNodes(AllowUnresolvedNodes) {
|
||||||
if (CUNode) {
|
if (CUNode) {
|
||||||
if (const auto &ETs = CUNode->getEnumTypes())
|
if (const auto &ETs = CUNode->getEnumTypes())
|
||||||
|
@ -974,6 +974,24 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(Value *V,
|
||||||
return insertDbgValueIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr);
|
return insertDbgValueIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction *DIBuilder::insertDbgAddrIntrinsic(Value *V,
|
||||||
|
DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr,
|
||||||
|
const DILocation *DL,
|
||||||
|
Instruction *InsertBefore) {
|
||||||
|
return insertDbgAddrIntrinsic(
|
||||||
|
V, VarInfo, Expr, DL, InsertBefore ? InsertBefore->getParent() : nullptr,
|
||||||
|
InsertBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction *DIBuilder::insertDbgAddrIntrinsic(Value *V,
|
||||||
|
DILocalVariable *VarInfo,
|
||||||
|
DIExpression *Expr,
|
||||||
|
const DILocation *DL,
|
||||||
|
BasicBlock *InsertAtEnd) {
|
||||||
|
return insertDbgAddrIntrinsic(V, VarInfo, Expr, DL, InsertAtEnd, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize IRBuilder for inserting dbg.declare and dbg.value intrinsics.
|
/// Initialize IRBuilder for inserting dbg.declare and dbg.value intrinsics.
|
||||||
/// This abstracts over the various ways to specify an insert position.
|
/// This abstracts over the various ways to specify an insert position.
|
||||||
static void initIRBuilder(IRBuilder<> &Builder, const DILocation *DL,
|
static void initIRBuilder(IRBuilder<> &Builder, const DILocation *DL,
|
||||||
|
@ -1018,17 +1036,20 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
|
||||||
return B.CreateCall(DeclareFn, Args);
|
return B.CreateCall(DeclareFn, Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction *DIBuilder::insertDbgValueIntrinsic(
|
Instruction *DIBuilder::insertDbgIntrinsic(llvm::Function *IntrinsicFn,
|
||||||
Value *V, DILocalVariable *VarInfo, DIExpression *Expr,
|
Value *V, DILocalVariable *VarInfo,
|
||||||
const DILocation *DL, BasicBlock *InsertBB, Instruction *InsertBefore) {
|
DIExpression *Expr,
|
||||||
assert(V && "no value passed to dbg.value");
|
const DILocation *DL,
|
||||||
assert(VarInfo && "empty or invalid DILocalVariable* passed to dbg.value");
|
BasicBlock *InsertBB,
|
||||||
|
Instruction *InsertBefore) {
|
||||||
|
assert(IntrinsicFn && "must pass a non-null intrinsic function");
|
||||||
|
assert(V && "must pass a value to a dbg intrinsic");
|
||||||
|
assert(VarInfo &&
|
||||||
|
"empty or invalid DILocalVariable* passed to debug intrinsic");
|
||||||
assert(DL && "Expected debug loc");
|
assert(DL && "Expected debug loc");
|
||||||
assert(DL->getScope()->getSubprogram() ==
|
assert(DL->getScope()->getSubprogram() ==
|
||||||
VarInfo->getScope()->getSubprogram() &&
|
VarInfo->getScope()->getSubprogram() &&
|
||||||
"Expected matching subprograms");
|
"Expected matching subprograms");
|
||||||
if (!ValueFn)
|
|
||||||
ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
|
|
||||||
|
|
||||||
trackIfUnresolved(VarInfo);
|
trackIfUnresolved(VarInfo);
|
||||||
trackIfUnresolved(Expr);
|
trackIfUnresolved(Expr);
|
||||||
|
@ -1038,7 +1059,7 @@ Instruction *DIBuilder::insertDbgValueIntrinsic(
|
||||||
|
|
||||||
IRBuilder<> B(DL->getContext());
|
IRBuilder<> B(DL->getContext());
|
||||||
initIRBuilder(B, DL, InsertBB, InsertBefore);
|
initIRBuilder(B, DL, InsertBB, InsertBefore);
|
||||||
return B.CreateCall(ValueFn, Args);
|
return B.CreateCall(IntrinsicFn, Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction *DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL,
|
Instruction *DIBuilder::insertLabel(DILabel *LabelInfo, const DILocation *DL,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
;; Run twice -- once with DBG_VALUEs, once with instruction referencing.
|
;; Run twice -- once with DBG_VALUEs, once with instruction referencing.
|
||||||
; RUN: llc %s -o %t.s -experimental-debug-variable-locations=false
|
; RUN: llc %s -o %t.s -experimental-debug-variable-locations=false
|
||||||
; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
|
; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
|
||||||
; RUN: FileCheck < %t.s %s
|
; RUN: FileCheck -input-file=%t.s %s
|
||||||
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
||||||
; RUN: llc %s -o %t.s -experimental-debug-variable-locations=true
|
; RUN: llc %s -o %t.s -experimental-debug-variable-locations=true
|
||||||
; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
|
; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
|
||||||
; RUN: FileCheck < %t.s %s
|
; RUN: FileCheck -input-file=%t.s %s
|
||||||
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,6 +20,19 @@
|
||||||
; DWARF-NEXT: DW_AT_location (DW_OP_fbreg +0)
|
; DWARF-NEXT: DW_AT_location (DW_OP_fbreg +0)
|
||||||
; DWARF-NEXT: DW_AT_name ("o")
|
; DWARF-NEXT: DW_AT_name ("o")
|
||||||
|
|
||||||
|
; Make sure that in the second case, we properly get a validity range in the
|
||||||
|
; dwarf for the value. This ensures that we can use this technique to invalidate
|
||||||
|
; variables.
|
||||||
|
|
||||||
|
; CHECK-LABEL: test_dbg_addr_and_dbg_val_undef
|
||||||
|
; CHECK: #DEBUG_VALUE: test_dbg_addr_and_dbg_val_undef:second_o <- [$rsp+0]
|
||||||
|
; CHECK: #DEBUG_VALUE: test_dbg_addr_and_dbg_val_undef:second_o <- undef
|
||||||
|
; CHECK-NOT: #DEBUG_VALUE:
|
||||||
|
|
||||||
|
; DWARF: DW_TAG_variable
|
||||||
|
; DWARF-NEXT: DW_AT_location (0x{{[0-9a-z][0-9a-z]*}}:
|
||||||
|
; DWARF-NEXT: [0x{{[0-9a-z][0-9a-z]*}}, 0x{{[0-9a-z][0-9a-z]*}}): DW_OP_breg7 RSP+0)
|
||||||
|
; DWARF-NEXT: DW_AT_name ("second_o")
|
||||||
|
|
||||||
; ModuleID = 't.c'
|
; ModuleID = 't.c'
|
||||||
source_filename = "t.c"
|
source_filename = "t.c"
|
||||||
|
@ -37,8 +50,18 @@ entry:
|
||||||
ret void, !dbg !18
|
ret void, !dbg !18
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @test_dbg_addr_and_dbg_val_undef() #0 !dbg !117 {
|
||||||
|
entry:
|
||||||
|
%o = alloca %struct.Foo, align 4
|
||||||
|
call void @llvm.dbg.addr(metadata %struct.Foo* %o, metadata !1110, metadata !1115), !dbg !1116
|
||||||
|
call void @escape_foo(%struct.Foo* %o), !dbg !1117
|
||||||
|
call void @llvm.dbg.value(metadata %struct.Foo* undef, metadata !1110, metadata !1115), !dbg !1116
|
||||||
|
ret void, !dbg !1118
|
||||||
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind readnone speculatable
|
; Function Attrs: nounwind readnone speculatable
|
||||||
declare void @llvm.dbg.addr(metadata, metadata, metadata) #1
|
declare void @llvm.dbg.addr(metadata, metadata, metadata) #1
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
||||||
|
|
||||||
declare void @escape_foo(%struct.Foo*)
|
declare void @escape_foo(%struct.Foo*)
|
||||||
|
|
||||||
|
@ -68,3 +91,16 @@ attributes #1 = { nounwind readnone speculatable }
|
||||||
!16 = !DILocation(line: 4, column: 14, scope: !7)
|
!16 = !DILocation(line: 4, column: 14, scope: !7)
|
||||||
!17 = !DILocation(line: 5, column: 3, scope: !7)
|
!17 = !DILocation(line: 5, column: 3, scope: !7)
|
||||||
!18 = !DILocation(line: 6, column: 1, scope: !7)
|
!18 = !DILocation(line: 6, column: 1, scope: !7)
|
||||||
|
|
||||||
|
!117 = distinct !DISubprogram(name: "test_dbg_addr_and_dbg_val_undef", scope: !1, file: !1, line: 3, type: !118, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
|
||||||
|
!118 = !DISubroutineType(types: !119)
|
||||||
|
!119 = !{null}
|
||||||
|
!1110 = !DILocalVariable(name: "second_o", scope: !117, file: !1, line: 4, type: !1111)
|
||||||
|
!1111 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 32, elements: !1112)
|
||||||
|
!1112 = !{!1113}
|
||||||
|
!1113 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !1111, file: !1, line: 1, baseType: !1114, size: 32)
|
||||||
|
!1114 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!1115 = !DIExpression()
|
||||||
|
!1116 = !DILocation(line: 4, column: 14, scope: !117)
|
||||||
|
!1117 = !DILocation(line: 5, column: 3, scope: !117)
|
||||||
|
!1118 = !DILocation(line: 6, column: 1, scope: !117)
|
||||||
|
|
|
@ -11,8 +11,10 @@
|
||||||
#include "llvm/AsmParser/Parser.h"
|
#include "llvm/AsmParser/Parser.h"
|
||||||
#include "llvm/IR/DIBuilder.h"
|
#include "llvm/IR/DIBuilder.h"
|
||||||
#include "llvm/IR/DebugInfoMetadata.h"
|
#include "llvm/IR/DebugInfoMetadata.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/IntrinsicInst.h"
|
#include "llvm/IR/IntrinsicInst.h"
|
||||||
#include "llvm/IR/LLVMContext.h"
|
#include "llvm/IR/LLVMContext.h"
|
||||||
|
#include "llvm/IR/Metadata.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/IR/Verifier.h"
|
#include "llvm/IR/Verifier.h"
|
||||||
#include "llvm/Support/SourceMgr.h"
|
#include "llvm/Support/SourceMgr.h"
|
||||||
|
@ -262,4 +264,69 @@ TEST(DIBuilder, DIEnumerator) {
|
||||||
EXPECT_FALSE(E2);
|
EXPECT_FALSE(E2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DIBuilder, createDbgAddr) {
|
||||||
|
LLVMContext C;
|
||||||
|
std::unique_ptr<Module> M = parseIR(C, R"(
|
||||||
|
define void @f() !dbg !6 {
|
||||||
|
%a = alloca i16, align 8
|
||||||
|
;; It is important that we put the debug marker on the return.
|
||||||
|
;; We take advantage of that to conjure up a debug loc without
|
||||||
|
;; having to synthesize one programatically.
|
||||||
|
ret void, !dbg !11
|
||||||
|
}
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
|
||||||
|
attributes #0 = { nounwind readnone speculatable willreturn }
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!5}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||||
|
!1 = !DIFile(filename: "t.ll", directory: "/")
|
||||||
|
!2 = !{}
|
||||||
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
|
||||||
|
!7 = !DISubroutineType(types: !2)
|
||||||
|
!8 = !{!9}
|
||||||
|
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
|
||||||
|
!10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
|
||||||
|
!11 = !DILocation(line: 1, column: 1, scope: !6)
|
||||||
|
)");
|
||||||
|
auto *F = M->getFunction("f");
|
||||||
|
auto *EntryBlock = &F->getEntryBlock();
|
||||||
|
|
||||||
|
auto *CU =
|
||||||
|
cast<DICompileUnit>(M->getNamedMetadata("llvm.dbg.cu")->getOperand(0));
|
||||||
|
auto *Alloca = &*EntryBlock->begin();
|
||||||
|
auto *Ret = EntryBlock->getTerminator();
|
||||||
|
|
||||||
|
auto *SP = cast<DISubprogram>(F->getMetadata(LLVMContext::MD_dbg));
|
||||||
|
auto *File = SP->getFile();
|
||||||
|
std::string Name = "myName";
|
||||||
|
const auto *Loc = Ret->getDebugLoc().get();
|
||||||
|
|
||||||
|
IRBuilder<> Builder(EntryBlock);
|
||||||
|
DIBuilder DIB(*M, true, CU);
|
||||||
|
DIType *DT = DIB.createBasicType("ty16", 16, dwarf::DW_ATE_unsigned);
|
||||||
|
|
||||||
|
DILocalVariable *LocalVar =
|
||||||
|
DIB.createAutoVariable(SP, Name, File, 5 /*line*/, DT,
|
||||||
|
/*AlwaysPreserve=*/true);
|
||||||
|
|
||||||
|
auto *Inst = DIB.insertDbgAddrIntrinsic(Alloca, LocalVar,
|
||||||
|
DIB.createExpression(), Loc, Ret);
|
||||||
|
|
||||||
|
DIB.finalize();
|
||||||
|
|
||||||
|
EXPECT_EQ(Inst->getDebugLoc().get(), Loc);
|
||||||
|
|
||||||
|
auto *MD0 = cast<MetadataAsValue>(Inst->getOperand(0))->getMetadata();
|
||||||
|
auto *MD0Local = cast<LocalAsMetadata>(MD0);
|
||||||
|
EXPECT_EQ(MD0Local->getValue(), Alloca);
|
||||||
|
auto *MD1 = cast<MetadataAsValue>(Inst->getOperand(1))->getMetadata();
|
||||||
|
EXPECT_EQ(MD1->getMetadataID(), Metadata::MetadataKind::DILocalVariableKind);
|
||||||
|
auto *MD2 = cast<MetadataAsValue>(Inst->getOperand(2))->getMetadata();
|
||||||
|
auto *MDExp = cast<DIExpression>(MD2);
|
||||||
|
EXPECT_EQ(MDExp->getNumElements(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
Loading…
Reference in New Issue