clang  20.0.0git
SemaBPF.cpp
Go to the documentation of this file.
1 //===------ SemaBPF.cpp ---------- BPF target-specific routines -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements semantic analysis functions specific to BPF.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/Sema/SemaBPF.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/Type.h"
18 #include "clang/Sema/ParsedAttr.h"
19 #include "clang/Sema/Sema.h"
20 #include "llvm/ADT/APSInt.h"
21 #include <optional>
22 
23 namespace clang {
24 
26 
27 static bool isValidPreserveFieldInfoArg(Expr *Arg) {
28  if (Arg->getType()->getAsPlaceholderType())
29  return false;
30 
31  // The first argument needs to be a record field access.
32  // If it is an array element access, we delay decision
33  // to BPF backend to check whether the access is a
34  // field access or not.
35  return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||
36  isa<MemberExpr>(Arg->IgnoreParens()) ||
37  isa<ArraySubscriptExpr>(Arg->IgnoreParens()));
38 }
39 
40 static bool isValidPreserveTypeInfoArg(Expr *Arg) {
41  QualType ArgType = Arg->getType();
42  if (ArgType->getAsPlaceholderType())
43  return false;
44 
45  // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type
46  // format:
47  // 1. __builtin_preserve_type_info(*(<type> *)0, flag);
48  // 2. <type> var;
49  // __builtin_preserve_type_info(var, flag);
50  if (!isa<DeclRefExpr>(Arg->IgnoreParens()) &&
51  !isa<UnaryOperator>(Arg->IgnoreParens()))
52  return false;
53 
54  // Typedef type.
55  if (ArgType->getAs<TypedefType>())
56  return true;
57 
58  // Record type or Enum type.
59  const Type *Ty = ArgType->getUnqualifiedDesugaredType();
60  if (const auto *RT = Ty->getAs<RecordType>()) {
61  if (!RT->getDecl()->getDeclName().isEmpty())
62  return true;
63  } else if (const auto *ET = Ty->getAs<EnumType>()) {
64  if (!ET->getDecl()->getDeclName().isEmpty())
65  return true;
66  }
67 
68  return false;
69 }
70 
71 static bool isValidPreserveEnumValueArg(Expr *Arg) {
72  QualType ArgType = Arg->getType();
73  if (ArgType->getAsPlaceholderType())
74  return false;
75 
76  // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type
77  // format:
78  // __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,
79  // flag);
80  const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());
81  if (!UO)
82  return false;
83 
84  const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());
85  if (!CE)
86  return false;
87  if (CE->getCastKind() != CK_IntegralToPointer &&
88  CE->getCastKind() != CK_NullToPointer)
89  return false;
90 
91  // The integer must be from an EnumConstantDecl.
92  const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());
93  if (!DR)
94  return false;
95 
96  const EnumConstantDecl *Enumerator =
97  dyn_cast<EnumConstantDecl>(DR->getDecl());
98  if (!Enumerator)
99  return false;
100 
101  // The type must be EnumType.
102  const Type *Ty = ArgType->getUnqualifiedDesugaredType();
103  const auto *ET = Ty->getAs<EnumType>();
104  if (!ET)
105  return false;
106 
107  // The enum value must be supported.
108  return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator);
109 }
110 
111 bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
112  CallExpr *TheCall) {
113  assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
114  BuiltinID == BPF::BI__builtin_btf_type_id ||
115  BuiltinID == BPF::BI__builtin_preserve_type_info ||
116  BuiltinID == BPF::BI__builtin_preserve_enum_value) &&
117  "unexpected BPF builtin");
118  ASTContext &Context = getASTContext();
119  if (SemaRef.checkArgCount(TheCall, 2))
120  return true;
121 
122  // The second argument needs to be a constant int
123  Expr *Arg = TheCall->getArg(1);
124  std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
126  if (!Value) {
127  if (BuiltinID == BPF::BI__builtin_preserve_field_info)
128  kind = diag::err_preserve_field_info_not_const;
129  else if (BuiltinID == BPF::BI__builtin_btf_type_id)
130  kind = diag::err_btf_type_id_not_const;
131  else if (BuiltinID == BPF::BI__builtin_preserve_type_info)
132  kind = diag::err_preserve_type_info_not_const;
133  else
134  kind = diag::err_preserve_enum_value_not_const;
135  Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();
136  return true;
137  }
138 
139  // The first argument
140  Arg = TheCall->getArg(0);
141  bool InvalidArg = false;
142  bool ReturnUnsignedInt = true;
143  if (BuiltinID == BPF::BI__builtin_preserve_field_info) {
144  if (!isValidPreserveFieldInfoArg(Arg)) {
145  InvalidArg = true;
146  kind = diag::err_preserve_field_info_not_field;
147  }
148  } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {
149  if (!isValidPreserveTypeInfoArg(Arg)) {
150  InvalidArg = true;
151  kind = diag::err_preserve_type_info_invalid;
152  }
153  } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {
154  if (!isValidPreserveEnumValueArg(Arg)) {
155  InvalidArg = true;
156  kind = diag::err_preserve_enum_value_invalid;
157  }
158  ReturnUnsignedInt = false;
159  } else if (BuiltinID == BPF::BI__builtin_btf_type_id) {
160  ReturnUnsignedInt = false;
161  }
162 
163  if (InvalidArg) {
164  Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();
165  return true;
166  }
167 
168  if (ReturnUnsignedInt)
169  TheCall->setType(Context.UnsignedIntTy);
170  else
171  TheCall->setType(Context.UnsignedLongTy);
172  return false;
173 }
174 
176  // Add preserve_access_index attribute to all fields and inner records.
177  for (auto *D : RD->decls()) {
178  if (D->hasAttr<BPFPreserveAccessIndexAttr>())
179  continue;
180 
181  D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext()));
182  if (auto *Rec = dyn_cast<RecordDecl>(D))
184  }
185 }
186 
188  auto *Rec = cast<RecordDecl>(D);
190  Rec->addAttr(::new (getASTContext())
191  BPFPreserveAccessIndexAttr(getASTContext(), AL));
192 }
193 
194 } // namespace clang
const Decl * D
This file declares semantic analysis functions specific to BPF.
Enumerates target-specific builtins in their own namespaces within namespace clang.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2882
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3073
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2350
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
An instance of this object exists for each enum constant that is defined.
Definition: Decl.h:3275
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:6001
This represents one expression.
Definition: Expr.h:110
void setType(QualType t)
Definition: Expr.h:143
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3118
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition: Expr.h:444
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc=nullptr) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
QualType getType() const
Definition: Expr.h:142
ParsedAttr - Represents a syntactic attribute.
Definition: ParsedAttr.h:129
A (possibly-)qualified type.
Definition: Type.h:941
Represents a struct/union/class.
Definition: Decl.h:4146
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5975
void handlePreserveAIRecord(RecordDecl *RD)
Definition: SemaBPF.cpp:175
SemaBPF(Sema &S)
Definition: SemaBPF.cpp:25
void handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaBPF.cpp:187
bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition: SemaBPF.cpp:111
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: SemaBase.cpp:64
ASTContext & getASTContext() const
Definition: SemaBase.cpp:9
Sema & SemaRef
Definition: SemaBase.h:40
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:493
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:338
The base class of the type hierarchy.
Definition: Type.h:1829
const BuiltinType * getAsPlaceholderType() const
Definition: Type.h:8329
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8568
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition: Type.cpp:605
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:65
The JSON file list parser is used to communicate input to InstallAPI.
static bool isValidPreserveFieldInfoArg(Expr *Arg)
Definition: SemaBPF.cpp:27
@ OK_BitField
A bitfield object is a bitfield on a C or C++ record.
Definition: Specifiers.h:154
static bool isValidPreserveEnumValueArg(Expr *Arg)
Definition: SemaBPF.cpp:71
static bool isValidPreserveTypeInfoArg(Expr *Arg)
Definition: SemaBPF.cpp:40