xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaBPF.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===------ SemaBPF.cpp ---------- BPF target-specific routines -----------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric //  This file implements semantic analysis functions specific to BPF.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaBPF.h"
14*0fca6ea1SDimitry Andric #include "clang/AST/Decl.h"
15*0fca6ea1SDimitry Andric #include "clang/AST/Type.h"
16*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h"
17*0fca6ea1SDimitry Andric #include "clang/Basic/TargetBuiltins.h"
18*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h"
19*0fca6ea1SDimitry Andric #include "clang/Sema/Sema.h"
20*0fca6ea1SDimitry Andric #include "llvm/ADT/APSInt.h"
21*0fca6ea1SDimitry Andric #include <optional>
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric namespace clang {
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}
26*0fca6ea1SDimitry Andric 
27*0fca6ea1SDimitry Andric static bool isValidPreserveFieldInfoArg(Expr *Arg) {
28*0fca6ea1SDimitry Andric   if (Arg->getType()->getAsPlaceholderType())
29*0fca6ea1SDimitry Andric     return false;
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric   // The first argument needs to be a record field access.
32*0fca6ea1SDimitry Andric   // If it is an array element access, we delay decision
33*0fca6ea1SDimitry Andric   // to BPF backend to check whether the access is a
34*0fca6ea1SDimitry Andric   // field access or not.
35*0fca6ea1SDimitry Andric   return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||
36*0fca6ea1SDimitry Andric           isa<MemberExpr>(Arg->IgnoreParens()) ||
37*0fca6ea1SDimitry Andric           isa<ArraySubscriptExpr>(Arg->IgnoreParens()));
38*0fca6ea1SDimitry Andric }
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric static bool isValidPreserveTypeInfoArg(Expr *Arg) {
41*0fca6ea1SDimitry Andric   QualType ArgType = Arg->getType();
42*0fca6ea1SDimitry Andric   if (ArgType->getAsPlaceholderType())
43*0fca6ea1SDimitry Andric     return false;
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric   // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type
46*0fca6ea1SDimitry Andric   // format:
47*0fca6ea1SDimitry Andric   //   1. __builtin_preserve_type_info(*(<type> *)0, flag);
48*0fca6ea1SDimitry Andric   //   2. <type> var;
49*0fca6ea1SDimitry Andric   //      __builtin_preserve_type_info(var, flag);
50*0fca6ea1SDimitry Andric   if (!isa<DeclRefExpr>(Arg->IgnoreParens()) &&
51*0fca6ea1SDimitry Andric       !isa<UnaryOperator>(Arg->IgnoreParens()))
52*0fca6ea1SDimitry Andric     return false;
53*0fca6ea1SDimitry Andric 
54*0fca6ea1SDimitry Andric   // Typedef type.
55*0fca6ea1SDimitry Andric   if (ArgType->getAs<TypedefType>())
56*0fca6ea1SDimitry Andric     return true;
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric   // Record type or Enum type.
59*0fca6ea1SDimitry Andric   const Type *Ty = ArgType->getUnqualifiedDesugaredType();
60*0fca6ea1SDimitry Andric   if (const auto *RT = Ty->getAs<RecordType>()) {
61*0fca6ea1SDimitry Andric     if (!RT->getDecl()->getDeclName().isEmpty())
62*0fca6ea1SDimitry Andric       return true;
63*0fca6ea1SDimitry Andric   } else if (const auto *ET = Ty->getAs<EnumType>()) {
64*0fca6ea1SDimitry Andric     if (!ET->getDecl()->getDeclName().isEmpty())
65*0fca6ea1SDimitry Andric       return true;
66*0fca6ea1SDimitry Andric   }
67*0fca6ea1SDimitry Andric 
68*0fca6ea1SDimitry Andric   return false;
69*0fca6ea1SDimitry Andric }
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric static bool isValidPreserveEnumValueArg(Expr *Arg) {
72*0fca6ea1SDimitry Andric   QualType ArgType = Arg->getType();
73*0fca6ea1SDimitry Andric   if (ArgType->getAsPlaceholderType())
74*0fca6ea1SDimitry Andric     return false;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type
77*0fca6ea1SDimitry Andric   // format:
78*0fca6ea1SDimitry Andric   //   __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,
79*0fca6ea1SDimitry Andric   //                                 flag);
80*0fca6ea1SDimitry Andric   const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());
81*0fca6ea1SDimitry Andric   if (!UO)
82*0fca6ea1SDimitry Andric     return false;
83*0fca6ea1SDimitry Andric 
84*0fca6ea1SDimitry Andric   const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());
85*0fca6ea1SDimitry Andric   if (!CE)
86*0fca6ea1SDimitry Andric     return false;
87*0fca6ea1SDimitry Andric   if (CE->getCastKind() != CK_IntegralToPointer &&
88*0fca6ea1SDimitry Andric       CE->getCastKind() != CK_NullToPointer)
89*0fca6ea1SDimitry Andric     return false;
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric   // The integer must be from an EnumConstantDecl.
92*0fca6ea1SDimitry Andric   const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());
93*0fca6ea1SDimitry Andric   if (!DR)
94*0fca6ea1SDimitry Andric     return false;
95*0fca6ea1SDimitry Andric 
96*0fca6ea1SDimitry Andric   const EnumConstantDecl *Enumerator =
97*0fca6ea1SDimitry Andric       dyn_cast<EnumConstantDecl>(DR->getDecl());
98*0fca6ea1SDimitry Andric   if (!Enumerator)
99*0fca6ea1SDimitry Andric     return false;
100*0fca6ea1SDimitry Andric 
101*0fca6ea1SDimitry Andric   // The type must be EnumType.
102*0fca6ea1SDimitry Andric   const Type *Ty = ArgType->getUnqualifiedDesugaredType();
103*0fca6ea1SDimitry Andric   const auto *ET = Ty->getAs<EnumType>();
104*0fca6ea1SDimitry Andric   if (!ET)
105*0fca6ea1SDimitry Andric     return false;
106*0fca6ea1SDimitry Andric 
107*0fca6ea1SDimitry Andric   // The enum value must be supported.
108*0fca6ea1SDimitry Andric   return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator);
109*0fca6ea1SDimitry Andric }
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
112*0fca6ea1SDimitry Andric                                           CallExpr *TheCall) {
113*0fca6ea1SDimitry Andric   assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
114*0fca6ea1SDimitry Andric           BuiltinID == BPF::BI__builtin_btf_type_id ||
115*0fca6ea1SDimitry Andric           BuiltinID == BPF::BI__builtin_preserve_type_info ||
116*0fca6ea1SDimitry Andric           BuiltinID == BPF::BI__builtin_preserve_enum_value) &&
117*0fca6ea1SDimitry Andric          "unexpected BPF builtin");
118*0fca6ea1SDimitry Andric   ASTContext &Context = getASTContext();
119*0fca6ea1SDimitry Andric   if (SemaRef.checkArgCount(TheCall, 2))
120*0fca6ea1SDimitry Andric     return true;
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric   // The second argument needs to be a constant int
123*0fca6ea1SDimitry Andric   Expr *Arg = TheCall->getArg(1);
124*0fca6ea1SDimitry Andric   std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
125*0fca6ea1SDimitry Andric   diag::kind kind;
126*0fca6ea1SDimitry Andric   if (!Value) {
127*0fca6ea1SDimitry Andric     if (BuiltinID == BPF::BI__builtin_preserve_field_info)
128*0fca6ea1SDimitry Andric       kind = diag::err_preserve_field_info_not_const;
129*0fca6ea1SDimitry Andric     else if (BuiltinID == BPF::BI__builtin_btf_type_id)
130*0fca6ea1SDimitry Andric       kind = diag::err_btf_type_id_not_const;
131*0fca6ea1SDimitry Andric     else if (BuiltinID == BPF::BI__builtin_preserve_type_info)
132*0fca6ea1SDimitry Andric       kind = diag::err_preserve_type_info_not_const;
133*0fca6ea1SDimitry Andric     else
134*0fca6ea1SDimitry Andric       kind = diag::err_preserve_enum_value_not_const;
135*0fca6ea1SDimitry Andric     Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();
136*0fca6ea1SDimitry Andric     return true;
137*0fca6ea1SDimitry Andric   }
138*0fca6ea1SDimitry Andric 
139*0fca6ea1SDimitry Andric   // The first argument
140*0fca6ea1SDimitry Andric   Arg = TheCall->getArg(0);
141*0fca6ea1SDimitry Andric   bool InvalidArg = false;
142*0fca6ea1SDimitry Andric   bool ReturnUnsignedInt = true;
143*0fca6ea1SDimitry Andric   if (BuiltinID == BPF::BI__builtin_preserve_field_info) {
144*0fca6ea1SDimitry Andric     if (!isValidPreserveFieldInfoArg(Arg)) {
145*0fca6ea1SDimitry Andric       InvalidArg = true;
146*0fca6ea1SDimitry Andric       kind = diag::err_preserve_field_info_not_field;
147*0fca6ea1SDimitry Andric     }
148*0fca6ea1SDimitry Andric   } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {
149*0fca6ea1SDimitry Andric     if (!isValidPreserveTypeInfoArg(Arg)) {
150*0fca6ea1SDimitry Andric       InvalidArg = true;
151*0fca6ea1SDimitry Andric       kind = diag::err_preserve_type_info_invalid;
152*0fca6ea1SDimitry Andric     }
153*0fca6ea1SDimitry Andric   } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {
154*0fca6ea1SDimitry Andric     if (!isValidPreserveEnumValueArg(Arg)) {
155*0fca6ea1SDimitry Andric       InvalidArg = true;
156*0fca6ea1SDimitry Andric       kind = diag::err_preserve_enum_value_invalid;
157*0fca6ea1SDimitry Andric     }
158*0fca6ea1SDimitry Andric     ReturnUnsignedInt = false;
159*0fca6ea1SDimitry Andric   } else if (BuiltinID == BPF::BI__builtin_btf_type_id) {
160*0fca6ea1SDimitry Andric     ReturnUnsignedInt = false;
161*0fca6ea1SDimitry Andric   }
162*0fca6ea1SDimitry Andric 
163*0fca6ea1SDimitry Andric   if (InvalidArg) {
164*0fca6ea1SDimitry Andric     Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();
165*0fca6ea1SDimitry Andric     return true;
166*0fca6ea1SDimitry Andric   }
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric   if (ReturnUnsignedInt)
169*0fca6ea1SDimitry Andric     TheCall->setType(Context.UnsignedIntTy);
170*0fca6ea1SDimitry Andric   else
171*0fca6ea1SDimitry Andric     TheCall->setType(Context.UnsignedLongTy);
172*0fca6ea1SDimitry Andric   return false;
173*0fca6ea1SDimitry Andric }
174*0fca6ea1SDimitry Andric 
175*0fca6ea1SDimitry Andric void SemaBPF::handlePreserveAIRecord(RecordDecl *RD) {
176*0fca6ea1SDimitry Andric   // Add preserve_access_index attribute to all fields and inner records.
177*0fca6ea1SDimitry Andric   for (auto *D : RD->decls()) {
178*0fca6ea1SDimitry Andric     if (D->hasAttr<BPFPreserveAccessIndexAttr>())
179*0fca6ea1SDimitry Andric       continue;
180*0fca6ea1SDimitry Andric 
181*0fca6ea1SDimitry Andric     D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext()));
182*0fca6ea1SDimitry Andric     if (auto *Rec = dyn_cast<RecordDecl>(D))
183*0fca6ea1SDimitry Andric       handlePreserveAIRecord(Rec);
184*0fca6ea1SDimitry Andric   }
185*0fca6ea1SDimitry Andric }
186*0fca6ea1SDimitry Andric 
187*0fca6ea1SDimitry Andric void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) {
188*0fca6ea1SDimitry Andric   auto *Rec = cast<RecordDecl>(D);
189*0fca6ea1SDimitry Andric   handlePreserveAIRecord(Rec);
190*0fca6ea1SDimitry Andric   Rec->addAttr(::new (getASTContext())
191*0fca6ea1SDimitry Andric                    BPFPreserveAccessIndexAttr(getASTContext(), AL));
192*0fca6ea1SDimitry Andric }
193*0fca6ea1SDimitry Andric 
194*0fca6ea1SDimitry Andric } // namespace clang
195