| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| //===- BPFCORE.h - Common info for Compile-Once Run-EveryWhere -*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_BPF_BPFCORE_H | ||
| #define LLVM_LIB_TARGET_BPF_BPFCORE_H | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class BPFCoreSharedInfo { | ||
| public: | ||
| /// The attribute attached to globals representing a member offset | ||
| static const std::string AmaAttr; | ||
| /// The section name to identify a patchable external global | ||
| static const std::string PatchableExtSecName; | ||
| }; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| //===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This pass targets a subset of instructions like below | ||
| // ld_imm64 r1, @global | ||
| // ldd r2, r1, 0 | ||
| // add r3, struct_base_reg, r2 | ||
| // | ||
| // Here @global should either present a AMA (abstruct member access) or | ||
| // a patchable extern variable. And these two kinds of accesses | ||
| // are subject to bpf load time patching. After this pass, the | ||
| // code becomes | ||
| // ld_imm64 r1, @global | ||
| // add r3, struct_base_reg, r1 | ||
| // | ||
| // Eventually, at BTF output stage, a relocation record will be generated | ||
| // for ld_imm64 which should be replaced later by bpf loader: | ||
| // r1 = <calculated offset> or <to_be_patched_extern_val> | ||
| // add r3, struct_base_reg, r1 | ||
| // or | ||
| // ld_imm64 r1, <to_be_patched_extern_val> | ||
| // add r3, struct_base_reg, r1 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "BPF.h" | ||
| #include "BPFCORE.h" | ||
| #include "BPFInstrInfo.h" | ||
| #include "BPFTargetMachine.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "bpf-mi-simplify-patchable" | ||
|
|
||
| namespace { | ||
|
|
||
| struct BPFMISimplifyPatchable : public MachineFunctionPass { | ||
|
|
||
| static char ID; | ||
| const BPFInstrInfo *TII; | ||
| MachineFunction *MF; | ||
|
|
||
| BPFMISimplifyPatchable() : MachineFunctionPass(ID) { | ||
| initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry()); | ||
| } | ||
|
|
||
| private: | ||
| // Initialize class variables. | ||
| void initialize(MachineFunction &MFParm); | ||
|
|
||
| bool removeLD(void); | ||
|
|
||
| public: | ||
| // Main entry point for this pass. | ||
| bool runOnMachineFunction(MachineFunction &MF) override { | ||
| if (!skipFunction(MF.getFunction())) { | ||
| initialize(MF); | ||
| } | ||
| return removeLD(); | ||
| } | ||
| }; | ||
|
|
||
| // Initialize class variables. | ||
| void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) { | ||
| MF = &MFParm; | ||
| TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); | ||
| LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n"); | ||
| } | ||
|
|
||
| /// Remove unneeded Load instructions. | ||
| bool BPFMISimplifyPatchable::removeLD() { | ||
| MachineRegisterInfo *MRI = &MF->getRegInfo(); | ||
| MachineInstr *ToErase = nullptr; | ||
| bool Changed = false; | ||
|
|
||
| for (MachineBasicBlock &MBB : *MF) { | ||
| for (MachineInstr &MI : MBB) { | ||
| if (ToErase) { | ||
| ToErase->eraseFromParent(); | ||
| ToErase = nullptr; | ||
| } | ||
|
|
||
| // Ensure the register format is LOAD <reg>, <reg>, 0 | ||
| if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW && | ||
| MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB && | ||
| MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 && | ||
| MI.getOpcode() != BPF::LDB32) | ||
| continue; | ||
|
|
||
| if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) | ||
| continue; | ||
|
|
||
| if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) | ||
| continue; | ||
|
|
||
| unsigned DstReg = MI.getOperand(0).getReg(); | ||
| unsigned SrcReg = MI.getOperand(1).getReg(); | ||
| int64_t ImmVal = MI.getOperand(2).getImm(); | ||
|
|
||
| MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); | ||
| if (!DefInst) | ||
| continue; | ||
|
|
||
| bool IsCandidate = false; | ||
| if (DefInst->getOpcode() == BPF::LD_imm64) { | ||
| const MachineOperand &MO = DefInst->getOperand(1); | ||
| if (MO.isGlobal()) { | ||
| const GlobalValue *GVal = MO.getGlobal(); | ||
| auto *GVar = dyn_cast<GlobalVariable>(GVal); | ||
| if (GVar) { | ||
| // Global variables representing structure offset or | ||
| // patchable extern globals. | ||
| if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { | ||
| assert(ImmVal == 0); | ||
| IsCandidate = true; | ||
| } else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() && | ||
| GVar->getSection() == | ||
| BPFCoreSharedInfo::PatchableExtSecName) { | ||
| if (ImmVal == 0) | ||
| IsCandidate = true; | ||
| else | ||
| errs() << "WARNING: unhandled patchable extern " | ||
| << GVar->getName() << " with load offset " << ImmVal | ||
| << "\n"; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (!IsCandidate) | ||
| continue; | ||
|
|
||
| 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); | ||
| I->setReg(SrcReg); | ||
| } | ||
|
|
||
| ToErase = &MI; | ||
| Changed = true; | ||
| } | ||
| } | ||
|
|
||
| return Changed; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE, | ||
| "BPF PreEmit SimplifyPatchable", false, false) | ||
|
|
||
| char BPFMISimplifyPatchable::ID = 0; | ||
| FunctionPass *llvm::createBPFMISimplifyPatchablePass() { | ||
| return new BPFMISimplifyPatchable(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| ; 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 key_type { | ||
| ; int a; | ||
| ; int b; | ||
| ; }; | ||
| ; struct map_type { | ||
| ; struct key_type *key; | ||
| ; unsigned *value; | ||
| ; }; | ||
| ; struct map_type __attribute__((section(".maps"))) hash_map; | ||
| ; Compilation flag: | ||
| ; clang -target bpf -O2 -g -S -emit-llvm t.c | ||
|
|
||
| %struct.map_type = type { %struct.key_type*, i32* } | ||
| %struct.key_type = type { i32, i32 } | ||
|
|
||
| @hash_map = dso_local local_unnamed_addr global %struct.map_type zeroinitializer, section ".maps", align 8, !dbg !0 | ||
|
|
||
| ; CHECK: .section .BTF,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 168 | ||
| ; CHECK-NEXT: .long 168 | ||
| ; CHECK-NEXT: .long 65 | ||
| ; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) | ||
| ; CHECK-NEXT: .long 67108866 # 0x4000002 | ||
| ; CHECK-NEXT: .long 16 | ||
| ; CHECK-NEXT: .long 10 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 14 | ||
| ; CHECK-NEXT: .long 5 | ||
| ; CHECK-NEXT: .long 64 # 0x40 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 20 # BTF_KIND_STRUCT(id = 3) | ||
| ; CHECK-NEXT: .long 67108866 # 0x4000002 | ||
| ; CHECK-NEXT: .long 8 | ||
| ; CHECK-NEXT: .long 29 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 31 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 32 # 0x20 | ||
| ; CHECK-NEXT: .long 33 # BTF_KIND_INT(id = 4) | ||
| ; CHECK-NEXT: .long 16777216 # 0x1000000 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 16777248 # 0x1000020 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 5) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 6 | ||
| ; CHECK-NEXT: .long 37 # BTF_KIND_INT(id = 6) | ||
| ; CHECK-NEXT: .long 16777216 # 0x1000000 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 32 # 0x20 | ||
| ; CHECK-NEXT: .long 50 # BTF_KIND_VAR(id = 7) | ||
| ; CHECK-NEXT: .long 234881024 # 0xe000000 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 59 # BTF_KIND_DATASEC(id = 8) | ||
| ; CHECK-NEXT: .long 251658241 # 0xf000001 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 7 | ||
| ; CHECK-NEXT: .long hash_map | ||
| ; CHECK-NEXT: .long 16 | ||
| ; CHECK-NEXT: .byte 0 # string offset=0 | ||
| ; CHECK-NEXT: .ascii "map_type" # string offset=1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "key" # string offset=10 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "value" # string offset=14 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "key_type" # string offset=20 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 97 # string offset=29 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 98 # string offset=31 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "int" # string offset=33 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "unsigned int" # string offset=37 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "hash_map" # string offset=50 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii ".maps" # string offset=59 | ||
| ; CHECK-NEXT: .byte 0 | ||
|
|
||
| !llvm.dbg.cu = !{!2} | ||
| !llvm.module.flags = !{!18, !19, !20} | ||
| !llvm.ident = !{!21} | ||
|
|
||
| !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) | ||
| !1 = distinct !DIGlobalVariable(name: "hash_map", scope: !2, file: !3, line: 9, type: !6, isLocal: false, isDefinition: true) | ||
| !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) | ||
| !3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm") | ||
| !4 = !{} | ||
| !5 = !{!0} | ||
| !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_type", file: !3, line: 5, size: 128, elements: !7) | ||
| !7 = !{!8, !15} | ||
| !8 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !6, file: !3, line: 6, baseType: !9, size: 64) | ||
| !9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) | ||
| !10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "key_type", file: !3, line: 1, size: 64, elements: !11) | ||
| !11 = !{!12, !14} | ||
| !12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32) | ||
| !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | ||
| !14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !3, line: 3, baseType: !13, size: 32, offset: 32) | ||
| !15 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !3, line: 7, baseType: !16, size: 64, offset: 64) | ||
| !16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) | ||
| !17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) | ||
| !18 = !{i32 2, !"Dwarf Version", i32 4} | ||
| !19 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !20 = !{i32 1, !"wchar_size", i32 4} | ||
| !21 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| ; 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 t { | ||
| ; int a; | ||
| ; }; | ||
| ; struct t2 { | ||
| ; struct t *f1; | ||
| ; }; | ||
| ; struct t2 __attribute__((section("prune_types"))) g; | ||
| ; Compilation flag: | ||
| ; clang -target bpf -O2 -g -S -emit-llvm t.c | ||
|
|
||
| %struct.t2 = type { %struct.t* } | ||
| %struct.t = type { i32 } | ||
|
|
||
| @g = dso_local local_unnamed_addr global %struct.t2 zeroinitializer, section "prune_types", align 8, !dbg !0 | ||
|
|
||
| ; CHECK: .section .BTF,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 88 | ||
| ; CHECK-NEXT: .long 88 | ||
| ; CHECK-NEXT: .long 23 | ||
| ; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) | ||
| ; CHECK-NEXT: .long 67108865 # 0x4000001 | ||
| ; CHECK-NEXT: .long 8 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 5 | ||
| ; CHECK-NEXT: .long 7 # BTF_KIND_VAR(id = 3) | ||
| ; CHECK-NEXT: .long 234881024 # 0xe000000 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 9 # BTF_KIND_DATASEC(id = 4) | ||
| ; CHECK-NEXT: .long 251658241 # 0xf000001 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long g | ||
| ; CHECK-NEXT: .long 8 | ||
| ; CHECK-NEXT: .long 21 # BTF_KIND_FWD(id = 5) | ||
| ; CHECK-NEXT: .long 117440512 # 0x7000000 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .byte 0 # string offset=0 | ||
| ; CHECK-NEXT: .ascii "t2" # string offset=1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "f1" # string offset=4 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 103 # string offset=7 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "prune_types" # string offset=9 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 116 # string offset=21 | ||
| ; CHECK-NEXT: .byte 0 | ||
|
|
||
| !llvm.dbg.cu = !{!2} | ||
| !llvm.module.flags = !{!14, !15, !16} | ||
| !llvm.ident = !{!17} | ||
|
|
||
| !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) | ||
| !1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) | ||
| !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) | ||
| !3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm") | ||
| !4 = !{} | ||
| !5 = !{!0} | ||
| !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 4, size: 64, elements: !7) | ||
| !7 = !{!8} | ||
| !8 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !6, file: !3, line: 5, baseType: !9, size: 64) | ||
| !9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) | ||
| !10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !3, line: 1, size: 32, elements: !11) | ||
| !11 = !{!12} | ||
| !12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32) | ||
| !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | ||
| !14 = !{i32 2, !"Dwarf Version", i32 4} | ||
| !15 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !16 = !{i32 1, !"wchar_size", i32 4} | ||
| !17 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| ; 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 sk_buff { | ||
| ; int i; | ||
| ; struct net_device *dev; | ||
| ; }; | ||
| ; #define _(x) (__builtin_preserve_access_index(x)) | ||
| ; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) | ||
| ; = (void *) 4; | ||
| ; | ||
| ; int bpf_prog(struct sk_buff *ctx) { | ||
| ; struct net_device *dev = 0; | ||
| ; bpf_probe_read(&dev, sizeof(dev), _(&ctx->dev)); | ||
| ; return dev != 0; | ||
| ; } | ||
| ; Compilation flag: | ||
| ; clang -target bpf -O2 -g -S -emit-llvm test.c | ||
|
|
||
| %struct.sk_buff = type { i32, %struct.net_device* } | ||
| %struct.net_device = type opaque | ||
|
|
||
| ; Function Attrs: nounwind | ||
| define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { | ||
| %2 = alloca %struct.net_device*, align 8 | ||
| call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !26, metadata !DIExpression()), !dbg !28 | ||
| %3 = bitcast %struct.net_device** %2 to i8*, !dbg !29 | ||
| call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %3) #4, !dbg !29 | ||
| call void @llvm.dbg.value(metadata %struct.net_device* null, metadata !27, metadata !DIExpression()), !dbg !28 | ||
| store %struct.net_device* null, %struct.net_device** %2, align 8, !dbg !30, !tbaa !31 | ||
| %4 = tail call %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19 | ||
| %5 = bitcast %struct.net_device** %4 to i8*, !dbg !35 | ||
| %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 8, i8* %5) #4, !dbg !36 | ||
| %7 = load %struct.net_device*, %struct.net_device** %2, align 8, !dbg !37, !tbaa !31 | ||
| call void @llvm.dbg.value(metadata %struct.net_device* %7, metadata !27, metadata !DIExpression()), !dbg !28 | ||
| %8 = icmp ne %struct.net_device* %7, null, !dbg !38 | ||
| %9 = zext i1 %8 to i32, !dbg !38 | ||
| call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %3) #4, !dbg !39 | ||
| ret i32 %9, !dbg !40 | ||
| } | ||
|
|
||
| ; CHECK: .section .BTF,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 120 | ||
| ; CHECK-NEXT: .long 120 | ||
| ; CHECK-NEXT: .long 90 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) | ||
| ; CHECK-NEXT: .long 67108866 # 0x4000002 | ||
| ; CHECK-NEXT: .long 16 | ||
| ; CHECK-NEXT: .long 9 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 11 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 64 # 0x40 | ||
| ; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) | ||
| ; CHECK-NEXT: .long 16777216 # 0x1000000 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 16777248 # 0x1000020 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 5 | ||
| ; CHECK-NEXT: .long 19 # BTF_KIND_FWD(id = 5) | ||
| ; CHECK-NEXT: .long 117440512 # 0x7000000 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) | ||
| ; CHECK-NEXT: .long 218103809 # 0xd000001 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 30 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 34 # BTF_KIND_FUNC(id = 7) | ||
| ; CHECK-NEXT: .long 201326592 # 0xc000000 | ||
| ; CHECK-NEXT: .long 6 | ||
| ; CHECK-NEXT: .byte 0 # string offset=0 | ||
| ; CHECK-NEXT: .ascii "sk_buff" # string offset=1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 105 # string offset=9 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "dev" # string offset=11 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "int" # string offset=15 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "net_device" # string offset=19 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "ctx" # string offset=30 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "bpf_prog" # string offset=34 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii ".text" # string offset=43 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=49 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "0:1" # string offset=86 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .section .BTF.ext,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 40 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 20 | ||
| ; CHECK-NEXT: .long 20 | ||
| ; CHECK-NEXT: .long 124 | ||
| ; CHECK-NEXT: .long 144 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 168 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 8 # FuncInfo | ||
|
|
||
| ; CHECK: .long 12 # OffsetReloc | ||
| ; CHECK-NEXT: .long 43 # Offset reloc section string offset=43 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long .Ltmp2 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 86 | ||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 | ||
|
|
||
| ; Function Attrs: nounwind readnone | ||
| declare %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 | ||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 | ||
|
|
||
| ; Function Attrs: nounwind readnone speculatable | ||
| declare void @llvm.dbg.value(metadata, metadata, metadata) #3 | ||
|
|
||
| attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } | ||
| attributes #2 = { nounwind readnone } | ||
| attributes #3 = { nounwind readnone speculatable } | ||
| attributes #4 = { nounwind } | ||
|
|
||
| !llvm.dbg.cu = !{!0} | ||
| !llvm.module.flags = !{!11, !12, !13} | ||
| !llvm.ident = !{!14} | ||
|
|
||
| !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) | ||
| !1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") | ||
| !2 = !{} | ||
| !3 = !{!4} | ||
| !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) | ||
| !5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 6, type: !6, isLocal: true, isDefinition: true) | ||
| !6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) | ||
| !7 = !DISubroutineType(types: !8) | ||
| !8 = !{!9, !10, !9, !10} | ||
| !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | ||
| !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) | ||
| !11 = !{i32 2, !"Dwarf Version", i32 4} | ||
| !12 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !13 = !{i32 1, !"wchar_size", i32 4} | ||
| !14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} | ||
| !15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 9, type: !16, scopeLine: 9, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !25) | ||
| !16 = !DISubroutineType(types: !17) | ||
| !17 = !{!9, !18} | ||
| !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) | ||
| !19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 128, elements: !20) | ||
| !20 = !{!21, !22} | ||
| !21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) | ||
| !22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 3, baseType: !23, size: 64, offset: 64) | ||
| !23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) | ||
| !24 = !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 3, flags: DIFlagFwdDecl) | ||
| !25 = !{!26, !27} | ||
| !26 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 9, type: !18) | ||
| !27 = !DILocalVariable(name: "dev", scope: !15, file: !1, line: 10, type: !23) | ||
| !28 = !DILocation(line: 0, scope: !15) | ||
| !29 = !DILocation(line: 10, column: 3, scope: !15) | ||
| !30 = !DILocation(line: 10, column: 22, scope: !15) | ||
| !31 = !{!32, !32, i64 0} | ||
| !32 = !{!"any pointer", !33, i64 0} | ||
| !33 = !{!"omnipotent char", !34, i64 0} | ||
| !34 = !{!"Simple C/C++ TBAA"} | ||
| !35 = !DILocation(line: 11, column: 37, scope: !15) | ||
| !36 = !DILocation(line: 11, column: 3, scope: !15) | ||
| !37 = !DILocation(line: 12, column: 10, scope: !15) | ||
| !38 = !DILocation(line: 12, column: 14, scope: !15) | ||
| !39 = !DILocation(line: 13, column: 1, scope: !15) | ||
| !40 = !DILocation(line: 12, column: 3, scope: !15) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,197 @@ | ||
| ; 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 net_device { | ||
| ; int dev_id; | ||
| ; int others; | ||
| ; }; | ||
| ; struct sk_buff { | ||
| ; int i; | ||
| ; struct net_device dev; | ||
| ; }; | ||
| ; #define _(x) (__builtin_preserve_access_index(x)) | ||
| ; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) | ||
| ; = (void *) 4; | ||
| ; | ||
| ; int bpf_prog(struct sk_buff *ctx) { | ||
| ; int dev_id; | ||
| ; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev.dev_id)); | ||
| ; return dev_id; | ||
| ; } | ||
| ; Compilation flag: | ||
| ; clang -target bpf -O2 -g -S -emit-llvm test.c | ||
|
|
||
| %struct.sk_buff = type { i32, %struct.net_device } | ||
| %struct.net_device = type { i32, i32 } | ||
|
|
||
| ; Function Attrs: nounwind | ||
| define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { | ||
| %2 = alloca i32, align 4 | ||
| call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !28, metadata !DIExpression()), !dbg !30 | ||
| %3 = bitcast i32* %2 to i8*, !dbg !31 | ||
| call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !31 | ||
| %4 = tail call %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* %0, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !19 | ||
| %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* %4, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !23 | ||
| %6 = bitcast i32* %5 to i8*, !dbg !32 | ||
| %7 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %6) #4, !dbg !33 | ||
| %8 = load i32, i32* %2, align 4, !dbg !34, !tbaa !35 | ||
| call void @llvm.dbg.value(metadata i32 %8, metadata !29, metadata !DIExpression()), !dbg !30 | ||
| call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !39 | ||
| ret i32 %8, !dbg !40 | ||
| } | ||
|
|
||
| ; CHECK: .section .BTF,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 132 | ||
| ; CHECK-NEXT: .long 132 | ||
| ; CHECK-NEXT: .long 106 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) | ||
| ; CHECK-NEXT: .long 33554432 # 0x2000000 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) | ||
| ; CHECK-NEXT: .long 67108866 # 0x4000002 | ||
| ; CHECK-NEXT: .long 12 | ||
| ; CHECK-NEXT: .long 9 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 11 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 32 # 0x20 | ||
| ; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) | ||
| ; CHECK-NEXT: .long 16777216 # 0x1000000 | ||
| ; CHECK-NEXT: .long 4 | ||
| ; CHECK-NEXT: .long 16777248 # 0x1000020 | ||
| ; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4) | ||
| ; CHECK-NEXT: .long 67108866 # 0x4000002 | ||
| ; CHECK-NEXT: .long 8 | ||
| ; CHECK-NEXT: .long 30 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 0 # 0x0 | ||
| ; CHECK-NEXT: .long 37 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 32 # 0x20 | ||
| ; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 5) | ||
| ; CHECK-NEXT: .long 218103809 # 0xd000001 | ||
| ; CHECK-NEXT: .long 3 | ||
| ; CHECK-NEXT: .long 44 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 6) | ||
| ; CHECK-NEXT: .long 201326592 # 0xc000000 | ||
| ; CHECK-NEXT: .long 5 | ||
| ; CHECK-NEXT: .byte 0 # string offset=0 | ||
| ; CHECK-NEXT: .ascii "sk_buff" # string offset=1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .byte 105 # string offset=9 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "dev" # string offset=11 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "int" # string offset=15 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "net_device" # string offset=19 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "dev_id" # string offset=30 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "others" # string offset=37 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "ctx" # string offset=44 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "bpf_prog" # string offset=48 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii ".text" # string offset=57 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=63 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .ascii "0:1:0" # string offset=100 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .section .BTF.ext,"",@progbits | ||
| ; CHECK-NEXT: .short 60319 # 0xeb9f | ||
| ; CHECK-NEXT: .byte 1 | ||
| ; CHECK-NEXT: .byte 0 | ||
| ; CHECK-NEXT: .long 40 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 20 | ||
| ; CHECK-NEXT: .long 20 | ||
| ; CHECK-NEXT: .long 76 | ||
| ; CHECK-NEXT: .long 96 | ||
| ; CHECK-NEXT: .long 24 | ||
| ; CHECK-NEXT: .long 120 | ||
| ; CHECK-NEXT: .long 0 | ||
| ; CHECK-NEXT: .long 8 # FuncInfo | ||
|
|
||
| ; CHECK: .long 12 # OffsetReloc | ||
| ; CHECK-NEXT: .long 57 # Offset reloc section string offset=57 | ||
| ; CHECK-NEXT: .long 1 | ||
| ; CHECK-NEXT: .long .Ltmp2 | ||
| ; CHECK-NEXT: .long 2 | ||
| ; CHECK-NEXT: .long 100 | ||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 | ||
|
|
||
| ; Function Attrs: nounwind readnone | ||
| declare %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 | ||
|
|
||
| ; Function Attrs: nounwind readnone | ||
| declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device*, i32 immarg, i32 immarg) #2 | ||
|
|
||
| ; Function Attrs: argmemonly nounwind | ||
| declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 | ||
|
|
||
| ; Function Attrs: nounwind readnone speculatable | ||
| declare void @llvm.dbg.value(metadata, metadata, metadata) #3 | ||
|
|
||
| attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = { argmemonly nounwind } | ||
| attributes #2 = { nounwind readnone } | ||
| attributes #3 = { nounwind readnone speculatable } | ||
| attributes #4 = { nounwind } | ||
|
|
||
| !llvm.dbg.cu = !{!0} | ||
| !llvm.module.flags = !{!11, !12, !13} | ||
| !llvm.ident = !{!14} | ||
|
|
||
| !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) | ||
| !1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") | ||
| !2 = !{} | ||
| !3 = !{!4} | ||
| !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) | ||
| !5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true) | ||
| !6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) | ||
| !7 = !DISubroutineType(types: !8) | ||
| !8 = !{!9, !10, !9, !10} | ||
| !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | ||
| !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) | ||
| !11 = !{i32 2, !"Dwarf Version", i32 4} | ||
| !12 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !13 = !{i32 1, !"wchar_size", i32 4} | ||
| !14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} | ||
| !15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) | ||
| !16 = !DISubroutineType(types: !17) | ||
| !17 = !{!9, !18} | ||
| !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) | ||
| !19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 96, elements: !20) | ||
| !20 = !{!21, !22} | ||
| !21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32) | ||
| !22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 64, offset: 32) | ||
| !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !24) | ||
| !24 = !{!25, !26} | ||
| !25 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !23, file: !1, line: 2, baseType: !9, size: 32) | ||
| !26 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !23, file: !1, line: 3, baseType: !9, size: 32, offset: 32) | ||
| !27 = !{!28, !29} | ||
| !28 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18) | ||
| !29 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9) | ||
| !30 = !DILocation(line: 0, scope: !15) | ||
| !31 = !DILocation(line: 14, column: 3, scope: !15) | ||
| !32 = !DILocation(line: 15, column: 40, scope: !15) | ||
| !33 = !DILocation(line: 15, column: 3, scope: !15) | ||
| !34 = !DILocation(line: 16, column: 10, scope: !15) | ||
| !35 = !{!36, !36, i64 0} | ||
| !36 = !{!"int", !37, i64 0} | ||
| !37 = !{!"omnipotent char", !38, i64 0} | ||
| !38 = !{!"Simple C/C++ TBAA"} | ||
| !39 = !DILocation(line: 17, column: 1, scope: !15) | ||
| !40 = !DILocation(line: 16, column: 3, scope: !15) |