From 02ac75092dbbd9efb250bfb4f4e79dd042abf3c4 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 3 Oct 2019 16:30:29 +0000 Subject: [PATCH] [BPF] Handle offset reloc endpoint ending in the middle of chain properly During studying support for bitfield, I found an issue for an example like the one in test offset-reloc-middle-chain.ll. struct t1 { int c; }; struct s1 { struct t1 b; }; struct r1 { struct s1 a; }; #define _(x) __builtin_preserve_access_index(x) void test1(void *p1, void *p2, void *p3); void test(struct r1 *arg) { struct s1 *ps = _(&arg->a); struct t1 *pt = _(&arg->a.b); int *pi = _(&arg->a.b.c); test1(ps, pt, pi); } The IR looks like: %0 = llvm.preserve.struct.access(base, ...) %1 = llvm.preserve.struct.access(%0, ...) %2 = llvm.preserve.struct.access(%1, ...) using %0, %1 and %2 In this case, we need to generate three relocatiions corresponding to chains: (%0), (%0, %1) and (%0, %1, %2). After collecting all the chains, the current implementation process each chain (in a map) with code generation sequentially. For example, after (%0) is processed, the code may look like: %0 = base + special_global_variable // llvm.preserve.struct.access(base, ...) is delisted // from the instruction stream. %1 = llvm.preserve.struct.access(%0, ...) %2 = llvm.preserve.struct.access(%1, ...) using %0, %1 and %2 When processing chain (%0, %1), the current implementation tries to visit intrinsic llvm.preserve.struct.access(base, ...) to get some of its properties and this caused segfault. This patch fixed the issue by remembering all necessary information (kind, metadata, access_index, base) during analysis phase, so in code generation phase there is no need to examine the intrinsic call instructions. This also simplifies the code. Differential Revision: https://reviews.llvm.org/D68389 llvm-svn: 373621 --- llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp | 218 ++++++++++----------- .../CodeGen/BPF/CORE/offset-reloc-middle-chain.ll | 127 ++++++++++++ 2 files changed, 227 insertions(+), 118 deletions(-) create mode 100644 llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp index c682c46..870300a 100644 --- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp @@ -90,6 +90,13 @@ public: static char ID; BPFAbstractMemberAccess() : ModulePass(ID) {} + struct CallInfo { + uint32_t Kind; + uint32_t AccessIndex; + MDNode *Metadata; + Value *Base; + }; + private: enum : uint32_t { BPFPreserveArrayAI = 1, @@ -99,34 +106,32 @@ private: std::map GEPGlobals; // A map to link preserve_*_access_index instrinsic calls. - std::map> AIChain; + std::map> AIChain; // A map to hold all the base preserve_*_access_index instrinsic calls. // The base call is not an input of any other preserve_*_access_index // intrinsics. - std::map BaseAICalls; + std::map BaseAICalls; bool doTransformation(Module &M); - void traceAICall(CallInst *Call, uint32_t Kind, const MDNode *ParentMeta, - uint32_t ParentAI); - void traceBitCast(BitCastInst *BitCast, CallInst *Parent, uint32_t Kind, - const MDNode *ParentMeta, uint32_t ParentAI); - void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, uint32_t Kind, - const MDNode *ParentMeta, uint32_t ParentAI); + void traceAICall(CallInst *Call, CallInfo &ParentInfo); + void traceBitCast(BitCastInst *BitCast, CallInst *Parent, + CallInfo &ParentInfo); + void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, + CallInfo &ParentInfo); void collectAICallChains(Module &M, Function &F); - bool IsPreserveDIAccessIndexCall(const CallInst *Call, uint32_t &Kind, - const MDNode *&TypeMeta, uint32_t &AccessIndex); + bool IsPreserveDIAccessIndexCall(const CallInst *Call, CallInfo &Cinfo); bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI, const MDNode *ChildMeta); bool removePreserveAccessIndexIntrinsic(Module &M); void replaceWithGEP(std::vector &CallList, uint32_t NumOfZerosIndex, uint32_t DIIndex); - Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey, - uint32_t Kind, MDNode *&BaseMeta); - bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex); - bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind); + Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo, + std::string &AccessKey, MDNode *&BaseMeta); + uint64_t getConstant(const Value *IndexValue); + bool transformGEPChain(Module &M, CallInst *Call, CallInfo &CInfo); }; } // End anonymous namespace @@ -192,9 +197,7 @@ static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) { /// Check whether a call is a preserve_*_access_index intrinsic call or not. bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, - uint32_t &Kind, - const MDNode *&TypeMeta, - uint32_t &AccessIndex) { + CallInfo &CInfo) { if (!Call) return false; @@ -202,30 +205,30 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, if (!GV) return false; if (GV->getName().startswith("llvm.preserve.array.access.index")) { - Kind = BPFPreserveArrayAI; - TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index); - if (!TypeMeta) + CInfo.Kind = BPFPreserveArrayAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic"); - AccessIndex = cast(Call->getArgOperand(2)) - ->getZExtValue(); + CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); + CInfo.Base = Call->getArgOperand(0); return true; } if (GV->getName().startswith("llvm.preserve.union.access.index")) { - Kind = BPFPreserveUnionAI; - TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index); - if (!TypeMeta) + CInfo.Kind = BPFPreserveUnionAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic"); - AccessIndex = cast(Call->getArgOperand(1)) - ->getZExtValue(); + CInfo.AccessIndex = getConstant(Call->getArgOperand(1)); + CInfo.Base = Call->getArgOperand(0); return true; } if (GV->getName().startswith("llvm.preserve.struct.access.index")) { - Kind = BPFPreserveStructAI; - TypeMeta = Call->getMetadata(LLVMContext::MD_preserve_access_index); - if (!TypeMeta) + CInfo.Kind = BPFPreserveStructAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic"); - AccessIndex = cast(Call->getArgOperand(2)) - ->getZExtValue(); + CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); + CInfo.Base = Call->getArgOperand(0); return true; } @@ -238,8 +241,7 @@ void BPFAbstractMemberAccess::replaceWithGEP(std::vector &CallList, for (auto Call : CallList) { uint32_t Dimension = 1; if (DimensionIndex > 0) - Dimension = cast(Call->getArgOperand(DimensionIndex)) - ->getZExtValue(); + Dimension = getConstant(Call->getArgOperand(DimensionIndex)); Constant *Zero = ConstantInt::get(Type::getInt32Ty(Call->getParent()->getContext()), 0); @@ -265,16 +267,14 @@ bool BPFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Module &M) { for (auto &BB : F) for (auto &I : BB) { auto *Call = dyn_cast(&I); - uint32_t Kind; - const MDNode *TypeMeta; - uint32_t AccessIndex; - if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex)) + CallInfo CInfo; + if (!IsPreserveDIAccessIndexCall(Call, CInfo)) continue; Found = true; - if (Kind == BPFPreserveArrayAI) + if (CInfo.Kind == BPFPreserveArrayAI) PreserveArrayIndexCalls.push_back(Call); - else if (Kind == BPFPreserveUnionAI) + else if (CInfo.Kind == BPFPreserveUnionAI) PreserveUnionIndexCalls.push_back(Call); else PreserveStructIndexCalls.push_back(Call); @@ -349,99 +349,94 @@ bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType, return dyn_cast(stripQualifiers(Ty)) == CTy; } -void BPFAbstractMemberAccess::traceAICall(CallInst *Call, uint32_t Kind, - const MDNode *ParentMeta, - uint32_t ParentAI) { +void BPFAbstractMemberAccess::traceAICall(CallInst *Call, + CallInfo &ParentInfo) { for (User *U : Call->users()) { Instruction *Inst = dyn_cast(U); if (!Inst) continue; if (auto *BI = dyn_cast(Inst)) { - traceBitCast(BI, Call, Kind, ParentMeta, ParentAI); + traceBitCast(BI, Call, ParentInfo); } else if (auto *CI = dyn_cast(Inst)) { - uint32_t CIKind; - const MDNode *ChildMeta; - uint32_t ChildAI; - if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) && - IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) { - AIChain[CI] = std::make_pair(Call, Kind); - traceAICall(CI, CIKind, ChildMeta, ChildAI); + CallInfo ChildInfo; + + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Call, ParentInfo); + traceAICall(CI, ChildInfo); } else { - BaseAICalls[Call] = Kind; + BaseAICalls[Call] = ParentInfo; } } else if (auto *GI = dyn_cast(Inst)) { if (GI->hasAllZeroIndices()) - traceGEP(GI, Call, Kind, ParentMeta, ParentAI); + traceGEP(GI, Call, ParentInfo); else - BaseAICalls[Call] = Kind; + BaseAICalls[Call] = ParentInfo; } else { - BaseAICalls[Call] = Kind; + BaseAICalls[Call] = ParentInfo; } } } void BPFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast, - CallInst *Parent, uint32_t Kind, - const MDNode *ParentMeta, - uint32_t ParentAI) { + CallInst *Parent, + CallInfo &ParentInfo) { for (User *U : BitCast->users()) { Instruction *Inst = dyn_cast(U); if (!Inst) continue; if (auto *BI = dyn_cast(Inst)) { - traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI); + traceBitCast(BI, Parent, ParentInfo); } else if (auto *CI = dyn_cast(Inst)) { - uint32_t CIKind; - const MDNode *ChildMeta; - uint32_t ChildAI; - if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) && - IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) { - AIChain[CI] = std::make_pair(Parent, Kind); - traceAICall(CI, CIKind, ChildMeta, ChildAI); + CallInfo ChildInfo; + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Parent, ParentInfo); + traceAICall(CI, ChildInfo); } else { - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } } else if (auto *GI = dyn_cast(Inst)) { if (GI->hasAllZeroIndices()) - traceGEP(GI, Parent, Kind, ParentMeta, ParentAI); + traceGEP(GI, Parent, ParentInfo); else - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } else { - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } } } void BPFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent, - uint32_t Kind, const MDNode *ParentMeta, - uint32_t ParentAI) { + CallInfo &ParentInfo) { for (User *U : GEP->users()) { Instruction *Inst = dyn_cast(U); if (!Inst) continue; if (auto *BI = dyn_cast(Inst)) { - traceBitCast(BI, Parent, Kind, ParentMeta, ParentAI); + traceBitCast(BI, Parent, ParentInfo); } else if (auto *CI = dyn_cast(Inst)) { - uint32_t CIKind; - const MDNode *ChildMeta; - uint32_t ChildAI; - if (IsPreserveDIAccessIndexCall(CI, CIKind, ChildMeta, ChildAI) && - IsValidAIChain(ParentMeta, ParentAI, ChildMeta)) { - AIChain[CI] = std::make_pair(Parent, Kind); - traceAICall(CI, CIKind, ChildMeta, ChildAI); + CallInfo ChildInfo; + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Parent, ParentInfo); + traceAICall(CI, ChildInfo); } else { - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } } else if (auto *GI = dyn_cast(Inst)) { if (GI->hasAllZeroIndices()) - traceGEP(GI, Parent, Kind, ParentMeta, ParentAI); + traceGEP(GI, Parent, ParentInfo); else - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } else { - BaseAICalls[Parent] = Kind; + BaseAICalls[Parent] = ParentInfo; } } } @@ -452,44 +447,37 @@ void BPFAbstractMemberAccess::collectAICallChains(Module &M, Function &F) { for (auto &BB : F) for (auto &I : BB) { - uint32_t Kind; - const MDNode *TypeMeta; - uint32_t AccessIndex; + CallInfo CInfo; auto *Call = dyn_cast(&I); - if (!IsPreserveDIAccessIndexCall(Call, Kind, TypeMeta, AccessIndex) || + if (!IsPreserveDIAccessIndexCall(Call, CInfo) || AIChain.find(Call) != AIChain.end()) continue; - traceAICall(Call, Kind, TypeMeta, AccessIndex); + traceAICall(Call, CInfo); } } -/// Get access index from the preserve_*_access_index intrinsic calls. -bool BPFAbstractMemberAccess::getAccessIndex(const Value *IndexValue, - uint64_t &AccessIndex) { +uint64_t BPFAbstractMemberAccess::getConstant(const Value *IndexValue) { const ConstantInt *CV = dyn_cast(IndexValue); - if (!CV) - return false; - - AccessIndex = CV->getValue().getZExtValue(); - return true; + assert(CV); + return CV->getValue().getZExtValue(); } /// Compute the base of the whole preserve_*_access_index chains, i.e., the base /// pointer of the first preserve_*_access_index call, and construct the access /// string, which will be the name of a global variable. Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, + CallInfo &CInfo, std::string &AccessKey, - uint32_t Kind, MDNode *&TypeMeta) { Value *Base = nullptr; std::string TypeName; - std::stack> CallStack; + std::stack> CallStack; // Put the access chain into a stack with the top as the head of the chain. while (Call) { - CallStack.push(std::make_pair(Call, Kind)); - Kind = AIChain[Call].second; + CallStack.push(std::make_pair(Call, CInfo)); + CInfo = AIChain[Call].second; Call = AIChain[Call].first; } @@ -508,14 +496,14 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, while (CallStack.size()) { auto StackElem = CallStack.top(); Call = StackElem.first; - Kind = StackElem.second; + CInfo = StackElem.second; if (!Base) - Base = Call->getArgOperand(0); + Base = CInfo.Base; - MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index); - DIType *Ty = stripQualifiers(cast(MDN)); - if (Kind == BPFPreserveUnionAI || Kind == BPFPreserveStructAI) { + DIType *Ty = stripQualifiers(cast(CInfo.Metadata)); + if (CInfo.Kind == BPFPreserveUnionAI || + CInfo.Kind == BPFPreserveStructAI) { // struct or union type TypeName = Ty->getName(); TypeMeta = Ty; @@ -527,9 +515,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, CallStack.pop(); // BPFPreserveArrayAI - uint64_t AccessIndex; - if (!getAccessIndex(Call->getArgOperand(2), AccessIndex)) - return nullptr; + uint64_t AccessIndex = CInfo.AccessIndex; DIType *BaseTy = nullptr; bool CheckElemType = false; @@ -580,18 +566,14 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, // and access key construction. while (CallStack.size()) { auto StackElem = CallStack.top(); - Call = StackElem.first; - Kind = StackElem.second; + CInfo = StackElem.second; CallStack.pop(); // Access Index - uint64_t AccessIndex; - uint32_t ArgIndex = (Kind == BPFPreserveUnionAI) ? 1 : 2; - if (!getAccessIndex(Call->getArgOperand(ArgIndex), AccessIndex)) - return nullptr; + uint64_t AccessIndex = CInfo.AccessIndex; AccessKey += ":" + std::to_string(AccessIndex); - MDNode *MDN = Call->getMetadata(LLVMContext::MD_preserve_access_index); + MDNode *MDN = CInfo.Metadata; // At this stage, it cannot be pointer type. auto *CTy = cast(stripQualifiers(cast(MDN))); uint32_t Tag = CTy->getTag(); @@ -615,11 +597,11 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, /// Call/Kind is the base preserve_*_access_index() call. Attempts to do /// transformation to a chain of relocable GEPs. bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call, - uint32_t Kind) { + CallInfo &CInfo) { std::string AccessKey; MDNode *TypeMeta; Value *Base = - computeBaseAndAccessKey(Call, AccessKey, Kind, TypeMeta); + computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta); if (!Base) return false; diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll new file mode 100644 index 0000000..0f75cd8 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll @@ -0,0 +1,127 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct t1 { +; int c; +; }; +; struct s1 { +; struct t1 b; +; }; +; struct r1 { +; struct s1 a; +; }; +; #define _(x) __builtin_preserve_access_index(x) +; void test1(void *p1, void *p2, void *p3); +; void test(struct r1 *arg) { +; struct s1 *ps = _(&arg->a); +; struct t1 *pt = _(&arg->a.b); +; int *pi = _(&arg->a.b.c); +; test1(ps, pt, pi); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.r1 = type { %struct.s1 } +%struct.s1 = type { %struct.t1 } +%struct.t1 = type { i32 } + +; Function Attrs: nounwind +define dso_local void @test(%struct.r1* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.r1* %arg, metadata !22, metadata !DIExpression()), !dbg !29 + %0 = tail call %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1* %arg, i32 0, i32 0), !dbg !30, !llvm.preserve.access.index !11 + call void @llvm.dbg.value(metadata %struct.s1* %0, metadata !23, metadata !DIExpression()), !dbg !29 + %1 = tail call %struct.t1* @llvm.preserve.struct.access.index.p0s_struct.t1s.p0s_struct.s1s(%struct.s1* %0, i32 0, i32 0), !dbg !31, !llvm.preserve.access.index !14 + call void @llvm.dbg.value(metadata %struct.t1* %1, metadata !25, metadata !DIExpression()), !dbg !29 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.t1s(%struct.t1* %1, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !17 + call void @llvm.dbg.value(metadata i32* %2, metadata !27, metadata !DIExpression()), !dbg !29 + %3 = bitcast %struct.s1* %0 to i8*, !dbg !33 + %4 = bitcast %struct.t1* %1 to i8*, !dbg !34 + %5 = bitcast i32* %2 to i8*, !dbg !35 + tail call void @test1(i8* %3, i8* %4, i8* %5) #4, !dbg !36 + ret void, !dbg !37 +} + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .ascii "r1" # string offset=1 +; CHECK: .ascii ".text" # string offset=29 +; CHECK: .ascii "0:0" # string offset=72 +; CHECK: .ascii "0:0:0" # string offset=76 +; CHECK: .ascii "0:0:0:0" # string offset=82 + +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long 29 # Offset reloc section string offset=29 +; CHECK-NEXT: .long 3 +; CHECK_NEXT: .long .Ltmp{{[0-9]+}} +; CHECK_NEXT: .long 2 +; CHECK_NEXT: .long 72 +; CHECK_NEXT: .long .Ltmp{{[0-9]+}} +; CHECK_NEXT: .long 2 +; CHECK_NEXT: .long 76 +; CHECK_NEXT: .long .Ltmp{{[0-9]+}} +; CHECK_NEXT: .long 2 +; CHECK_NEXT: .long 82 + +; Function Attrs: nounwind readnone +declare %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare %struct.t1* @llvm.preserve.struct.access.index.p0s_struct.t1s.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.t1s(%struct.t1*, i32, i32) #1 + +declare dso_local void @test1(i8*, i8*, i8*) local_unnamed_addr #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!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 10.0.0 (https://github.com/llvm/llvm-project.git 42b3328a2368b38fba6bdb0c616fe6c5520e3bc5)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 42b3328a2368b38fba6bdb0c616fe6c5520e3bc5)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 12, type: !8, scopeLine: 12, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "r1", file: !1, line: 7, size: 32, elements: !12) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !11, file: !1, line: 8, baseType: !14, size: 32) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 4, size: 32, elements: !15) +!15 = !{!16} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 5, baseType: !17, size: 32) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !18) +!18 = !{!19} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !17, file: !1, line: 2, baseType: !20, size: 32) +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !{!22, !23, !25, !27} +!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 12, type: !10) +!23 = !DILocalVariable(name: "ps", scope: !7, file: !1, line: 13, type: !24) +!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!25 = !DILocalVariable(name: "pt", scope: !7, file: !1, line: 14, type: !26) +!26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!27 = !DILocalVariable(name: "pi", scope: !7, file: !1, line: 15, type: !28) +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!29 = !DILocation(line: 0, scope: !7) +!30 = !DILocation(line: 13, column: 19, scope: !7) +!31 = !DILocation(line: 14, column: 19, scope: !7) +!32 = !DILocation(line: 15, column: 13, scope: !7) +!33 = !DILocation(line: 16, column: 9, scope: !7) +!34 = !DILocation(line: 16, column: 13, scope: !7) +!35 = !DILocation(line: 16, column: 17, scope: !7) +!36 = !DILocation(line: 16, column: 3, scope: !7) +!37 = !DILocation(line: 17, column: 1, scope: !7) -- 2.7.4