yonghong-song created this revision. yonghong-song added reviewers: ast, anakryiko. yonghong-song added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits. yonghong-song added a comment.
The corresponding LLVM side of change is https://reviews.llvm.org/D74572 Such a builtin function is mostly useful to preserve btf type id for non-global data. For example, extern void foo(..., void *data, int size); int test(...) { struct t { int a; int b; int c; } d; d.a = ...; d.b = ...; d.c = ...; foo(..., &d, sizeof(d)); } The function "foo" in the above only see raw data and does not know what type of the data is. In certain cases, e.g., logging, the additional type information will help pretty print. This patch implemented a BPF specific builtin u32 btf_type_id = __builtin_btf_type_id(param) which will return a btf type id for the "param". Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74668 Files: clang/include/clang/Basic/BuiltinsBPF.def clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Sema/SemaChecking.cpp clang/test/CodeGen/builtin-bpf-btf-type-id.c clang/test/Sema/builtin-bpf-btf-type-id.c llvm/include/llvm/IR/IntrinsicsBPF.td
Index: llvm/include/llvm/IR/IntrinsicsBPF.td =================================================================== --- llvm/include/llvm/IR/IntrinsicsBPF.td +++ llvm/include/llvm/IR/IntrinsicsBPF.td @@ -23,4 +23,6 @@ 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>]>; + def int_bpf_btf_type_id : GCCBuiltin<"__builtin_bpf_btf_type_id">, + Intrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_any_ty], [IntrNoMem]>; } Index: clang/test/Sema/builtin-bpf-btf-type-id.c =================================================================== --- /dev/null +++ clang/test/Sema/builtin-bpf-btf-type-id.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -x c -triple bpf-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +struct { + char f1[100]; + int f2; +} tmp = {}; + +unsigned invalid1() { return __builtin_btf_type_id(1, 1); } // expected-error {{too many arguments to function call, expected 1, have 2}} +int valid2() { return __builtin_btf_type_id(tmp); } +int valid3() { return __builtin_btf_type_id(&tmp); } +int valid4() { return __builtin_btf_type_id(tmp.f1[4]); } Index: clang/test/CodeGen/builtin-bpf-btf-type-id.c =================================================================== --- /dev/null +++ clang/test/CodeGen/builtin-bpf-btf-type-id.c @@ -0,0 +1,13 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +unsigned test1(int a) { return __builtin_btf_type_id(a); } +unsigned test2(int a) { return __builtin_btf_type_id(&a); } + +// CHECK: define dso_local i32 @test1 +// CHECK: call i32 @llvm.bpf.btf.type.id.p0i32.i32(i32* %{{[0-9a-z.]+}}, i32 1), !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), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT_POINTER:[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 Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -2284,9 +2284,17 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + assert((BuiltinID == BPF::BI__builtin_preserve_field_info || + BuiltinID == BPF::BI__builtin_btf_type_id) && "unexpected ARM builtin"); + if (BuiltinID == BPF::BI__builtin_btf_type_id) { + if (checkArgCount(*this, TheCall, 1)) + return true; + TheCall->setType(Context.UnsignedIntTy); + return false; + } + if (checkArgCount(*this, TheCall, 2)) return true; Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -9703,33 +9703,99 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - assert(BuiltinID == BPF::BI__builtin_preserve_field_info && - "unexpected ARM builtin"); + assert((BuiltinID == BPF::BI__builtin_preserve_field_info || + BuiltinID == BPF::BI__builtin_btf_type_id) && + "unexpected BPF builtin"); - const Expr *Arg = E->getArg(0); - bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField; + switch (BuiltinID) { + default: + llvm_unreachable("Unexpected BPF builtin"); + case BPF::BI__builtin_preserve_field_info: { + 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(*this); - } + if (!getDebugInfo()) { + CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g"); + return IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(*this); + } - // Enable underlying preserve_*_access_index() generation. - bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; - IsInPreservedAIRegion = true; - Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(*this); - IsInPreservedAIRegion = OldIsInPreservedAIRegion; + // Enable underlying preserve_*_access_index() generation. + bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; + IsInPreservedAIRegion = true; + Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() + : EmitLValue(Arg).getPointer(*this); + 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}); + } + 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)); - ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1))); - Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue()); + if (!getDebugInfo()) { + CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g"); + return nullptr; + } + + // Generate debuginfo type for the first argument. + llvm::DIType *DbgInfo = + getDebugInfo()->getOrCreateStandaloneType(E->getArg(0)->getType(), + E->getArg(0)->getExprLoc()); - // 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}); + // 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); + // will be converted to + // L1: llvm.bpf.btf.type.id(&v) + // This makes it hard to differentiate from + // C2: __builtin_btf_type_id(&v); + // to + // L2: llvm.bpf.btf.type.id(&v) + // + // 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) !di_type_for_{v}; + // L2: llvm.bpf.btf.type.id(&v, 0) !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}); + Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); + return Fn; + } + } } llvm::Value *CodeGenFunction:: Index: clang/include/clang/Basic/BuiltinsBPF.def =================================================================== --- clang/include/clang/Basic/BuiltinsBPF.def +++ clang/include/clang/Basic/BuiltinsBPF.def @@ -20,5 +20,8 @@ // Get record field information. TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "") +// Get BTF type id. +TARGET_BUILTIN(__builtin_btf_type_id, "v.", "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