brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.9 KiB · a976176 Raw
189 lines · cpp
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-exception6//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"16#include "clang/Basic/DiagnosticSema.h"17#include "clang/Basic/TargetBuiltins.h"18#include "clang/Sema/ParsedAttr.h"19#include "clang/Sema/Sema.h"20#include "llvm/ADT/APSInt.h"21#include <optional>22 23namespace clang {24 25SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}26 27static 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 decision33  // to BPF backend to check whether the access is a34  // field access or not.35  return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||36          isa<MemberExpr>(Arg->IgnoreParens()) ||37          isa<ArraySubscriptExpr>(Arg->IgnoreParens()));38}39 40static 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 type46  // 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  if (const auto *RT = ArgType->getAsCanonical<TagType>())60    if (!RT->getDecl()->getDeclName().isEmpty())61      return true;62 63  return false;64}65 66static bool isValidPreserveEnumValueArg(Expr *Arg) {67  QualType ArgType = Arg->getType();68  if (ArgType->getAsPlaceholderType())69    return false;70 71  // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type72  // format:73  //   __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,74  //                                 flag);75  const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());76  if (!UO)77    return false;78 79  const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());80  if (!CE)81    return false;82  if (CE->getCastKind() != CK_IntegralToPointer &&83      CE->getCastKind() != CK_NullToPointer)84    return false;85 86  // The integer must be from an EnumConstantDecl.87  const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());88  if (!DR)89    return false;90 91  const EnumConstantDecl *Enumerator =92      dyn_cast<EnumConstantDecl>(DR->getDecl());93  if (!Enumerator)94    return false;95 96  // The type must be EnumType.97  const auto *ED = ArgType->getAsEnumDecl();98  if (!ED)99    return false;100 101  // The enum value must be supported.102  return llvm::is_contained(ED->enumerators(), Enumerator);103}104 105bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,106                                          CallExpr *TheCall) {107  assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||108          BuiltinID == BPF::BI__builtin_btf_type_id ||109          BuiltinID == BPF::BI__builtin_preserve_type_info ||110          BuiltinID == BPF::BI__builtin_preserve_enum_value) &&111         "unexpected BPF builtin");112  ASTContext &Context = getASTContext();113  if (SemaRef.checkArgCount(TheCall, 2))114    return true;115 116  // The second argument needs to be a constant int117  Expr *Arg = TheCall->getArg(1);118  std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);119  diag::kind kind;120  if (!Value) {121    if (BuiltinID == BPF::BI__builtin_preserve_field_info)122      kind = diag::err_preserve_field_info_not_const;123    else if (BuiltinID == BPF::BI__builtin_btf_type_id)124      kind = diag::err_btf_type_id_not_const;125    else if (BuiltinID == BPF::BI__builtin_preserve_type_info)126      kind = diag::err_preserve_type_info_not_const;127    else128      kind = diag::err_preserve_enum_value_not_const;129    Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();130    return true;131  }132 133  // The first argument134  Arg = TheCall->getArg(0);135  bool InvalidArg = false;136  bool ReturnUnsignedInt = true;137  if (BuiltinID == BPF::BI__builtin_preserve_field_info) {138    if (!isValidPreserveFieldInfoArg(Arg)) {139      InvalidArg = true;140      kind = diag::err_preserve_field_info_not_field;141    }142  } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {143    if (!isValidPreserveTypeInfoArg(Arg)) {144      InvalidArg = true;145      kind = diag::err_preserve_type_info_invalid;146    }147  } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {148    if (!isValidPreserveEnumValueArg(Arg)) {149      InvalidArg = true;150      kind = diag::err_preserve_enum_value_invalid;151    }152    ReturnUnsignedInt = false;153  } else if (BuiltinID == BPF::BI__builtin_btf_type_id) {154    ReturnUnsignedInt = false;155  }156 157  if (InvalidArg) {158    Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();159    return true;160  }161 162  if (ReturnUnsignedInt)163    TheCall->setType(Context.UnsignedIntTy);164  else165    TheCall->setType(Context.UnsignedLongTy);166  return false;167}168 169void SemaBPF::handlePreserveAIRecord(RecordDecl *RD) {170  // Add preserve_access_index attribute to all fields and inner records.171  for (auto *D : RD->decls()) {172    if (D->hasAttr<BPFPreserveAccessIndexAttr>())173      continue;174 175    D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(getASTContext()));176    if (auto *Rec = dyn_cast<RecordDecl>(D))177      handlePreserveAIRecord(Rec);178  }179}180 181void SemaBPF::handlePreserveAccessIndexAttr(Decl *D, const ParsedAttr &AL) {182  auto *Rec = cast<RecordDecl>(D);183  handlePreserveAIRecord(Rec);184  Rec->addAttr(::new (getASTContext())185                   BPFPreserveAccessIndexAttr(getASTContext(), AL));186}187 188} // namespace clang189