yonghong-song updated this revision to Diff 223405. yonghong-song retitled this revision from "[WIP][CLANG][BPF] do compile-once run-everywhere relocation for bitfields" to "[CLANG][BPF] do compile-once run-everywhere relocation for bitfields". yonghong-song edited the summary of this revision. yonghong-song added a comment.
fixed a few bugs from previous revision. Removed FIELD_ACCESS_OFFSET relocation which will be identical to FIELD_BYTE_OFFSET. All of these CORE related test cases are adjusted and passed now. Removed [WIP] prefix. TODO: write new tests for the new functionality. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D67980/new/ https://reviews.llvm.org/D67980 Files: clang/include/clang/Basic/BuiltinsBPF.def clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/TargetBuiltins.h clang/include/clang/Sema/Sema.h clang/include/clang/module.modulemap clang/lib/Basic/Targets/BPF.cpp clang/lib/Basic/Targets/BPF.h clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Sema/SemaChecking.cpp llvm/include/llvm/IR/IntrinsicsBPF.td llvm/lib/Target/BPF/BPF.h llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp llvm/lib/Target/BPF/BPFCORE.h llvm/lib/Target/BPF/BPFTargetMachine.cpp llvm/lib/Target/BPF/BTF.h llvm/lib/Target/BPF/BTFDebug.cpp llvm/lib/Target/BPF/BTFDebug.h llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll
Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-union.ll @@ -133,17 +133,18 @@ ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 76 ; CHECK-NEXT: .long 96 -; CHECK-NEXT: .long 24 -; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 54 # Offset reloc section string offset=54 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 54 # Field reloc section string offset=54 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp2 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 97 +; CHECK-NEXT: .long 0 ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll @@ -45,12 +45,13 @@ ; CHECK-NEXT: .byte 0 ; CHECK: .ascii "1:1:1" # string offset=[[ACCESS_STR:[0-9]+]] ; CHECK-NEXT: .byte 0 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Offset reloc section string offset=[[SEC_STR:[0-9]+]] +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Field reloc section string offset=[[SEC_STR:[0-9]+]] ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC:.Ltmp[0-9]+]] ; CHECK-NEXT: .long [[TYPE_ID:[0-9]+]] ; CHECK-NEXT: .long [[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll @@ -37,12 +37,13 @@ ; CHECK-NEXT: .byte 0 ; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] ; CHECK-NEXT: .byte 0 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long [[TYPE_ID]] ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll @@ -37,12 +37,13 @@ ; CHECK-NEXT: .byte 0 ; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] ; CHECK-NEXT: .byte 0 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset={{[0-9]+}} +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset={{[0-9]+}} ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long [[TYPE_ID]] ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll @@ -38,12 +38,13 @@ ; CHECK-NEXT: .byte 0 ; CHECK: .ascii "0:0:1" # string offset=[[ACCESS_STR:[0-9]+]] ; CHECK-NEXT: .byte 0 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long [[TYPE_ID]] ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-array.ll @@ -130,17 +130,18 @@ ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 76 ; CHECK-NEXT: .long 96 -; CHECK-NEXT: .long 24 -; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 77 # Offset reloc section string offset=77 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 77 # Field reloc section string offset=77 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp2 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 0 ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-struct-anonymous.ll @@ -127,17 +127,18 @@ ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 76 ; CHECK-NEXT: .long 96 -; CHECK-NEXT: .long 24 -; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 66 # Offset reloc section string offset=66 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 66 # Field reloc section string offset=66 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp2 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 109 +; CHECK-NEXT: .long 0 ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-2.ll @@ -31,12 +31,13 @@ ; CHECK: .ascii ".text" # string offset=26 ; CHECK: .ascii "1:1" # string offset=32 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 26 # Offset reloc section string offset=26 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 26 # Field reloc section string offset=26 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-pointer-1.ll @@ -32,12 +32,13 @@ ; CHECK: .ascii ".text" # string offset=26 ; CHECK: .byte 49 # string offset=32 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 26 # Offset reloc section string offset=26 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 26 # Field reloc section string offset=26 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-multilevel.ll @@ -117,17 +117,18 @@ ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 76 ; CHECK-NEXT: .long 96 -; CHECK-NEXT: .long 24 -; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 124 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 57 # Offset reloc section string offset=57 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp2 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 100 +; CHECK-NEXT: .long 0 ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-2.ll @@ -36,12 +36,13 @@ ; CHECK: .ascii ".text" # string offset=52 ; CHECK: .ascii "1:1:2:3:2" # string offset=58 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 52 # Offset reloc section string offset=52 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 52 # Field reloc section string offset=52 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 58 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-multi-array-1.ll @@ -35,12 +35,13 @@ ; CHECK: .ascii ".text" # string offset=52 ; CHECK: .ascii "1:1:2:3" # string offset=58 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 52 # Offset reloc section string offset=52 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 52 # Field reloc section string offset=52 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 58 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-middle-chain.ll @@ -50,18 +50,21 @@ ; 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: .long 16 # FieldReloc +; CHECK-NEXT: .long 29 # Field 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 0 ; CHECK_NEXT: .long .Ltmp{{[0-9]+}} ; CHECK_NEXT: .long 2 ; CHECK_NEXT: .long 76 +; CHECK_NEXT: .long 0 ; CHECK_NEXT: .long .Ltmp{{[0-9]+}} ; CHECK_NEXT: .long 2 ; CHECK_NEXT: .long 82 +; CHECK_NEXT: .long 0 ; Function Attrs: nounwind readnone declare %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1*, i32, i32) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-ignore.ll @@ -21,7 +21,7 @@ ; CHECK: r1 += 16 ; CHECK: call get_value ; CHECK: .section .BTF.ext,"",@progbits -; CHECK-NOT: .long 12 # OffsetReloc +; CHECK-NOT: .long 16 # FieldReloc declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-global-3.ll @@ -34,12 +34,13 @@ ; CHECK: .ascii "v3" # string offset=16 ; CHECK: .ascii "0:1" # string offset=23 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 10 # Offset reloc section string offset=10 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-global-2.ll @@ -36,12 +36,13 @@ ; CHECK: .ascii "v3" # string offset=16 ; CHECK: .ascii "7:1" # string offset=23 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 10 # Offset reloc section string offset=10 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-global-1.ll @@ -34,12 +34,13 @@ ; CHECK: .ascii "v3" # string offset=16 ; CHECK: .ascii "0:1" # string offset=23 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 10 # Offset reloc section string offset=10 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-end-ret.ll @@ -30,12 +30,13 @@ ; CHECK: .ascii ".text" # string offset=20 ; CHECK: .ascii "0:1" # string offset=63 ; -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 20 # Offset reloc section string offset=20 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 ; Function Attrs: nounwind readnone declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-end-load.ll @@ -30,12 +30,13 @@ ; CHECK: .ascii ".text" # string offset=20 ; CHECK: .ascii "0:1" # string offset=26 ; -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 20 # Offset reloc section string offset=20 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 ; Function Attrs: nounwind readnone declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-2.ll @@ -47,15 +47,17 @@ ; CHECK: .ascii "v1" # string offset=111 ; CHECK: .ascii "0:1" # string offset=118 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 57 # Offset reloc section string offset=57 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 118 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-union-1.ll @@ -46,15 +46,17 @@ ; CHECK: .ascii "0:1" # string offset=45 ; CHECK: .ascii "v1" # string offset=91 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 39 # Offset reloc section string offset=39 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 39 # Field reloc section string offset=39 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-3.ll @@ -45,15 +45,17 @@ ; CHECK: .ascii "v1" # string offset=111 ; CHECK: .ascii "0:1" # string offset=118 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 57 # Offset reloc section string offset=57 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 118 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-2.ll @@ -46,15 +46,17 @@ ; CHECK: .ascii "v1" # string offset=91 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 39 # Offset reloc section string offset=39 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 39 # Field reloc section string offset=39 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-struct-1.ll @@ -46,15 +46,17 @@ ; CHECK: .ascii "v1" # string offset=81 ; CHECK-NEXT: .byte 0 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset=[[SEC_STR]] +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset=[[SEC_STR]] ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[V3_TID]] ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[V1_TID]] ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-2.ll @@ -47,15 +47,17 @@ ; CHECK: .ascii "v1" # string offset=100 ; CHECK: .ascii "11:1" # string offset=107 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 46 # Offset reloc section string offset=46 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 46 # Field reloc section string offset=46 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 107 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-cast-array-1.ll @@ -45,15 +45,17 @@ ; CHECK: .ascii "0:1:0" # string offset=52 ; CHECK: .ascii "2:1" # string offset=107 -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 46 # Offset reloc section string offset=46 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 46 # Field reloc section string offset=46 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID1]] ; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long [[TID2]] ; CHECK-NEXT: .long 107 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-basic.ll @@ -109,17 +109,18 @@ ; CHECK-NEXT: .long 20 ; CHECK-NEXT: .long 124 ; CHECK-NEXT: .long 144 -; CHECK-NEXT: .long 24 -; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 172 ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 8 # FuncInfo -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 43 # Offset reloc section string offset=43 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp2 ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 86 +; CHECK-NEXT: .long 0 ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 Index: llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll +++ llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll @@ -33,15 +33,17 @@ ; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] ; CHECK-NEXT: .byte 0 ; CHECK: .section .BTF.ext,"",@progbits -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long {{[0-9]+}} ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}} ; CHECK-NEXT: .long {{[0-9]+}} ; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*, i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll +++ llvm/test/CodeGen/BPF/CORE/intrinsic-union.ll @@ -27,12 +27,13 @@ ; CHECK: exit ; CHECK: .section .BTF.ext,"",@progbits -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 20 # Offset reloc section string offset=20 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll +++ llvm/test/CodeGen/BPF/CORE/intrinsic-struct.ll @@ -28,12 +28,13 @@ ; CHECK: exit ; ; CHECK: .section .BTF.ext,"",@progbits -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 20 # Offset reloc section string offset=20 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll =================================================================== --- llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll +++ llvm/test/CodeGen/BPF/CORE/intrinsic-array.ll @@ -28,12 +28,13 @@ ; CHECK: exit ; ; CHECK: .section .BTF.ext,"",@progbits -; CHECK: .long 12 # OffsetReloc -; CHECK-NEXT: .long 20 # Offset reloc section string offset=20 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long [[RELOC]] ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 Index: llvm/lib/Target/BPF/BTFDebug.h =================================================================== --- llvm/lib/Target/BPF/BTFDebug.h +++ llvm/lib/Target/BPF/BTFDebug.h @@ -195,7 +195,7 @@ /// A mapping from string table offset to the index /// of the Table. It is used to avoid putting /// duplicated strings in the table. - std::unordered_map<uint32_t, uint32_t> OffsetToIdMap; + std::map<uint32_t, uint32_t> OffsetToIdMap; /// A vector of strings to represent the string table. std::vector<std::string> Table; @@ -224,10 +224,11 @@ }; /// Represent one offset relocation. -struct BTFOffsetReloc { +struct BTFFieldReloc { const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc uint32_t TypeID; ///< Type ID uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t RelocKind; ///< What to patch the instruction }; /// Represent one extern relocation. @@ -249,12 +250,12 @@ std::unordered_map<const DIType *, uint32_t> DIToIdMap; std::map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable; std::map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable; - std::map<uint32_t, std::vector<BTFOffsetReloc>> OffsetRelocTable; + std::map<uint32_t, std::vector<BTFFieldReloc>> FieldRelocTable; std::map<uint32_t, std::vector<BTFExternReloc>> ExternRelocTable; StringMap<std::vector<std::string>> FileContent; std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries; std::vector<BTFTypeStruct *> StructTypes; - std::map<std::string, int64_t> AccessOffsets; + std::map<std::string, uint32_t> PatchImms; std::map<StringRef, std::pair<bool, std::vector<BTFTypeDerived *>>> FixupDerivedTypes; @@ -300,7 +301,7 @@ void processGlobals(bool ProcessingMapDef); /// Generate one offset relocation record. - void generateOffsetReloc(const MachineInstr *MI, const MCSymbol *ORSym, + void generateFieldReloc(const MachineInstr *MI, const MCSymbol *ORSym, DIType *RootTy, StringRef AccessPattern); /// Populating unprocessed struct type. Index: llvm/lib/Target/BPF/BTFDebug.cpp =================================================================== --- llvm/lib/Target/BPF/BTFDebug.cpp +++ llvm/lib/Target/BPF/BTFDebug.cpp @@ -754,7 +754,7 @@ void BTFDebug::emitBTFExtSection() { // Do not emit section if empty FuncInfoTable and LineInfoTable. if (!FuncInfoTable.size() && !LineInfoTable.size() && - !OffsetRelocTable.size() && !ExternRelocTable.size()) + !FieldRelocTable.size() && !ExternRelocTable.size()) return; MCContext &Ctx = OS.getContext(); @@ -766,8 +766,8 @@ // Account for FuncInfo/LineInfo record size as well. uint32_t FuncLen = 4, LineLen = 4; - // Do not account for optional OffsetReloc/ExternReloc. - uint32_t OffsetRelocLen = 0, ExternRelocLen = 0; + // Do not account for optional FieldReloc/ExternReloc. + uint32_t FieldRelocLen = 0, ExternRelocLen = 0; for (const auto &FuncSec : FuncInfoTable) { FuncLen += BTF::SecFuncInfoSize; FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize; @@ -776,17 +776,17 @@ LineLen += BTF::SecLineInfoSize; LineLen += LineSec.second.size() * BTF::BPFLineInfoSize; } - for (const auto &OffsetRelocSec : OffsetRelocTable) { - OffsetRelocLen += BTF::SecOffsetRelocSize; - OffsetRelocLen += OffsetRelocSec.second.size() * BTF::BPFOffsetRelocSize; + for (const auto &FieldRelocSec : FieldRelocTable) { + FieldRelocLen += BTF::SecFieldRelocSize; + FieldRelocLen += FieldRelocSec.second.size() * BTF::BPFFieldRelocSize; } for (const auto &ExternRelocSec : ExternRelocTable) { ExternRelocLen += BTF::SecExternRelocSize; ExternRelocLen += ExternRelocSec.second.size() * BTF::BPFExternRelocSize; } - if (OffsetRelocLen) - OffsetRelocLen += 4; + if (FieldRelocLen) + FieldRelocLen += 4; if (ExternRelocLen) ExternRelocLen += 4; @@ -795,8 +795,8 @@ OS.EmitIntValue(FuncLen, 4); OS.EmitIntValue(LineLen, 4); OS.EmitIntValue(FuncLen + LineLen, 4); - OS.EmitIntValue(OffsetRelocLen, 4); - OS.EmitIntValue(FuncLen + LineLen + OffsetRelocLen, 4); + OS.EmitIntValue(FieldRelocLen, 4); + OS.EmitIntValue(FuncLen + LineLen + FieldRelocLen, 4); OS.EmitIntValue(ExternRelocLen, 4); // Emit func_info table. @@ -831,19 +831,20 @@ } } - // Emit offset reloc table. - if (OffsetRelocLen) { - OS.AddComment("OffsetReloc"); - OS.EmitIntValue(BTF::BPFOffsetRelocSize, 4); - for (const auto &OffsetRelocSec : OffsetRelocTable) { - OS.AddComment("Offset reloc section string offset=" + - std::to_string(OffsetRelocSec.first)); - OS.EmitIntValue(OffsetRelocSec.first, 4); - OS.EmitIntValue(OffsetRelocSec.second.size(), 4); - for (const auto &OffsetRelocInfo : OffsetRelocSec.second) { - Asm->EmitLabelReference(OffsetRelocInfo.Label, 4); - OS.EmitIntValue(OffsetRelocInfo.TypeID, 4); - OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4); + // Emit field reloc table. + if (FieldRelocLen) { + OS.AddComment("FieldReloc"); + OS.EmitIntValue(BTF::BPFFieldRelocSize, 4); + for (const auto &FieldRelocSec : FieldRelocTable) { + OS.AddComment("Field reloc section string offset=" + + std::to_string(FieldRelocSec.first)); + OS.EmitIntValue(FieldRelocSec.first, 4); + OS.EmitIntValue(FieldRelocSec.second.size(), 4); + for (const auto &FieldRelocInfo : FieldRelocSec.second) { + Asm->EmitLabelReference(FieldRelocInfo.Label, 4); + OS.EmitIntValue(FieldRelocInfo.TypeID, 4); + OS.EmitIntValue(FieldRelocInfo.OffsetNameOff, 4); + OS.EmitIntValue(FieldRelocInfo.RelocKind, 4); } } } @@ -958,23 +959,27 @@ return Id; } -/// Generate a struct member offset relocation. -void BTFDebug::generateOffsetReloc(const MachineInstr *MI, +/// Generate a struct member field relocation. +void BTFDebug::generateFieldReloc(const MachineInstr *MI, 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 OffsetStr = AccessPattern.substr(FirstColon + 1, - FirstDollar - FirstColon); - - BTFOffsetReloc OffsetReloc; - OffsetReloc.Label = ORSym; - OffsetReloc.OffsetNameOff = addString(IndexPattern); - OffsetReloc.TypeID = RootId; - AccessOffsets[AccessPattern.str()] = std::stoi(OffsetStr); - OffsetRelocTable[SecNameOff].push_back(OffsetReloc); + StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1, + SecondColon - FirstColon); + StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1, + FirstDollar - SecondColon); + + BTFFieldReloc FieldReloc; + FieldReloc.Label = ORSym; + FieldReloc.OffsetNameOff = addString(IndexPattern); + FieldReloc.TypeID = RootId; + FieldReloc.RelocKind = std::stoull(RelocKindStr); + PatchImms[AccessPattern.str()] = std::stoul(PatchImmStr); + FieldRelocTable[SecNameOff].push_back(FieldReloc); } void BTFDebug::processLDimm64(const MachineInstr *MI) { @@ -982,7 +987,7 @@ // will generate an .BTF.ext record. // // If the insn is "r2 = LD_imm64 @__BTF_...", - // add this insn into the .BTF.ext OffsetReloc subsection. + // add this insn into the .BTF.ext FieldReloc subsection. // Relocation looks like: // . SecName: // . InstOffset @@ -1013,7 +1018,7 @@ MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index); DIType *Ty = dyn_cast<DIType>(MDN); - generateOffsetReloc(MI, ORSym, Ty, GVar->getName()); + generateFieldReloc(MI, ORSym, Ty, GVar->getName()); } else if (GVar && !GVar->hasInitializer() && GVar->hasExternalLinkage() && GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) { MCSymbol *ORSym = OS.getContext().createTempSymbol(); @@ -1154,8 +1159,8 @@ const GlobalValue *GVal = MO.getGlobal(); auto *GVar = dyn_cast<GlobalVariable>(GVal); if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) { - // Emit "mov ri, <imm>" for abstract member accesses. - int64_t Imm = AccessOffsets[GVar->getName().str()]; + // Emit "mov ri, <imm>" for patched immediate. + uint32_t Imm = PatchImms[GVar->getName().str()]; OutMI.setOpcode(BPF::MOV_ri); OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); OutMI.addOperand(MCOperand::createImm(Imm)); Index: llvm/lib/Target/BPF/BTF.h =================================================================== --- llvm/lib/Target/BPF/BTF.h +++ llvm/lib/Target/BPF/BTF.h @@ -17,7 +17,7 @@ /// /// The binary layout for .BTF.ext section: /// struct ExtHeader -/// FuncInfo, LineInfo, OffsetReloc and ExternReloc subsections +/// FuncInfo, LineInfo, FieldReloc and ExternReloc subsections /// The FuncInfo subsection is defined as below: /// BTFFuncInfo Size /// struct SecFuncInfo for ELF section #1 @@ -32,12 +32,12 @@ /// struct SecLineInfo for ELF section #2 /// A number of struct BPFLineInfo for ELF section #2 /// ... -/// The OffsetReloc subsection is defined as below: -/// BPFOffsetReloc Size -/// struct SecOffsetReloc for ELF section #1 -/// A number of struct BPFOffsetReloc for ELF section #1 -/// struct SecOffsetReloc for ELF section #2 -/// A number of struct BPFOffsetReloc for ELF section #2 +/// The FieldReloc subsection is defined as below: +/// BPFFieldReloc Size +/// struct SecFieldReloc for ELF section #1 +/// A number of struct BPFFieldReloc for ELF section #1 +/// struct SecFieldReloc for ELF section #2 +/// A number of struct BPFFieldReloc for ELF section #2 /// ... /// The ExternReloc subsection is defined as below: /// BPFExternReloc Size @@ -72,11 +72,11 @@ BTFDataSecVarSize = 12, SecFuncInfoSize = 8, SecLineInfoSize = 8, - SecOffsetRelocSize = 8, + SecFieldRelocSize = 8, SecExternRelocSize = 8, BPFFuncInfoSize = 8, BPFLineInfoSize = 16, - BPFOffsetRelocSize = 12, + BPFFieldRelocSize = 16, BPFExternRelocSize = 8, }; @@ -213,8 +213,8 @@ uint32_t FuncInfoLen; ///< Length of func info section uint32_t LineInfoOff; ///< Offset of line info section uint32_t LineInfoLen; ///< Length of line info section - uint32_t OffsetRelocOff; ///< Offset of offset reloc section - uint32_t OffsetRelocLen; ///< Length of offset reloc section + uint32_t FieldRelocOff; ///< Offset of offset reloc section + uint32_t FieldRelocLen; ///< Length of offset reloc section uint32_t ExternRelocOff; ///< Offset of extern reloc section uint32_t ExternRelocLen; ///< Length of extern reloc section }; @@ -247,16 +247,17 @@ }; /// Specifying one offset relocation. -struct BPFOffsetReloc { +struct BPFFieldReloc { uint32_t InsnOffset; ///< Byte offset in this section uint32_t TypeID; ///< TypeID for the relocation uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t RelocKind; ///< What to patch the instruction }; /// Specifying offset relocation's in one section. -struct SecOffsetReloc { +struct SecFieldReloc { uint32_t SecNameOff; ///< Section name index in the .BTF string table - uint32_t NumOffsetReloc; ///< Number of offset reloc's in this section + uint32_t NumFieldReloc; ///< Number of offset reloc's in this section }; /// Specifying one offset relocation. Index: llvm/lib/Target/BPF/BPFTargetMachine.cpp =================================================================== --- llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -94,7 +94,7 @@ void BPFPassConfig::addIRPasses() { - addPass(createBPFAbstractMemberAccess()); + addPass(createBPFAbstractMemberAccess(&getBPFTargetMachine())); TargetPassConfig::addIRPasses(); } Index: llvm/lib/Target/BPF/BPFCORE.h =================================================================== --- llvm/lib/Target/BPF/BPFCORE.h +++ llvm/lib/Target/BPF/BPFCORE.h @@ -13,6 +13,16 @@ class BPFCoreSharedInfo { public: + enum OffsetRelocKind : uint32_t { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE, + FIELD_EXISTENCE, + FIELD_SIGNEDNESS, + FIELD_LSHIFT_U64, + FIELD_RSHIFT_U64, + + MAX_FIELD_RELOC_KIND, + }; /// The attribute attached to globals representing a member offset static const std::string AmaAttr; /// The section name to identify a patchable external global Index: llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp =================================================================== --- llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp @@ -50,6 +50,28 @@ // addr = preserve_struct_access_index(base, gep_index, di_index) // !llvm.preserve.access.index <struct_ditype> // +// Bitfield member access needs special attention. User cannot take the +// address of a bitfield acceess. To facilitate kernel verifier +// for easy bitfield code optimization, a new clang intrinsic is introduced: +// uint32_t __builtin_preserve_field_info(member_access, info_kind) +// In IR, a chain with two (or more) intrinsic calls will be generated: +// ... +// addr = preserve_struct_access_index(base, 1, 1) !struct s +// uint32_t result = bpf_preserve_field_info(addr, info_kind) +// +// Suppose the info_kind is FIELD_SIGNEDNESS, +// The above two IR intrinsics will be replaced with +// a relocatable insn: +// signness = /* signness of member_access */ +// and signness can be changed by bpf loader based on the +// types on the host. +// +// User can also test whether a field exists or not with +// uint32_t result = bpf_preserve_field_info(member_access, FIELD_EXISTENCE) +// The field will be always available (result = 1) during initial +// compilation, but bpf loader can patch with the correct value +// on the target host where the member_access may or may not be available +// //===----------------------------------------------------------------------===// #include "BPF.h" @@ -88,7 +110,11 @@ public: static char ID; - BPFAbstractMemberAccess() : ModulePass(ID) {} + TargetMachine *TM; + // Add optional BPFTargetMachine parameter so that BPF backend can add the phase + // with target machine to find out the endianness. The default constructor (without + // parameters) is used by the pass manager for managing purposes. + BPFAbstractMemberAccess(BPFTargetMachine *TM = nullptr) : ModulePass(ID), TM(TM) {} struct CallInfo { uint32_t Kind; @@ -102,13 +128,14 @@ BPFPreserveArrayAI = 1, BPFPreserveUnionAI = 2, BPFPreserveStructAI = 3, + BPFPreserveFieldInfoAI = 4, }; std::map<std::string, GlobalVariable *> GEPGlobals; // A map to link preserve_*_access_index instrinsic calls. std::map<CallInst *, std::pair<CallInst *, CallInfo>> 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 + // The base call is not an input of any other preserve_* // intrinsics. std::map<CallInst *, CallInfo> BaseAICalls; @@ -127,6 +154,8 @@ bool removePreserveAccessIndexIntrinsic(Module &M); void replaceWithGEP(std::vector<CallInst *> &CallList, uint32_t NumOfZerosIndex, uint32_t DIIndex); + uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy, + uint32_t AccessIndex); Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo, std::string &AccessKey, MDNode *&BaseMeta); @@ -139,8 +168,8 @@ INITIALIZE_PASS(BPFAbstractMemberAccess, DEBUG_TYPE, "abstracting struct/union member accessees", false, false) -ModulePass *llvm::createBPFAbstractMemberAccess() { - return new BPFAbstractMemberAccess(); +ModulePass *llvm::createBPFAbstractMemberAccess(BPFTargetMachine *TM) { + return new BPFAbstractMemberAccess(TM); } bool BPFAbstractMemberAccess::runOnModule(Module &M) { @@ -231,6 +260,16 @@ CInfo.Base = Call->getArgOperand(0); return true; } + if (GV->getName().startswith("llvm.bpf.preserve.field.info")) { + CInfo.Kind = BPFPreserveFieldInfoAI; + CInfo.Metadata = nullptr; + // Check validity of info_kind as clang did not check this. + uint64_t InfoKind = getConstant(Call->getArgOperand(1)); + if (InfoKind >= BPFCoreSharedInfo::MAX_FIELD_RELOC_KIND) + report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic"); + CInfo.AccessIndex = InfoKind; + return true; + } return false; } @@ -306,6 +345,9 @@ bool BPFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType, uint32_t ParentAI, const MDNode *ChildType) { + if (!ChildType) + return true; // preserve_field_info, no type comparison needed. + const DIType *PType = stripQualifiers(cast<DIType>(ParentType)); const DIType *CType = stripQualifiers(cast<DIType>(ChildType)); @@ -463,7 +505,94 @@ return CV->getValue().getZExtValue(); } -/// Compute the base of the whole preserve_*_access_index chains, i.e., the base +uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, + DICompositeType *CTy, + uint32_t AccessIndex) { + if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE) + return 1; + + uint32_t Tag = CTy->getTag(); + assert(Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type); + auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); + + if (InfoKind == BPFCoreSharedInfo::FIELD_SIGNEDNESS) { + const DIType *BaseTy = stripQualifiers(MemberTy->getBaseType()); + // Only basic types and enum types have signedness. + const auto *BTy = dyn_cast<DIBasicType>(BaseTy); + while (!BTy) { + const auto *CompTy = dyn_cast<DICompositeType>(BaseTy); + // Report an error if the member expression does not have signedness. + if (!CompTy || CompTy->getTag() != dwarf::DW_TAG_enumeration_type) + report_fatal_error("Invalid member expression for llvm.bpf.preserve.field.info"); + BaseTy = stripQualifiers(CompTy->getBaseType()); + BTy = dyn_cast<DIBasicType>(BaseTy); + } + uint32_t Encoding = BTy->getEncoding(); + return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char); + } + + if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_SIZE) { + uint32_t SizeInBits = MemberTy->getSizeInBits(); + if (!MemberTy->isBitField()) + return SizeInBits >> 3; + + uint32_t OffsetInBits = MemberTy->getOffsetInBits(); + uint32_t Start = OffsetInBits >> 3; + uint32_t End = (OffsetInBits + SizeInBits - 1) >> 3; + return End - Start + 1; + } + + if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64) { + uint32_t SizeInBits = MemberTy->getSizeInBits(); + const Triple &Triple = TM->getTargetTriple(); + if (!MemberTy->isBitField()) { + if (SizeInBits > 64) + report_fatal_error("too big member size for llvm.bpf.preserve.field.info"); + + /* endianness */ + if (Triple.getArch() == Triple::bpfeb) + return 0; + else + return 64 - SizeInBits; + } + + uint32_t OffsetInBits = MemberTy->getOffsetInBits(); + uint32_t Start = OffsetInBits >> 3; + uint32_t End = (OffsetInBits + SizeInBits - 1) >> 3; + uint32_t NumOfBytes = End - Start + 1; + if (NumOfBytes > 8) + report_fatal_error("too big member size for llvm.bpf.preserve.field.info"); + + /* endianness */ + if (Triple.getArch() == Triple::bpfeb) + return OffsetInBits - (Start << 3); + else + return ((Start + 8) << 3) - OffsetInBits - SizeInBits; + } + + if (InfoKind == BPFCoreSharedInfo::FIELD_RSHIFT_U64) { + uint32_t SizeInBits = MemberTy->getSizeInBits(); + if (!MemberTy->isBitField()) { + if (SizeInBits > 64) + report_fatal_error("too big member size for llvm.bpf.preserve.field.info"); + + return 64 - SizeInBits; + } + + uint32_t OffsetInBits = MemberTy->getOffsetInBits(); + uint32_t Start = OffsetInBits >> 3; + uint32_t End = (OffsetInBits + SizeInBits - 1) >> 3; + uint32_t NumOfBytes = End - Start + 1; + if (NumOfBytes > 8) + report_fatal_error("too big member size for llvm.bpf.preserve.field.info"); + + return 64 - SizeInBits; + } + + llvm_unreachable("Unknown llvm.bpf.preserve.field.info info kind"); +} + +/// Compute the base of the whole preserve_* intrinsics 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, @@ -492,7 +621,8 @@ // int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ... // we will skip them. uint32_t FirstIndex = 0; - uint32_t AccessOffset = 0; + uint32_t PatchImm = 0; // AccessOffset or the requested field info + uint32_t InfoKind = BPFCoreSharedInfo::FIELD_BYTE_OFFSET; while (CallStack.size()) { auto StackElem = CallStack.top(); Call = StackElem.first; @@ -507,10 +637,12 @@ // struct or union type TypeName = Ty->getName(); TypeMeta = Ty; - AccessOffset += FirstIndex * Ty->getSizeInBits() >> 3; + PatchImm += FirstIndex * (Ty->getSizeInBits() >> 3); break; } + assert(CInfo.Kind == BPFPreserveArrayAI); + // Array entries will always be consumed for accumulative initial index. CallStack.pop(); @@ -555,7 +687,7 @@ else TypeName = CTy->getName(); TypeMeta = CTy; - AccessOffset += FirstIndex * CTy->getSizeInBits() >> 3; + PatchImm += FirstIndex * (CTy->getSizeInBits() >> 3); break; } } @@ -569,6 +701,20 @@ CInfo = StackElem.second; CallStack.pop(); + if (CInfo.Kind == BPFPreserveFieldInfoAI) + break; + + // If the next Call (the top of the stack) is a BPFPreserveFieldInfoAI, + // the action will be extracting field info. + if (CallStack.size()) { + auto StackElem2 = CallStack.top(); + CallInfo CInfo2 = StackElem2.second; + if (CInfo2.Kind == BPFPreserveFieldInfoAI) { + InfoKind = CInfo2.AccessIndex; + assert(CallStack.size() == 1); + } + } + // Access Index uint64_t AccessIndex = CInfo.AccessIndex; AccessKey += ":" + std::to_string(AccessIndex); @@ -577,19 +723,24 @@ // At this stage, it cannot be pointer type. auto *CTy = cast<DICompositeType>(stripQualifiers(cast<DIType>(MDN))); uint32_t Tag = CTy->getTag(); - if (Tag == dwarf::DW_TAG_structure_type) { - auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); - AccessOffset += MemberTy->getOffsetInBits() >> 3; - } else if (Tag == dwarf::DW_TAG_array_type) { - auto *EltTy = stripQualifiers(CTy->getBaseType()); - AccessOffset += AccessIndex * calcArraySize(CTy, 1) * - EltTy->getSizeInBits() >> 3; + if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_OFFSET) { + if (Tag == dwarf::DW_TAG_structure_type) { + auto *MemberTy = cast<DIDerivedType>(CTy->getElements()[AccessIndex]); + PatchImm += MemberTy->getOffsetInBits() >> 3; + } else if (Tag == dwarf::DW_TAG_array_type) { + auto *EltTy = stripQualifiers(CTy->getBaseType()); + PatchImm += AccessIndex * calcArraySize(CTy, 1) * + (EltTy->getSizeInBits() >> 3); + } + } else { + PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex); } } - // Access key is the type name + access string, uniquely identifying - // one kernel memory access. - AccessKey = TypeName + ":" + std::to_string(AccessOffset) + "$" + AccessKey; + // Access key is the type name + reloc type + patched imm + access string, + // uniquely identifying one relocation. + AccessKey = TypeName + ":" + std::to_string(InfoKind) + ":" + + std::to_string(PatchImm) + "$" + AccessKey; return Base; } @@ -605,22 +756,18 @@ if (!Base) return false; - // Do the transformation - // For any original GEP Call and Base %2 like - // %4 = bitcast %struct.net_device** %dev1 to i64* - // it is transformed to: - // %6 = load sk_buff:50:$0:0:0:2:0 - // %7 = bitcast %struct.sk_buff* %2 to i8* - // %8 = getelementptr i8, i8* %7, %6 - // %9 = bitcast i8* %8 to i64* - // using %9 instead of %4 - // The original Call inst is removed. BasicBlock *BB = Call->getParent(); GlobalVariable *GV; if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) { - GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false, - GlobalVariable::ExternalLinkage, NULL, AccessKey); + IntegerType *VarType; + if (CInfo.Kind == BPFPreserveFieldInfoAI) + VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value + else + VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr arith + + GV = new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage, + NULL, AccessKey); GV->addAttribute(BPFCoreSharedInfo::AmaAttr); GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta); GEPGlobals[AccessKey] = GV; @@ -628,6 +775,25 @@ GV = GEPGlobals[AccessKey]; } + if (CInfo.Kind == BPFPreserveFieldInfoAI) { + // Load the global variable which represents the returned field info. + auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV); + BB->getInstList().insert(Call->getIterator(), LDInst); + Call->replaceAllUsesWith(LDInst); + Call->eraseFromParent(); + return true; + } + + // For any original GEP Call and Base %2 like + // %4 = bitcast %struct.net_device** %dev1 to i64* + // it is transformed to: + // %6 = load sk_buff:50:$0:0:0:2:0 + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // %9 = bitcast i8* %8 to i64* + // using %9 instead of %4 + // The original Call inst is removed. + // Load the global variable. auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV); BB->getInstList().insert(Call->getIterator(), LDInst); Index: llvm/lib/Target/BPF/BPF.h =================================================================== --- llvm/lib/Target/BPF/BPF.h +++ llvm/lib/Target/BPF/BPF.h @@ -15,7 +15,7 @@ namespace llvm { class BPFTargetMachine; -ModulePass *createBPFAbstractMemberAccess(); +ModulePass *createBPFAbstractMemberAccess(BPFTargetMachine *TM); FunctionPass *createBPFISelDag(BPFTargetMachine &TM); FunctionPass *createBPFMISimplifyPatchablePass(); Index: llvm/include/llvm/IR/IntrinsicsBPF.td =================================================================== --- llvm/include/llvm/IR/IntrinsicsBPF.td +++ llvm/include/llvm/IR/IntrinsicsBPF.td @@ -20,4 +20,7 @@ Intrinsic<[llvm_i64_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>; def int_bpf_pseudo : GCCBuiltin<"__builtin_bpf_pseudo">, Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty]>; + def int_bpf_preserve_field_info : GCCBuiltin<"__builtin_bpf_preserve_field_info">, + Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_i64_ty], + [IntrNoMem, ImmArg<1>]>; } Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -1540,6 +1540,11 @@ if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::hexagon: if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); @@ -1940,6 +1945,36 @@ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + if (checkArgCount(*this, TheCall, 2)) + return true; + + // The first argument needs to be a record field access + Expr *Arg = TheCall->getArg(0); + if (Arg->getType()->getAsPlaceholderType() || + (Arg->IgnoreParens()->getObjectKind() != OK_BitField && + !dyn_cast<MemberExpr>(Arg->IgnoreParens()))) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field) + << 1 << Arg->getSourceRange(); + return true; + } + + // The second argument needs to be a constant int + llvm::APSInt Value; + if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + + TheCall->setType(Context.UnsignedIntTy); + return false; +} + bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { struct BuiltinAndString { unsigned BuiltinID; Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -3760,6 +3760,7 @@ llvm::Value *vectorWrapScalar16(llvm::Value *Op); llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, llvm::Triple::ArchType Arch); + llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -3990,9 +3990,19 @@ const CGBitFieldInfo &Info = RL.getBitFieldInfo(field); Address Addr = base.getAddress(); unsigned Idx = RL.getLLVMFieldNo(field); - if (Idx != 0) - // For structs, we GEP to the field that the record layout suggests. - Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); + if (!IsInPreservedAIRegion) { + if (Idx != 0) + // For structs, we GEP to the field that the record layout suggests. + Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); + } else { + const RecordDecl *rec = field->getParent(); + llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( + getContext().getRecordType(rec), rec->getLocation()); + Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx, + getDebugInfoFIndex(rec, field->getFieldIndex()), + DbgInfo); + } + // Get the access type. llvm::Type *FieldIntTy = llvm::Type::getIntNTy(getLLVMContext(), Info.StorageSize); Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -4242,6 +4242,9 @@ case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch); + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + return CGF->EmitBPFBuiltinExpr(BuiltinID, E); case llvm::Triple::x86: case llvm::Triple::x86_64: return CGF->EmitX86BuiltinExpr(BuiltinID, E); @@ -9300,6 +9303,37 @@ } } +Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + const Expr *Arg = E->getArg(0); + bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField; + + if (!getDebugInfo()) { + CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g"); + return IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(); + } + + // Enable underlying preserve_*_access_index() generation. + bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; + IsInPreservedAIRegion = true; + Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(); + IsInPreservedAIRegion = OldIsInPreservedAIRegion; + + ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1))); + Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue()); + + // Built the IR for the preserve_field_info intrinsic. + llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info, + {FieldAddr->getType()}); + return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind}); +} + llvm::Value *CodeGenFunction:: BuildVector(ArrayRef<llvm::Value*> Ops) { assert((Ops.size() & (Ops.size() - 1)) == 0 && Index: clang/lib/Basic/Targets/BPF.h =================================================================== --- clang/lib/Basic/Targets/BPF.h +++ clang/lib/Basic/Targets/BPF.h @@ -22,6 +22,8 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + public: BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { @@ -54,7 +56,7 @@ Features[Name] = Enabled; } - ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + ArrayRef<Builtin::Info> getTargetBuiltins() const override; const char *getClobbers() const override { return ""; } Index: clang/lib/Basic/Targets/BPF.cpp =================================================================== --- clang/lib/Basic/Targets/BPF.cpp +++ clang/lib/Basic/Targets/BPF.cpp @@ -13,11 +13,18 @@ #include "BPF.h" #include "Targets.h" #include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringRef.h" using namespace clang; using namespace clang::targets; +const Builtin::Info BPFTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsBPF.def" +}; + void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__bpf__"); @@ -34,3 +41,8 @@ void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } + +ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} Index: clang/include/clang/module.modulemap =================================================================== --- clang/include/clang/module.modulemap +++ clang/include/clang/module.modulemap @@ -34,6 +34,7 @@ textual header "Basic/BuiltinsAArch64.def" textual header "Basic/BuiltinsAMDGPU.def" textual header "Basic/BuiltinsARM.def" + textual header "Basic/BuiltinsBPF.def" textual header "Basic/Builtins.def" textual header "Basic/BuiltinsHexagon.def" textual header "Basic/BuiltinsLe64.def" Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11052,6 +11052,7 @@ bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); Index: clang/include/clang/Basic/TargetBuiltins.h =================================================================== --- clang/include/clang/Basic/TargetBuiltins.h +++ clang/include/clang/Basic/TargetBuiltins.h @@ -52,6 +52,16 @@ }; } + /// BPF builtins + namespace BPF { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + #define BUILTIN(ID, TYPE, ATTRS) BI##ID, + #include "clang/Basic/BuiltinsBPF.def" + LastTSBuiltin + }; + } + /// PPC builtins namespace PPC { enum { Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9953,6 +9953,11 @@ "%select{non-pointer|function pointer|void pointer}0 argument to " "'__builtin_launder' is not allowed">; +def err_preserve_field_info_not_field : Error< + "__builtin_preserve_field_info argument %0 not a field access">; +def err_preserve_field_info_not_const: Error< + "__builtin_preserve_field_info argument %0 not a constant">; + def err_bit_cast_non_trivially_copyable : Error< "__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">; def err_bit_cast_type_size_mismatch : Error< Index: clang/include/clang/Basic/BuiltinsBPF.def =================================================================== --- /dev/null +++ clang/include/clang/Basic/BuiltinsBPF.def @@ -0,0 +1,24 @@ +//===--- BuiltinsBPF.def - BPF Builtin function database --------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the BPF-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Get record field information. +TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "") + +#undef BUILTIN +#undef TARGET_BUILTIN
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits