Skip to content

Commit

Permalink
BPF: simplify IR generation for __builtin_btf_type_id()
Browse files Browse the repository at this point in the history
This patch simplified IR generation for __builtin_btf_type_id().
For __builtin_btf_type_id(obj, flag), previously IR builtin
looks like
   if (obj is a lvalue)
     llvm.bpf.btf.type.id(obj.ptr, 1, flag)  !type
   else
     llvm.bpf.btf.type.id(obj, 0, flag)  !type
The purpose of the 2nd argument is to differentiate
   __builtin_btf_type_id(obj, flag) where obj is a lvalue
vs.
   __builtin_btf_type_id(obj.ptr, flag)

Note that obj or obj.ptr is never used by the backend
and the `obj` argument is only used to derive the type.
This code sequence is subject to potential llvm CSE when
  - obj is the same .e.g., nullptr
  - flag is the same
  - metadata type is different, e.g., typedef of struct "s"
    and strust "s".
In the above, we don't want CSE since their metadata is different.

This patch change IR builtin to
   llvm.bpf.btf.type.id(seq_num, flag)  !type
and seq_num is always increasing. This will prevent potential
llvm CSE.

Also report an error if the type name is empty for
remote relocation since remote relocation needs non-empty
type name to do relocation against vmlinux.

Differential Revision: https://reviews.llvm.org/D85174
  • Loading branch information
yonghong-song committed Aug 4, 2020
1 parent 4b25f67 commit 00602ee
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 123 deletions.
75 changes: 9 additions & 66 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10961,68 +10961,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
{FieldAddr->getType()});
return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind});
}
case BPF::BI__builtin_btf_type_id: {
Value *FieldVal = nullptr;

// The LValue cannot be converted Value in order to be used as the function
// parameter. If it is a structure, it is the "alloca" result of the LValue
// (a pointer) is used in the parameter. If it is a simple type,
// the value will be loaded from its corresponding "alloca" and used as
// the parameter. In our case, let us just get a pointer of the LValue
// since we do not really use the parameter. The purpose of parameter
// is to prevent the generated IR llvm.bpf.btf.type.id intrinsic call,
// which carries metadata, from being changed.
bool IsLValue = E->getArg(0)->isLValue();
if (IsLValue)
FieldVal = EmitLValue(E->getArg(0)).getPointer(*this);
else
FieldVal = EmitScalarExpr(E->getArg(0));

if (!getDebugInfo()) {
CGM.Error(E->getExprLoc(), "using __builtin_btf_type_id() without -g");
return nullptr;
}

// Generate debuginfo type for the first argument.
llvm::DIType *DbgInfo =
getDebugInfo()->getOrCreateStandaloneType(E->getArg(0)->getType(),
E->getArg(0)->getExprLoc());

ConstantInt *Flag = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue());

// Built the IR for the btf_type_id intrinsic.
//
// In the above, we converted LValue argument to a pointer to LValue.
// For example, the following
// int v;
// C1: __builtin_btf_type_id(v, flag);
// will be converted to
// L1: llvm.bpf.btf.type.id(&v, flag)
// This makes it hard to differentiate from
// C2: __builtin_btf_type_id(&v, flag);
// to
// L2: llvm.bpf.btf.type.id(&v, flag)
//
// If both C1 and C2 are present in the code, the llvm may later
// on do CSE on L1 and L2, which will result in incorrect tagged types.
//
// The C1->L1 transformation only happens if the argument of
// __builtin_btf_type_id() is a LValue. So Let us put whether
// the argument is an LValue or not into generated IR. This should
// prevent potential CSE from causing debuginfo type loss.
//
// The generated IR intrinsics will hence look like
// L1: llvm.bpf.btf.type.id(&v, 1, flag) !di_type_for_{v};
// L2: llvm.bpf.btf.type.id(&v, 0, flag) !di_type_for_{&v};
Constant *CV = ConstantInt::get(IntTy, IsLValue);
llvm::Function *FnBtfTypeId = llvm::Intrinsic::getDeclaration(
&CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id,
{FieldVal->getType(), CV->getType()});
CallInst *Fn = Builder.CreateCall(FnBtfTypeId, {FieldVal, CV, FlagValue});
Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
return Fn;
}
case BPF::BI__builtin_btf_type_id:
case BPF::BI__builtin_preserve_type_info: {
if (!getDebugInfo()) {
CGM.Error(E->getExprLoc(), "using builtin function without -g");
Expand All @@ -11037,10 +10976,14 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue());
Value *SeqNumVal = ConstantInt::get(Int32Ty, BuiltinSeqNum++);

llvm::Function *FnPreserveTypeInfo = llvm::Intrinsic::getDeclaration(
&CGM.getModule(), llvm::Intrinsic::bpf_preserve_type_info, {});
CallInst *Fn =
Builder.CreateCall(FnPreserveTypeInfo, {SeqNumVal, FlagValue});
llvm::Function *FnDecl;
if (BuiltinID == BPF::BI__builtin_btf_type_id)
FnDecl = llvm::Intrinsic::getDeclaration(
&CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id, {});
else
FnDecl = llvm::Intrinsic::getDeclaration(
&CGM.getModule(), llvm::Intrinsic::bpf_preserve_type_info, {});
CallInst *Fn = Builder.CreateCall(FnDecl, {SeqNumVal, FlagValue});
Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
return Fn;
}
Expand Down
16 changes: 14 additions & 2 deletions clang/test/CodeGen/builtin-bpf-btf-type-id.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@
unsigned test1(int a) { return __builtin_btf_type_id(a, 0); }
unsigned test2(int a) { return __builtin_btf_type_id(&a, 0); }

struct t1 { int a; };
typedef struct t1 __t1;
unsigned test3() {
return __builtin_btf_type_id(*(struct t1 *)0, 1) +
__builtin_btf_type_id(*(__t1 *)0, 1);
}

// CHECK: define dso_local i32 @test1
// CHECK: call i32 @llvm.bpf.btf.type.id.p0i32.i32(i32* %{{[0-9a-z.]+}}, i32 1, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT:[0-9]+]]
// CHECK: call i32 @llvm.bpf.btf.type.id(i32 0, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT:[0-9]+]]
// CHECK: define dso_local i32 @test2
// CHECK: call i32 @llvm.bpf.btf.type.id.p0i32.i32(i32* %{{[0-9a-z.]+}}, i32 0, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT_POINTER:[0-9]+]]
// CHECK: call i32 @llvm.bpf.btf.type.id(i32 1, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT_POINTER:[0-9]+]]
// CHECK: define dso_local i32 @test3
// CHECK: call i32 @llvm.bpf.btf.type.id(i32 2, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_T1:[0-9]+]]
// CHECK: call i32 @llvm.bpf.btf.type.id(i32 3, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_T1:[0-9]+]]
//
// CHECK: ![[INT]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed
// CHECK: ![[INT_POINTER]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[INT]], size: 64
// CHECK: ![[TYPEDEF_T1]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__t1"
// CHECK: ![[STRUCT_T1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1"
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/IntrinsicsBPF.td
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let TargetPrefix = "bpf" in { // All intrinsics start with "llvm.bpf."
Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty, llvm_i64_ty],
[IntrNoMem, ImmArg<ArgIndex<1>>]>;
def int_bpf_btf_type_id : GCCBuiltin<"__builtin_bpf_btf_type_id">,
Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_any_ty, llvm_i64_ty],
Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i64_ty],
[IntrNoMem]>;
def int_bpf_preserve_type_info : GCCBuiltin<"__builtin_bpf_preserve_type_info">,
Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i64_ty],
Expand Down
13 changes: 9 additions & 4 deletions llvm/lib/Target/BPF/BPFPreserveDIType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,24 @@ bool BPFPreserveDIType::doTransformation(Module &M) {
std::string BaseName = "llvm.btf_type_id.";
int Count = 0;
for (auto Call : PreserveDITypeCalls) {
const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(2));
const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(1));
assert(Flag);
uint64_t FlagValue = Flag->getValue().getZExtValue();

if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG)
report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic");

MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);

uint32_t Reloc;
if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC)
if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) {
Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL;
else
} else {
Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE;
DIType *Ty = cast<DIType>(MD);
if (Ty->getName().empty())
report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc");
}

BasicBlock *BB = Call->getParent();
IntegerType *VarType = Type::getInt32Ty(BB->getContext());
Expand All @@ -116,7 +122,6 @@ bool BPFPreserveDIType::doTransformation(Module &M) {
new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage,
NULL, GVName);
GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr);
MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);
GV->setMetadata(LLVMContext::MD_preserve_access_index, MD);

// Load the global variable which represents the type info.
Expand Down
97 changes: 47 additions & 50 deletions llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,90 +13,87 @@
; bpf_log(__builtin_btf_type_id(tmp__abc, 0), &tmp__abc, sizeof(tmp__abc));
; }
; void prog2() {
; bpf_log(__builtin_btf_type_id(&tmp__abc, 1), &tmp__abc, sizeof(tmp__abc));
; bpf_log(__builtin_btf_type_id(&tmp__abc, 0), &tmp__abc, sizeof(tmp__abc));
; }
; void prog3() {
; bpf_log(__builtin_btf_type_id(tmp__abc.f1[3], 1), &tmp__abc, sizeof(tmp__abc));
; }
; Compilation flag:
; clang -target bpf -O2 -g -S -emit-llvm test.c

%struct.anon = type { [100 x i8], i32 }

@tmp__abc = dso_local global { <{ i8, i8, [98 x i8] }>, i32 } { <{ i8, i8, [98 x i8] }> <{ i8 1, i8 3, [98 x i8] zeroinitializer }>, i32 0 }, align 4, !dbg !0

; Function Attrs: nounwind
define dso_local void @prog1() local_unnamed_addr #0 !dbg !28 {
entry:
%0 = tail call i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon* bitcast ({ <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc to %struct.anon*), i32 1, i64 0), !dbg !31, !llvm.preserve.access.index !7
%0 = tail call i32 @llvm.bpf.btf.type.id(i32 0, i64 0), !dbg !31, !llvm.preserve.access.index !7
%call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !32
ret void, !dbg !33
}

; Function Attrs: nounwind readnone
declare i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon*, i32, i64) #1
declare i32 @llvm.bpf.btf.type.id(i32, i64) #1

; Function Attrs: nounwind
define dso_local void @prog2() local_unnamed_addr #0 !dbg !34 {
entry:
%0 = tail call i32 @llvm.bpf.btf.type.id.p0s_struct.anons.i32(%struct.anon* bitcast ({ <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc to %struct.anon*), i32 0, i64 1), !dbg !35, !llvm.preserve.access.index !6
%0 = tail call i32 @llvm.bpf.btf.type.id(i32 1, i64 0), !dbg !35, !llvm.preserve.access.index !6
%call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !36
ret void, !dbg !37
}

; Function Attrs: nounwind
define dso_local void @prog3() local_unnamed_addr #0 !dbg !38 {
entry:
%0 = tail call i32 @llvm.bpf.btf.type.id.p0i8.i32(i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 2, i64 1), i32 1, i64 1), !dbg !39, !llvm.preserve.access.index !11
%0 = tail call i32 @llvm.bpf.btf.type.id(i32 2, i64 1), !dbg !39, !llvm.preserve.access.index !11
%call = tail call i32 inttoptr (i64 999 to i32 (i32, i8*, i32)*)(i32 %0, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i64 0, i32 0, i32 0), i32 104) #2, !dbg !40
ret void, !dbg !41
}

; CHECK-LABEL: prog1
; CHECK: r1 = 3
; CHECK-LABEL: prog2
; CHECK: r1 = 10
; CHECK-LABEL: prog3
; CHECK: r1 = 4
;
; CHECK: .long 0 # BTF_KIND_STRUCT(id = 3)
; CHECK-NEXT: .long 67108866 # 0x4000002
; CHECK-NEXT: .long 104
; CHECK-NEXT: .long 13
; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 0 # 0x0
; CHECK-NEXT: .long 16
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 800 # 0x320
; CHECK-NEXT: .long 19 # BTF_KIND_INT(id = 4)
; CHECK-NEXT: .long 16777216 # 0x1000000
; CHECK-NEXT: .long 1
; CHECK-NEXT: .long 16777224 # 0x1000008
; CHECK: .long 0 # BTF_KIND_PTR(id = 10)
; CHECK-NEXT: .long 33554432 # 0x2000000
; CHECK-NEXT: .long 3
; CHECK-LABEL: prog1
; CHECK: r1 = 3
; CHECK-LABEL: prog2
; CHECK: r1 = 10
; CHECK-LABEL: prog3
; CHECK: r1 = 4

; CHECK: .long 16 # FieldReloc
; CHECK-NEXT: .long {{[0-9]+}} # Field reloc section string offset={{[0-9]+}}
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long {{[0-9]+}}
; CHECK-NEXT: .long 6
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 10
; CHECK-NEXT: .long {{[0-9]+}}
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long {{[0-9]+}}
; CHECK-NEXT: .long 7
; CHECK: .long 0 # BTF_KIND_STRUCT(id = 3)
; CHECK-NEXT: .long 67108866 # 0x4000002
; CHECK-NEXT: .long 104
; CHECK-NEXT: .long 13
; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 0 # 0x0
; CHECK-NEXT: .long 16
; CHECK-NEXT: .long 7
; CHECK-NEXT: .long 800 # 0x320
; CHECK: .long 19 # BTF_KIND_INT(id = 4)
; CHECK: .long 0 # BTF_KIND_PTR(id = 10)
; CHECK-NEXT: .long 33554432 # 0x2000000
; CHECK-NEXT: .long 3

; CHECK: .ascii ".text" # string offset=7
; CHECK: .ascii "f1" # string offset=13
; CHECK: .ascii "f2" # string offset=16
; CHECK: .ascii "char" # string offset=19
; CHECK: .byte 48 # string offset=48

; Function Attrs: nounwind readnone
declare i32 @llvm.bpf.btf.type.id.p0i8.i32(i8*, i32, i64) #1
; CHECK: .long 16 # FieldReloc
; CHECK-NEXT: .long 7 # Field reloc section string offset=7
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 3
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 6
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 10
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 6
; CHECK-NEXT: .long .Ltmp{{[0-9]+}}
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 48
; CHECK-NEXT: .long 7

attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }

Expand All @@ -106,7 +103,7 @@ attributes #2 = { nounwind }

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "tmp__abc", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 95253d8f16b8085b4b85cb3a6106ccbfe8a6d9b2)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !16, splitDebugInlining: false, nameTableKind: None)
!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git f39aae11dca3f8f8c2c755a871726ed2fa82fd57)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !16, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core")
!4 = !{}
!5 = !{!6, !11}
Expand All @@ -131,7 +128,7 @@ attributes #2 = { nounwind }
!24 = !{i32 7, !"Dwarf Version", i32 4}
!25 = !{i32 2, !"Debug Info Version", i32 3}
!26 = !{i32 1, !"wchar_size", i32 4}
!27 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 95253d8f16b8085b4b85cb3a6106ccbfe8a6d9b2)"}
!27 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git f39aae11dca3f8f8c2c755a871726ed2fa82fd57)"}
!28 = distinct !DISubprogram(name: "prog1", scope: !3, file: !3, line: 6, type: !29, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4)
!29 = !DISubroutineType(types: !30)
!30 = !{null}
Expand Down

0 comments on commit 00602ee

Please sign in to comment.