yonghong-song updated this revision to Diff 280027.
yonghong-song retitled this revision from "[clang][BPF] support expr with
typedef/record type for FIELD_EXISTENCE reloc" to "[clang][BPF] support expr
with typedef/record type for TYPE_EXISTENCE reloc".
yonghong-song edited the summary of this revision.
yonghong-song added a comment.
use a different reloc type TYPE_EXISTENCE (defined in
llvm/lib/Target/BPF/BPFCORE.h) instead of old FIELD_EXISTENCE. This will
simplify libbpf processing.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D83242/new/
https://reviews.llvm.org/D83242
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/TargetInfo.h
clang/lib/Basic/TargetInfo.cpp
clang/lib/Basic/Targets/BPF.h
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/SemaChecking.cpp
clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c
clang/test/Sema/builtins-bpf.c
Index: clang/test/Sema/builtins-bpf.c
===================================================================
--- clang/test/Sema/builtins-bpf.c
+++ clang/test/Sema/builtins-bpf.c
@@ -1,14 +1,27 @@
// RUN: %clang_cc1 -x c -triple bpf-pc-linux-gnu -dwarf-version=4 -fsyntax-only -verify %s
-struct s { int a; int b[4]; int c:1; };
-union u { int a; int b[4]; int c:1; };
+struct s {
+ int a;
+ int b[4];
+ int c:1;
+};
+union u {
+ int a;
+ int b[4];
+ int c:1;
+};
+typedef struct {
+ int a;
+ int b;
+} __t;
+typedef int (*__f)(void);
unsigned invalid1(const int *arg) {
- return __builtin_preserve_field_info(arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 not a field access}}
+ return __builtin_preserve_field_info(arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 invalid}}
}
unsigned invalid2(const int *arg) {
- return __builtin_preserve_field_info(*arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 not a field access}}
+ return __builtin_preserve_field_info(*arg, 1); // expected-error {{__builtin_preserve_field_info argument 1 invalid}}
}
void *invalid3(struct s *arg) {
@@ -46,3 +59,25 @@
unsigned invalid11(struct s *arg, int info_kind) {
return __builtin_preserve_field_info(arg->a, info_kind); // expected-error {{__builtin_preserve_field_info argument 2 not a constant}}
}
+
+unsigned valid12() {
+ const struct s t = {};
+ return __builtin_preserve_field_info(t, 8);
+}
+
+unsigned valid13() {
+ return __builtin_preserve_field_info(*(struct s *)0, 8);
+}
+
+unsigned valid14() {
+ __t t = {};
+ return __builtin_preserve_field_info(t, 8);
+}
+
+unsigned valid15() {
+ return __builtin_preserve_field_info((const __f)0, 8);
+}
+
+unsigned invalid16(struct s *arg) {
+ return __builtin_preserve_field_info(arg->a + 2, 8); // expected-error {{__builtin_preserve_field_info argument 1 invalid}}
+}
Index: clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c
@@ -0,0 +1,33 @@
+// REQUIRES: bpf-registered-target
+// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s
+
+#define _(x, y) (__builtin_preserve_field_info((x), (y)))
+
+struct s {
+ char a;
+};
+typedef struct {
+ char a;
+} __s1;
+
+typedef int (*__func)(void);
+
+unsigned unit1() {
+ const __s1 v = {};
+ return _(v, 8) + _(*(struct s *)0, 8);
+}
+
+// CHECK: call i32 @llvm.bpf.preserve.field.info.p0s_struct.__s1s(%struct.__s1* %{{[0-9a-z]+}}, i64 8), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[CONST_S1:[0-9]+]]
+// CHECK: call i32 @llvm.bpf.preserve.field.info.p0s_struct.ss(%struct.s* null, i64 8), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S:[0-9]+]]
+
+unsigned unit2() {
+ __func f;
+ return _((__func)0, 8) + _(f, 8);
+}
+
+// CHECK: call i32 @llvm.bpf.preserve.field.info.p0f_i32f(i32 ()* null, i64 8), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF:[0-9]+]]
+// CHECK: call i32 @llvm.bpf.preserve.field.info.p0p0f_i32f(i32 ()** %{{[0-9a-z]+}}, i64 8), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF:[0-9]+]]
+
+// CHECK: ![[STRUCT_S]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s"
+// CHECK: ![[TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__func"
+// CHECK: ![[CONST_S1]] = !DIDerivedType(tag: DW_TAG_const_type
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -2564,7 +2564,7 @@
CallExpr *TheCall) {
assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
BuiltinID == BPF::BI__builtin_btf_type_id) &&
- "unexpected ARM builtin");
+ "unexpected BPF builtin");
if (checkArgCount(*this, TheCall, 2))
return true;
@@ -2583,25 +2583,49 @@
return false;
}
- // The first argument needs to be a record field access.
+ // The second argument needs to be a constant int
+ Arg = TheCall->getArg(1);
+ Optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
+ if (!Value) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const)
+ << 2 << Arg->getSourceRange();
+ return true;
+ }
+
+ // For non TYPE_EXISTENCE relocation type,
+ // the first argument needs to be a record field access.
// If it is an array element access, we delay decision
// to BPF backend to check whether the access is a
// field access or not.
+ //
+ // For TYPE_EXISTENCE relocation type, the argument type
+ // should be a typedef or a named record type.
Arg = TheCall->getArg(0);
- if (Arg->getType()->getAsPlaceholderType() ||
- (Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
- !dyn_cast<MemberExpr>(Arg->IgnoreParens()) &&
- !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens()))) {
- Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field)
- << 1 << Arg->getSourceRange();
- return true;
+ bool InvalidArg = false;
+ if (Arg->getType()->getAsPlaceholderType()) {
+ InvalidArg = true;
+ } else if (*Value != Context.getTargetInfo().getBPFCOREKindTypeExist()) {
+ if (Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
+ !dyn_cast<MemberExpr>(Arg->IgnoreParens()) &&
+ !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens())) {
+ InvalidArg = true;
+ }
+ } else {
+ if (!dyn_cast<DeclRefExpr>(Arg->IgnoreParens()) &&
+ !dyn_cast<CStyleCastExpr>(Arg->IgnoreParens()) &&
+ !dyn_cast<UnaryOperator>(Arg->IgnoreParens())) {
+ InvalidArg = true;
+ } else if (!Arg->getType()->getAs<TypedefType>()) {
+ const auto *Ty = Arg->getType()->getUnqualifiedDesugaredType();
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT || RT->getDecl()->getDeclName().isEmpty())
+ InvalidArg = true;
+ }
}
- // The second argument needs to be a constant int
- Arg = TheCall->getArg(1);
- if (!Arg->isIntegerConstantExpr(Context)) {
- Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const)
- << 2 << Arg->getSourceRange();
+ if (InvalidArg) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_invalid)
+ << 1 << Arg->getSourceRange();
return true;
}
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -10960,11 +10960,14 @@
llvm_unreachable("Unexpected BPF builtin");
case BPF::BI__builtin_preserve_field_info: {
const Expr *Arg = E->getArg(0);
+ bool IsLValue = Arg->isLValue();
bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField;
if (!getDebugInfo()) {
CGM.Error(E->getExprLoc(),
"using __builtin_preserve_field_info() without -g");
+ if (!IsLValue)
+ return EmitScalarExpr(Arg);
return IsBitField ? EmitLValue(Arg).getBitFieldPointer()
: EmitLValue(Arg).getPointer(*this);
}
@@ -10972,8 +10975,12 @@
// Enable underlying preserve_*_access_index() generation.
bool OldIsInPreservedAIRegion = IsInPreservedAIRegion;
IsInPreservedAIRegion = true;
- Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer()
- : EmitLValue(Arg).getPointer(*this);
+ Value *FieldAddr;
+ if (!IsLValue)
+ FieldAddr = EmitScalarExpr(Arg);
+ else
+ FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer()
+ : EmitLValue(Arg).getPointer(*this);
IsInPreservedAIRegion = OldIsInPreservedAIRegion;
ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
@@ -10983,7 +10990,21 @@
llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration(
&CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info,
{FieldAddr->getType()});
- return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind});
+ CallInst *Fn = Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind});
+
+ // Add debuginfo metadata to bpf_preserve_field_info intrinsic
+ // for CORE relocation type TYPE_EXISTENCE. This is
+ // used to capture the existence of a typedef or a struct/union type,
+ // for which we do not have IR intrinsics generated.
+ uint32_t TypeExistReloc =
+ getContext().getTargetInfo().getBPFCOREKindTypeExist();
+ if (C->getSExtValue() == TypeExistReloc) {
+ llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType(
+ E->getArg(0)->getType(), E->getArg(0)->getExprLoc());
+ Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo);
+ }
+
+ return Fn;
}
case BPF::BI__builtin_btf_type_id: {
Value *FieldVal = nullptr;
Index: clang/lib/Basic/Targets/BPF.h
===================================================================
--- clang/lib/Basic/Targets/BPF.h
+++ clang/lib/Basic/Targets/BPF.h
@@ -42,6 +42,7 @@
MaxAtomicPromoteWidth = 64;
MaxAtomicInlineWidth = 64;
TLSSupported = false;
+ BPFCOREKindTypeExist = 8;
}
void getTargetDefines(const LangOptions &Opts,
Index: clang/lib/Basic/TargetInfo.cpp
===================================================================
--- clang/lib/Basic/TargetInfo.cpp
+++ clang/lib/Basic/TargetInfo.cpp
@@ -116,6 +116,7 @@
IsRenderScriptTarget = false;
HasAArch64SVETypes = false;
ARMCDECoprocMask = 0;
+ BPFCOREKindTypeExist = 0;
// Default to no types using fpret.
RealTypeUsesObjCFPRet = 0;
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -220,6 +220,8 @@
unsigned ARMCDECoprocMask : 8;
+ unsigned BPFCOREKindTypeExist : 8;
+
unsigned MaxOpenCLWorkGroupSize;
// TargetInfo Constructor. Default initializes all fields.
@@ -860,6 +862,9 @@
/// as Custom Datapath.
uint32_t getARMCDECoprocMask() const { return ARMCDECoprocMask; }
+ /// For BPF targets return the CORE relocation kind FIELD_EXISTENCE.
+ uint32_t getBPFCOREKindTypeExist() const { return BPFCOREKindTypeExist; }
+
/// Returns whether the passed in string is a valid clobber in an
/// inline asm statement.
///
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10850,8 +10850,8 @@
"import %select{module|name}0 cannot be applied to a function with a definition">,
InGroup<IgnoredAttributes>;
-def err_preserve_field_info_not_field : Error<
- "__builtin_preserve_field_info argument %0 not a field access">;
+def err_preserve_field_info_invalid : Error<
+ "__builtin_preserve_field_info argument %0 invalid">;
def err_preserve_field_info_not_const: Error<
"__builtin_preserve_field_info argument %0 not a constant">;
def err_btf_type_id_not_const: Error<
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits