BPF: simplify IR generation for __builtin_btf_type_id()
authorYonghong Song <yhs@fb.com>
Mon, 3 Aug 2020 23:12:19 +0000 (16:12 -0700)
committerYonghong Song <yhs@fb.com>
Tue, 4 Aug 2020 23:29:42 +0000 (16:29 -0700)
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

clang/lib/CodeGen/CGBuiltin.cpp
clang/test/CodeGen/builtin-bpf-btf-type-id.c
llvm/include/llvm/IR/IntrinsicsBPF.td
llvm/lib/Target/BPF/BPFPreserveDIType.cpp
llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id.ll

index 1891118..1797dfa 100644 (file)
@@ -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");
@@ -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;
   }
index f60e3ca..5143dee 100644 (file)
@@ -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"
index f25f631..0a0a7f3 100644 (file)
@@ -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],
index c3cb764..271ae56 100644 (file)
@@ -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());
@@ -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.
index 4ea3b27..b5d5cec 100644 (file)
@@ -13,7 +13,7 @@
 ;     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
 }
@@ -47,56 +45,55 @@ entry:
 ; 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 }
 
@@ -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}
@@ -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}