diff --git a/clang/include/clang/Basic/BuiltinsBPF.def b/clang/include/clang/Basic/BuiltinsBPF.def --- a/clang/include/clang/Basic/BuiltinsBPF.def +++ b/clang/include/clang/Basic/BuiltinsBPF.def @@ -23,5 +23,8 @@ // Get BTF type id. TARGET_BUILTIN(__builtin_btf_type_id, "Ui.", "t", "") +// Load a unsigned value and convert it to a pointer. +TARGET_BUILTIN(__builtin_load_u32_to_ptr, "v*v*Ui", "n", "") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10788,6 +10788,8 @@ "__builtin_preserve_field_info argument %0 not a constant">; def err_btf_type_id_not_const: Error< "__builtin_btf_type_id argument %0 not a constant">; +def err_load_u32_to_ptr_not_const: Error< + "__builtin_load_u32_to_ptr 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">; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -10685,7 +10685,8 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id) && + BuiltinID == BPF::BI__builtin_btf_type_id || + BuiltinID == BPF::BI__builtin_load_u32_to_ptr) && "unexpected BPF builtin"); switch (BuiltinID) { @@ -10780,6 +10781,16 @@ Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); return Fn; } + case BPF::BI__builtin_load_u32_to_ptr: { + Value *BaseV = EmitScalarExpr(E->getArg(0)); + ConstantInt *C = cast(EmitScalarExpr(E->getArg(1))); + Value *OffsetV = ConstantInt::get(Int64Ty, C->getSExtValue()); + + // Built the IR for the bpf_load_u32_to_ptr intrinsic. + llvm::Function *FnLoadU32ToPtr = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_load_u32_to_ptr, {}); + return Builder.CreateCall(FnLoadU32ToPtr, {BaseV, OffsetV}); + } } } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2501,13 +2501,28 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id) && - "unexpected ARM builtin"); + BuiltinID == BPF::BI__builtin_btf_type_id || + BuiltinID == BPF::BI__builtin_load_u32_to_ptr) && + "unexpected BPF builtin"); + + // Generic checking has done basic checking against the + // signature, here only to ensure the second argument + // be a constant. + Expr *Arg; + if (BuiltinID == BPF::BI__builtin_load_u32_to_ptr) { + llvm::APSInt Value; + Arg = TheCall->getArg(1); + if (!Arg->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_load_u32_to_ptr_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + return false; + } if (checkArgCount(*this, TheCall, 2)) return true; - Expr *Arg; if (BuiltinID == BPF::BI__builtin_btf_type_id) { // The second argument needs to be a constant int llvm::APSInt Value; diff --git a/clang/test/CodeGen/builtin-bpf-load-u32-to-ptr.c b/clang/test/CodeGen/builtin-bpf-load-u32-to-ptr.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtin-bpf-load-u32-to-ptr.c @@ -0,0 +1,8 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S %s -o - | FileCheck %s + +struct t { int a; int b; }; +void *test(struct t *arg) { return __builtin_load_u32_to_ptr(arg, 4); } + +// CHECK: define dso_local i8* @test +// CHECK: call i8* @llvm.bpf.load.u32.to.ptr(i8* %{{[0-9a-z.]+}}, i64 4) diff --git a/clang/test/Sema/builtin-bpf-load-u32-to-ptr.c b/clang/test/Sema/builtin-bpf-load-u32-to-ptr.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/builtin-bpf-load-u32-to-ptr.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -x c -triple bpf-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s + +struct t { int a; int b; }; + +void *invalid1(struct t *arg) { return __builtin_load_u32_to_ptr(arg, arg->a); } // expected-error {{__builtin_load_u32_to_ptr argument 2 not a constant}} +void *invalid2(struct t *arg) { return __builtin_load_u32_to_ptr(arg + 4); } // expected-error {{too few arguments to function call, expected 2, have 1}} +void *invalid3(struct t *arg) { return __builtin_load_u32_to_ptr(arg, 4, 0); } // expected-error {{too many arguments to function call, expected 2, have 3}} +unsigned invalid4(struct t *arg) { return __builtin_load_u32_to_ptr(arg, 4); } // expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'unsigned int'}} + +void *valid1(struct t *arg) { return __builtin_load_u32_to_ptr(arg, 4); } diff --git a/llvm/include/llvm/IR/IntrinsicsBPF.td b/llvm/include/llvm/IR/IntrinsicsBPF.td --- a/llvm/include/llvm/IR/IntrinsicsBPF.td +++ b/llvm/include/llvm/IR/IntrinsicsBPF.td @@ -26,4 +26,6 @@ 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], [IntrNoMem]>; + def int_bpf_load_u32_to_ptr : GCCBuiltin<"__builtin_bpf_load_u32_to_ptr">, + Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_i64_ty], [IntrReadMem]>; }