diff --git a/llvm/lib/Target/BPF/BPF.h b/llvm/lib/Target/BPF/BPF.h --- a/llvm/lib/Target/BPF/BPF.h +++ b/llvm/lib/Target/BPF/BPF.h @@ -16,6 +16,7 @@ class BPFTargetMachine; ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); +ModulePass *createBPFPreserveDIType(); FunctionPass *createBPFISelDag(BPFTargetMachine &TM); FunctionPass *createBPFMISimplifyPatchablePass(); @@ -25,6 +26,7 @@ FunctionPass *createBPFMIPreEmitCheckingPass(); void initializeBPFAbstractMemberAccessPass(PassRegistry&); +void initializeBPFPreserveDITypePass(PassRegistry&); void initializeBPFMISimplifyPatchablePass(PassRegistry&); void initializeBPFMIPeepholePass(PassRegistry&); void initializeBPFMIPeepholeTruncElimPass(PassRegistry&); diff --git a/llvm/lib/Target/BPF/BPFCORE.h b/llvm/lib/Target/BPF/BPFCORE.h --- a/llvm/lib/Target/BPF/BPFCORE.h +++ b/llvm/lib/Target/BPF/BPFCORE.h @@ -13,18 +13,21 @@ class BPFCoreSharedInfo { public: - enum OffsetRelocKind : uint32_t { + enum PatchableRelocKind : uint32_t { FIELD_BYTE_OFFSET = 0, FIELD_BYTE_SIZE, FIELD_EXISTENCE, FIELD_SIGNEDNESS, FIELD_LSHIFT_U64, FIELD_RSHIFT_U64, + BTF_TYPE_ID, MAX_FIELD_RELOC_KIND, }; /// The attribute attached to globals representing a field access static const std::string AmaAttr; + /// The attribute attached to globals representing a type id + static const std::string TypeIdAttr; }; } // namespace llvm diff --git a/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp b/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp --- a/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp +++ b/llvm/lib/Target/BPF/BPFMISimplifyPatchable.cpp @@ -22,6 +22,9 @@ // r1 = // add r3, struct_base_reg, r1 // +// This pass also removes the intermediate load generated in IR pass for +// __builtin_btf_type_id() intrinsic. +// //===----------------------------------------------------------------------===// #include "BPF.h" @@ -55,10 +58,10 @@ bool removeLD(void); void processCandidate(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, MachineInstr &MI, Register &SrcReg, Register &DstReg, - const GlobalValue *GVal); + const GlobalValue *GVal, bool IsAma); void processDstReg(MachineRegisterInfo *MRI, Register &DstReg, Register &SrcReg, const GlobalValue *GVal, - bool doSrcRegProp); + bool doSrcRegProp, bool IsAma); void processInst(MachineRegisterInfo *MRI, MachineInstr *Inst, MachineOperand *RelocOp, const GlobalValue *GVal); void checkADDrr(MachineRegisterInfo *MRI, MachineOperand *RelocOp, @@ -144,25 +147,27 @@ void BPFMISimplifyPatchable::processCandidate(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, MachineInstr &MI, Register &SrcReg, - Register &DstReg, const GlobalValue *GVal) { + Register &DstReg, const GlobalValue *GVal, bool IsAma) { if (MRI->getRegClass(DstReg) == &BPF::GPR32RegClass) { - // We can optimize such a pattern: - // %1:gpr = LD_imm64 @"llvm.s:0:4$0:2" - // %2:gpr32 = LDW32 %1:gpr, 0 - // %3:gpr = SUBREG_TO_REG 0, %2:gpr32, %subreg.sub_32 - // %4:gpr = ADD_rr %0:gpr, %3:gpr - // or similar patterns below for non-alu32 case. - auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); - decltype(End) NextI; - for (auto I = Begin; I != End; I = NextI) { - NextI = std::next(I); - if (!MRI->getUniqueVRegDef(I->getReg())) - continue; - - unsigned Opcode = I->getParent()->getOpcode(); - if (Opcode == BPF::SUBREG_TO_REG) { - Register TmpReg = I->getParent()->getOperand(0).getReg(); - processDstReg(MRI, TmpReg, DstReg, GVal, false); + if (IsAma) { + // We can optimize such a pattern: + // %1:gpr = LD_imm64 @"llvm.s:0:4$0:2" + // %2:gpr32 = LDW32 %1:gpr, 0 + // %3:gpr = SUBREG_TO_REG 0, %2:gpr32, %subreg.sub_32 + // %4:gpr = ADD_rr %0:gpr, %3:gpr + // or similar patterns below for non-alu32 case. + auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); + decltype(End) NextI; + for (auto I = Begin; I != End; I = NextI) { + NextI = std::next(I); + if (!MRI->getUniqueVRegDef(I->getReg())) + continue; + + unsigned Opcode = I->getParent()->getOpcode(); + if (Opcode == BPF::SUBREG_TO_REG) { + Register TmpReg = I->getParent()->getOperand(0).getReg(); + processDstReg(MRI, TmpReg, DstReg, GVal, false, IsAma); + } } } @@ -172,12 +177,12 @@ } // All uses of DstReg replaced by SrcReg - processDstReg(MRI, DstReg, SrcReg, GVal, true); + processDstReg(MRI, DstReg, SrcReg, GVal, true, IsAma); } void BPFMISimplifyPatchable::processDstReg(MachineRegisterInfo *MRI, Register &DstReg, Register &SrcReg, const GlobalValue *GVal, - bool doSrcRegProp) { + bool doSrcRegProp, bool IsAma) { auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); decltype(End) NextI; for (auto I = Begin; I != End; I = NextI) { @@ -186,7 +191,7 @@ I->setReg(SrcReg); // The candidate needs to have a unique definition. - if (MRI->getUniqueVRegDef(I->getReg())) + if (IsAma && MRI->getUniqueVRegDef(I->getReg())) processInst(MRI, I->getParent(), &*I, GVal); } } @@ -258,28 +263,26 @@ if (!DefInst) continue; - bool IsCandidate = false; - const GlobalValue *GVal = nullptr; - if (DefInst->getOpcode() == BPF::LD_imm64) { - const MachineOperand &MO = DefInst->getOperand(1); - if (MO.isGlobal()) { - GVal = MO.getGlobal(); - auto *GVar = dyn_cast(GVal); - if (GVar) { - // Global variables representing structure offset or - // patchable extern globals. - if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - assert(MI.getOperand(2).getImm() == 0); - IsCandidate = true; - } - } - } - } + if (DefInst->getOpcode() != BPF::LD_imm64) + continue; + + const MachineOperand &MO = DefInst->getOperand(1); + if (!MO.isGlobal()) + continue; + + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (!GVar) + continue; - if (!IsCandidate) + // Global variables representing structure offset or type id. + bool IsAma = false; + if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) + IsAma = true; + else if (!GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) continue; - processCandidate(MRI, MBB, MI, SrcReg, DstReg, GVal); + processCandidate(MRI, MBB, MI, SrcReg, DstReg, GVal, IsAma); ToErase = &MI; Changed = true; diff --git a/llvm/lib/Target/BPF/BPFPreserveDIType.cpp b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp @@ -0,0 +1,116 @@ +//===------------- BPFPreserveType.cpp - Preserve DebugInfo Types ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Preserve Debuginfo types encoded in __builtin_bpf_btf_type_id() metadata. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "BPFCORE.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +#define DEBUG_TYPE "bpf-preserve-di-type" + +namespace llvm { +const std::string BPFCoreSharedInfo::TypeIdAttr = "btf_type_id"; +} // namespace llvm + +using namespace llvm; + +namespace { + +class BPFPreserveDIType final : public ModulePass { + StringRef getPassName() const override { + return "BPF Preserve DebugInfo Type"; + } + + bool runOnModule(Module &M) override; + +public: + static char ID; + BPFPreserveDIType() : ModulePass(ID) {} + +private: + bool doTransformation(Module &M); +}; +} // End anonymous namespace + +char BPFPreserveDIType::ID = 0; +INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "preserve debuginfo type", false, + false) + +ModulePass *llvm::createBPFPreserveDIType() { return new BPFPreserveDIType(); } + +bool BPFPreserveDIType::runOnModule(Module &M) { + LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n"); + + // Bail out if no debug info. + if (M.debug_compile_units().empty()) + return false; + + return doTransformation(M); +} + +bool BPFPreserveDIType::doTransformation(Module &M) { + std::vector PreserveDITypeCalls; + + for (auto &F : M) { + for (auto &BB : F) { + for (auto &I : BB) { + auto *Call = dyn_cast(&I); + if (!Call) + continue; + + const auto *GV = dyn_cast(Call->getCalledValue()); + if (!GV) + continue; + + if (GV->getName().startswith("llvm.bpf.btf.type.id")) { + if (!Call->getMetadata(LLVMContext::MD_preserve_access_index)) + report_fatal_error( + "Missing metadata for llvm.bpf.btf.type.id intrinsic"); + PreserveDITypeCalls.push_back(Call); + } + } + } + } + + if (PreserveDITypeCalls.empty()) + return false; + + std::string BaseName = "llvm.bpf_pdit."; + int Count = 0; + for (auto Call : PreserveDITypeCalls) { + BasicBlock *BB = Call->getParent(); + IntegerType *VarType = Type::getInt32Ty(BB->getContext()); + GlobalVariable *GV = + new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage, + NULL, BaseName + std::to_string(Count)); + GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr); + MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index); + GV->setMetadata(LLVMContext::MD_preserve_access_index, MD); + + // Load the global variable which represents the type info. + auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV); + BB->getInstList().insert(Call->getIterator(), LDInst); + Call->replaceAllUsesWith(LDInst); + Call->eraseFromParent(); + Count++; + } + + return true; +} diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -35,6 +35,7 @@ PassRegistry &PR = *PassRegistry::getPassRegistry(); initializeBPFAbstractMemberAccessPass(PR); + initializeBPFPreserveDITypePass(PR); initializeBPFMIPeepholePass(PR); initializeBPFMIPeepholeTruncElimPass(PR); } @@ -96,6 +97,7 @@ void BPFPassConfig::addIRPasses() { addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); + addPass(createBPFPreserveDIType()); TargetPassConfig::addIRPasses(); } diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -25,6 +25,7 @@ class AsmPrinter; class BTFDebug; class DIType; +class GlobalVariable; class MCStreamer; class MCSymbol; class MachineFunction; @@ -249,7 +250,7 @@ StringMap> FileContent; std::map> DataSecEntries; std::vector StructTypes; - std::map PatchImms; + std::map PatchImms; std::map>> FixupDerivedTypes; std::setProtoFunctions; @@ -299,11 +300,11 @@ void processFuncPrototypes(const Function *); /// Generate one field relocation record. - void generateFieldReloc(const MCSymbol *ORSym, DIType *RootTy, - StringRef AccessPattern); + void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, + const GlobalVariable *, bool IsAma); - /// Populating unprocessed struct type. - unsigned populateStructType(const DIType *Ty); + /// Populating unprocessed type on demand. + unsigned populateType(const DIType *Ty); /// Process relocation instructions. void processReloc(const MachineOperand &MO); diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -928,9 +928,9 @@ SecNameOff = 0; } -/// On-demand populate struct types as requested from abstract member -/// accessing. -unsigned BTFDebug::populateStructType(const DIType *Ty) { +/// On-demand populate types as requested from abstract member +/// accessing or preserve debuginfo type. +unsigned BTFDebug::populateType(const DIType *Ty) { unsigned Id; visitTypeEntry(Ty, Id, false, false); for (const auto &TypeEntry : TypeEntries) @@ -939,24 +939,32 @@ } /// Generate a struct member field relocation. -void BTFDebug::generateFieldReloc(const MCSymbol *ORSym, DIType *RootTy, - StringRef AccessPattern) { - unsigned RootId = populateStructType(RootTy); - size_t FirstDollar = AccessPattern.find_first_of('$'); - size_t FirstColon = AccessPattern.find_first_of(':'); - size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1); - StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1); - StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1, - SecondColon - FirstColon); - StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1, - FirstDollar - SecondColon); - +void BTFDebug::generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, + const GlobalVariable *GVar, bool IsAma) { BTFFieldReloc FieldReloc; FieldReloc.Label = ORSym; - FieldReloc.OffsetNameOff = addString(IndexPattern); FieldReloc.TypeID = RootId; - FieldReloc.RelocKind = std::stoull(std::string(RelocKindStr)); - PatchImms[AccessPattern.str()] = std::stoul(std::string(PatchImmStr)); + + if (IsAma) { + StringRef AccessPattern = GVar->getName(); + size_t FirstDollar = AccessPattern.find_first_of('$'); + size_t FirstColon = AccessPattern.find_first_of(':'); + size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1); + StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1); + StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1, + SecondColon - FirstColon); + StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1, + FirstDollar - SecondColon); + + FieldReloc.OffsetNameOff = addString(IndexPattern); + FieldReloc.RelocKind = std::stoull(std::string(RelocKindStr)); + PatchImms[GVar] = std::stoul(std::string(PatchImmStr)); + } else { + FieldReloc.OffsetNameOff = 0; + FieldReloc.RelocKind = BPFCoreSharedInfo::BTF_TYPE_ID; + PatchImms[GVar] = RootId; + } + FieldRelocTable[SecNameOff].push_back(FieldReloc); } @@ -965,14 +973,20 @@ if (MO.isGlobal()) { const GlobalValue *GVal = MO.getGlobal(); auto *GVar = dyn_cast(GVal); - if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - MCSymbol *ORSym = OS.getContext().createTempSymbol(); - OS.EmitLabel(ORSym); + if (!GVar) + return; - MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index); - DIType *Ty = dyn_cast(MDN); - generateFieldReloc(ORSym, Ty, GVar->getName()); - } + if (!GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr) && + !GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) + return; + + MCSymbol *ORSym = OS.getContext().createTempSymbol(); + OS.EmitLabel(ORSym); + + MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index); + uint32_t RootId = populateType(dyn_cast(MDN)); + generatePatchImmReloc(ORSym, RootId, GVar, + GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)); } } @@ -1008,6 +1022,9 @@ // Later, the insn is replaced with "r2 = " // where "" equals to the offset based on current // type definitions. + // + // If the insn is "r2 = LD_imm64 @", + // The LD_imm64 result will be replaced with a btf type id. processReloc(MI->getOperand(1)); } else if (MI->getOpcode() == BPF::CORE_MEM || MI->getOpcode() == BPF::CORE_ALU32_MEM || @@ -1140,9 +1157,15 @@ if (MO.isGlobal()) { const GlobalValue *GVal = MO.getGlobal(); auto *GVar = dyn_cast(GVal); - if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - // Emit "mov ri, " for patched immediate. - uint32_t Imm = PatchImms[GVar->getName().str()]; + if (GVar) { + // Emit "mov ri, " + uint32_t Imm; + if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr) || + GVar->hasAttribute(BPFCoreSharedInfo::TypeIdAttr)) + Imm = PatchImms[GVar]; + else + return false; + OutMI.setOpcode(BPF::MOV_ri); OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); OutMI.addOperand(MCOperand::createImm(Imm)); @@ -1157,7 +1180,7 @@ const GlobalValue *GVal = MO.getGlobal(); auto *GVar = dyn_cast(GVal); if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - uint32_t Imm = PatchImms[GVar->getName().str()]; + uint32_t Imm = PatchImms[GVar]; OutMI.setOpcode(MI->getOperand(1).getImm()); if (MI->getOperand(0).isImm()) OutMI.addOperand(MCOperand::createImm(MI->getOperand(0).getImm())); diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -20,6 +20,7 @@ BPFISelDAGToDAG.cpp BPFISelLowering.cpp BPFMCInstLower.cpp + BPFPreserveDIType.cpp BPFRegisterInfo.cpp BPFSelectionDAGInfo.cpp BPFSubtarget.cpp diff --git a/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id.ll b/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id.ll @@ -0,0 +1,147 @@ +; 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 +; RUN: llc -march=bpfel -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -mattr=+alu32 -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; static int (*bpf_log)(unsigned tid, void *data, int data_size) = (void *)999; +; struct { +; char f1[100]; +; typeof(3) f2; +; } tmp__abc = {1, 3}; +; void prog1() { +; bpf_log(__builtin_btf_type_id(tmp__abc), &tmp__abc, sizeof(tmp__abc)); +; } +; void prog2() { +; bpf_log(__builtin_btf_type_id(&tmp__abc), &tmp__abc, sizeof(tmp__abc)); +; } +; void prog3() { +; bpf_log(__builtin_btf_type_id(tmp__abc.f1[3]), &tmp__abc, sizeof(tmp__abc)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.anon = type { [100 x i8], i32 } + +@tmp__abc = dso_local global { <{ i8, i8, [98 x i8] }>, i32 } { <{ i8, i8, [98 x i8] }> <{ i8 1, i8 3, [98 x i8] zeroinitializer }>, i32 0 }, align 4, !dbg !0 + +; Function Attrs: nounwind +define dso_local void @prog1() local_unnamed_addr #0 !dbg !28 { +entry: + %0 = tail call i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon* bitcast ({ <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc to %struct.anon*), i32 1), !dbg !31, !llvm.preserve.access.index !7 + %call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !32 + ret void, !dbg !33 +} + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon*, i32) #1 + +; Function Attrs: nounwind +define dso_local void @prog2() local_unnamed_addr #0 !dbg !34 { +entry: + %0 = tail call i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon* bitcast ({ <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc to %struct.anon*), i32 0), !dbg !35, !llvm.preserve.access.index !6 + %call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !36 + ret void, !dbg !37 +} + +; Function Attrs: nounwind +define dso_local void @prog3() local_unnamed_addr #0 !dbg !38 { +entry: + %0 = tail call i32 @llvm.bpf.btf.type.id.p0i8.i32(i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 2, i64 1), i32 1), !dbg !39, !llvm.preserve.access.index !11 + %call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !40 + ret void, !dbg !41 +} + +; CHECK-LABEL: prog1 +; CHECK: r1 = 3 +; CHECK-LABEL: prog2 +; CHECK: r1 = 10 +; CHECK-LABEL: prog3 +; CHECK: r1 = 4 +; +; CHECK: .long 0 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 13 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 800 # 0x320 +; CHECK-NEXT: .long 19 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK: .long 0 # BTF_KIND_PTR(id = 10) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 3 +; +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long {{[0-9]+}} # Field reloc section string offset={{[0-9]+}} +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.btf.type.id.p0i8.i32(i8*, i32) #1 + +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 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!24, !25, !26} +!llvm.ident = !{!27} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "tmp__abc", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 189ae9d45901971ef2fda7599be9e32eb37d89ad)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !16, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/log") +!4 = !{} +!5 = !{!6, !11} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 2, size: 832, elements: !8) +!8 = !{!9, !14} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !7, file: !3, line: 3, baseType: !10, size: 800) +!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 800, elements: !12) +!11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!12 = !{!13} +!13 = !DISubrange(count: 100) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !7, file: !3, line: 4, baseType: !15, size: 32, offset: 800) +!15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!16 = !{!0, !17} +!17 = !DIGlobalVariableExpression(var: !18, expr: !DIExpression()) +!18 = distinct !DIGlobalVariable(name: "bpf_log", scope: !2, file: !3, line: 1, type: !19, isLocal: true, isDefinition: true) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = !DISubroutineType(types: !21) +!21 = !{!15, !22, !23, !15} +!22 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!24 = !{i32 7, !"Dwarf Version", i32 4} +!25 = !{i32 2, !"Debug Info Version", i32 3} +!26 = !{i32 1, !"wchar_size", i32 4} +!27 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 189ae9d45901971ef2fda7599be9e32eb37d89ad)"} +!28 = distinct !DISubprogram(name: "prog1", scope: !3, file: !3, line: 6, type: !29, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!29 = !DISubroutineType(types: !30) +!30 = !{null} +!31 = !DILocation(line: 7, column: 11, scope: !28) +!32 = !DILocation(line: 7, column: 3, scope: !28) +!33 = !DILocation(line: 8, column: 1, scope: !28) +!34 = distinct !DISubprogram(name: "prog2", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!35 = !DILocation(line: 10, column: 11, scope: !34) +!36 = !DILocation(line: 10, column: 3, scope: !34) +!37 = !DILocation(line: 11, column: 1, scope: !34) +!38 = distinct !DISubprogram(name: "prog3", scope: !3, file: !3, line: 12, type: !29, scopeLine: 12, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!39 = !DILocation(line: 13, column: 11, scope: !38) +!40 = !DILocation(line: 13, column: 3, scope: !38) +!41 = !DILocation(line: 14, column: 1, scope: !38)