brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.0 KiB · 74ec986 Raw
682 lines · cpp
1//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//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#include "Context.h"10#include "Boolean.h"11#include "ByteCodeEmitter.h"12#include "Compiler.h"13#include "EvalEmitter.h"14#include "Integral.h"15#include "InterpFrame.h"16#include "InterpHelpers.h"17#include "InterpStack.h"18#include "Pointer.h"19#include "PrimType.h"20#include "Program.h"21#include "clang/AST/ASTLambda.h"22#include "clang/AST/Expr.h"23#include "clang/Basic/TargetInfo.h"24 25using namespace clang;26using namespace clang::interp;27 28Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {29  this->ShortWidth = Ctx.getTargetInfo().getShortWidth();30  this->IntWidth = Ctx.getTargetInfo().getIntWidth();31  this->LongWidth = Ctx.getTargetInfo().getLongWidth();32  this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();33  assert(Ctx.getTargetInfo().getCharWidth() == 8 &&34         "We're assuming 8 bit chars");35}36 37Context::~Context() {}38 39bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {40  assert(Stk.empty());41 42  // Get a function handle.43  const Function *Func = getOrCreateFunction(FD);44  if (!Func)45    return false;46 47  // Compile the function.48  Compiler<ByteCodeEmitter>(*this, *P).compileFunc(49      FD, const_cast<Function *>(Func));50 51  if (!Func->isValid())52    return false;53 54  ++EvalID;55  // And run it.56  return Run(Parent, Func);57}58 59void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,60                                                 const FunctionDecl *FD) {61  assert(Stk.empty());62  ++EvalID;63  size_t StackSizeBefore = Stk.size();64  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);65 66  if (!C.interpretCall(FD, E)) {67    C.cleanup();68    Stk.clearTo(StackSizeBefore);69  }70}71 72bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {73  ++EvalID;74  bool Recursing = !Stk.empty();75  size_t StackSizeBefore = Stk.size();76  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);77 78  auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());79 80  if (Res.isInvalid()) {81    C.cleanup();82    Stk.clearTo(StackSizeBefore);83    return false;84  }85 86  if (!Recursing) {87    // We *can* actually get here with a non-empty stack, since88    // things like InterpState::noteSideEffect() exist.89    C.cleanup();90#ifndef NDEBUG91    // Make sure we don't rely on some value being still alive in92    // InterpStack memory.93    Stk.clearTo(StackSizeBefore);94#endif95  }96 97  Result = Res.stealAPValue();98 99  return true;100}101 102bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,103                       ConstantExprKind Kind) {104  ++EvalID;105  bool Recursing = !Stk.empty();106  size_t StackSizeBefore = Stk.size();107  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);108 109  auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,110                             /*DestroyToplevelScope=*/true);111  if (Res.isInvalid()) {112    C.cleanup();113    Stk.clearTo(StackSizeBefore);114    return false;115  }116 117  if (!Recursing) {118    assert(Stk.empty());119    C.cleanup();120#ifndef NDEBUG121    // Make sure we don't rely on some value being still alive in122    // InterpStack memory.123    Stk.clearTo(StackSizeBefore);124#endif125  }126 127  Result = Res.stealAPValue();128  return true;129}130 131bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,132                                    const Expr *Init, APValue &Result) {133  ++EvalID;134  bool Recursing = !Stk.empty();135  size_t StackSizeBefore = Stk.size();136  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);137 138  bool CheckGlobalInitialized =139      shouldBeGloballyIndexed(VD) &&140      (VD->getType()->isRecordType() || VD->getType()->isArrayType());141  auto Res = C.interpretDecl(VD, Init, CheckGlobalInitialized);142  if (Res.isInvalid()) {143    C.cleanup();144    Stk.clearTo(StackSizeBefore);145 146    return false;147  }148 149  if (!Recursing) {150    assert(Stk.empty());151    C.cleanup();152#ifndef NDEBUG153    // Make sure we don't rely on some value being still alive in154    // InterpStack memory.155    Stk.clearTo(StackSizeBefore);156#endif157  }158 159  Result = Res.stealAPValue();160  return true;161}162 163template <typename ResultT>164bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,165                                 const Expr *PtrExpr, ResultT &Result) {166  assert(Stk.empty());167  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);168 169  // Evaluate size value.170  APValue SizeValue;171  if (!evaluateAsRValue(Parent, SizeExpr, SizeValue))172    return false;173 174  if (!SizeValue.isInt())175    return false;176  uint64_t Size = SizeValue.getInt().getZExtValue();177 178  auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {179    if (Size == 0) {180      if constexpr (std::is_same_v<ResultT, APValue>)181        Result = APValue(APValue::UninitArray{}, 0, 0);182      return true;183    }184 185    if (!Ptr.isLive() || !Ptr.getFieldDesc()->isPrimitiveArray())186      return false;187 188    // Must be char.189    if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)190      return false;191 192    if (Size > Ptr.getNumElems()) {193      Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;194      Size = Ptr.getNumElems();195    }196 197    if constexpr (std::is_same_v<ResultT, APValue>) {198      QualType CharTy = PtrExpr->getType()->getPointeeType();199      Result = APValue(APValue::UninitArray{}, Size, Size);200      for (uint64_t I = 0; I != Size; ++I) {201        if (std::optional<APValue> ElemVal =202                Ptr.atIndex(I).toRValue(*this, CharTy))203          Result.getArrayInitializedElt(I) = *ElemVal;204        else205          return false;206      }207    } else {208      assert((std::is_same_v<ResultT, std::string>));209      if (Size < Result.max_size())210        Result.resize(Size);211      Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);212    }213 214    return true;215  });216 217  if (PtrRes.isInvalid()) {218    C.cleanup();219    Stk.clear();220    return false;221  }222 223  return true;224}225 226bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,227                                const Expr *PtrExpr, APValue &Result) {228  assert(SizeExpr);229  assert(PtrExpr);230 231  return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);232}233 234bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,235                                const Expr *PtrExpr, std::string &Result) {236  assert(SizeExpr);237  assert(PtrExpr);238 239  return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);240}241 242bool Context::evaluateString(State &Parent, const Expr *E,243                             std::string &Result) {244  assert(Stk.empty());245  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);246 247  auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {248    const Descriptor *FieldDesc = Ptr.getFieldDesc();249    if (!FieldDesc->isPrimitiveArray())250      return false;251 252    if (!Ptr.isConst())253      return false;254 255    unsigned N = Ptr.getNumElems();256 257    if (Ptr.elemSize() == 1 /* bytes */) {258      const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress());259      unsigned Length = strnlen(Chars, N);260      // Wasn't null terminated.261      if (N == Length)262        return false;263      Result.assign(Chars, Length);264      return true;265    }266 267    PrimType ElemT = FieldDesc->getPrimType();268    for (unsigned I = Ptr.getIndex(); I != N; ++I) {269      INT_TYPE_SWITCH(ElemT, {270        auto Elem = Ptr.elem<T>(I);271        if (Elem.isZero())272          return true;273        Result.push_back(static_cast<char>(Elem));274      });275    }276    // We didn't find a 0 byte.277    return false;278  });279 280  if (PtrRes.isInvalid()) {281    C.cleanup();282    Stk.clear();283    return false;284  }285  return true;286}287 288bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) {289  assert(Stk.empty());290  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);291 292  auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {293    const Descriptor *FieldDesc = Ptr.getFieldDesc();294    if (!FieldDesc->isPrimitiveArray())295      return false;296 297    if (Ptr.isDummy() || Ptr.isUnknownSizeArray())298      return false;299 300    unsigned N = Ptr.getNumElems();301    if (Ptr.elemSize() == 1) {302      Result = strnlen(reinterpret_cast<const char *>(Ptr.getRawAddress()), N);303      return Result != N;304    }305 306    PrimType ElemT = FieldDesc->getPrimType();307    Result = 0;308    for (unsigned I = Ptr.getIndex(); I != N; ++I) {309      INT_TYPE_SWITCH(ElemT, {310        auto Elem = Ptr.elem<T>(I);311        if (Elem.isZero())312          return true;313        ++Result;314      });315    }316    // We didn't find a 0 byte.317    return false;318  });319 320  if (PtrRes.isInvalid()) {321    C.cleanup();322    Stk.clear();323    return false;324  }325  return true;326}327 328const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }329 330static PrimType integralTypeToPrimTypeS(unsigned BitWidth) {331  switch (BitWidth) {332  case 64:333    return PT_Sint64;334  case 32:335    return PT_Sint32;336  case 16:337    return PT_Sint16;338  case 8:339    return PT_Sint8;340  default:341    return PT_IntAPS;342  }343  llvm_unreachable("Unhandled BitWidth");344}345 346static PrimType integralTypeToPrimTypeU(unsigned BitWidth) {347  switch (BitWidth) {348  case 64:349    return PT_Uint64;350  case 32:351    return PT_Uint32;352  case 16:353    return PT_Uint16;354  case 8:355    return PT_Uint8;356  default:357    return PT_IntAP;358  }359  llvm_unreachable("Unhandled BitWidth");360}361 362OptPrimType Context::classify(QualType T) const {363 364  if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) {365    auto Kind = BT->getKind();366    if (Kind == BuiltinType::Bool)367      return PT_Bool;368    if (Kind == BuiltinType::NullPtr)369      return PT_Ptr;370    if (Kind == BuiltinType::BoundMember)371      return PT_MemberPtr;372 373    // Just trying to avoid the ASTContext::getIntWidth call below.374    if (Kind == BuiltinType::Short)375      return integralTypeToPrimTypeS(this->ShortWidth);376    if (Kind == BuiltinType::UShort)377      return integralTypeToPrimTypeU(this->ShortWidth);378 379    if (Kind == BuiltinType::Int)380      return integralTypeToPrimTypeS(this->IntWidth);381    if (Kind == BuiltinType::UInt)382      return integralTypeToPrimTypeU(this->IntWidth);383    if (Kind == BuiltinType::Long)384      return integralTypeToPrimTypeS(this->LongWidth);385    if (Kind == BuiltinType::ULong)386      return integralTypeToPrimTypeU(this->LongWidth);387    if (Kind == BuiltinType::LongLong)388      return integralTypeToPrimTypeS(this->LongLongWidth);389    if (Kind == BuiltinType::ULongLong)390      return integralTypeToPrimTypeU(this->LongLongWidth);391 392    if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)393      return integralTypeToPrimTypeS(8);394    if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||395        Kind == BuiltinType::Char8)396      return integralTypeToPrimTypeU(8);397 398    if (BT->isSignedInteger())399      return integralTypeToPrimTypeS(Ctx.getIntWidth(T));400    if (BT->isUnsignedInteger())401      return integralTypeToPrimTypeU(Ctx.getIntWidth(T));402 403    if (BT->isFloatingPoint())404      return PT_Float;405  }406 407  if (T->isPointerOrReferenceType())408    return PT_Ptr;409 410  if (T->isMemberPointerType())411    return PT_MemberPtr;412 413  if (const auto *BT = T->getAs<BitIntType>()) {414    if (BT->isSigned())415      return integralTypeToPrimTypeS(BT->getNumBits());416    return integralTypeToPrimTypeU(BT->getNumBits());417  }418 419  if (const auto *D = T->getAsEnumDecl()) {420    if (!D->isComplete())421      return std::nullopt;422    return classify(D->getIntegerType());423  }424 425  if (const auto *AT = T->getAs<AtomicType>())426    return classify(AT->getValueType());427 428  if (const auto *DT = dyn_cast<DecltypeType>(T))429    return classify(DT->getUnderlyingType());430 431  if (T->isObjCObjectPointerType() || T->isBlockPointerType())432    return PT_Ptr;433 434  if (T->isFixedPointType())435    return PT_FixedPoint;436 437  // Vector and complex types get here.438  return std::nullopt;439}440 441unsigned Context::getCharBit() const {442  return Ctx.getTargetInfo().getCharWidth();443}444 445/// Simple wrapper around getFloatTypeSemantics() to make code a446/// little shorter.447const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {448  return Ctx.getFloatTypeSemantics(T);449}450 451bool Context::Run(State &Parent, const Function *Func) {452  InterpState State(Parent, *P, Stk, *this, Func);453  if (Interpret(State)) {454    assert(Stk.empty());455    return true;456  }457  Stk.clear();458  return false;459}460 461// TODO: Virtual bases?462const CXXMethodDecl *463Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,464                               const CXXRecordDecl *StaticDecl,465                               const CXXMethodDecl *InitialFunction) const {466  assert(DynamicDecl);467  assert(StaticDecl);468  assert(InitialFunction);469 470  const CXXRecordDecl *CurRecord = DynamicDecl;471  const CXXMethodDecl *FoundFunction = InitialFunction;472  for (;;) {473    const CXXMethodDecl *Overrider =474        FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);475    if (Overrider)476      return Overrider;477 478    // Common case of only one base class.479    if (CurRecord->getNumBases() == 1) {480      CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();481      continue;482    }483 484    // Otherwise, go to the base class that will lead to the StaticDecl.485    for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {486      const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();487      if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {488        CurRecord = Base;489        break;490      }491    }492  }493 494  llvm_unreachable(495      "Couldn't find an overriding function in the class hierarchy?");496  return nullptr;497}498 499const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) {500  assert(FuncDecl);501  if (const Function *Func = P->getFunction(FuncDecl))502    return Func;503 504  // Manually created functions that haven't been assigned proper505  // parameters yet.506  if (!FuncDecl->param_empty() && !FuncDecl->param_begin())507    return nullptr;508 509  bool IsLambdaStaticInvoker = false;510  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);511      MD && MD->isLambdaStaticInvoker()) {512    // For a lambda static invoker, we might have to pick a specialized513    // version if the lambda is generic. In that case, the picked function514    // will *NOT* be a static invoker anymore. However, it will still515    // be a non-static member function, this (usually) requiring an516    // instance pointer. We suppress that later in this function.517    IsLambdaStaticInvoker = true;518  }519  // Set up argument indices.520  unsigned ParamOffset = 0;521  SmallVector<PrimType, 8> ParamTypes;522  SmallVector<unsigned, 8> ParamOffsets;523  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;524 525  // If the return is not a primitive, a pointer to the storage where the526  // value is initialized in is passed as the first argument. See 'RVO'527  // elsewhere in the code.528  QualType Ty = FuncDecl->getReturnType();529  bool HasRVO = false;530  if (!Ty->isVoidType() && !canClassify(Ty)) {531    HasRVO = true;532    ParamTypes.push_back(PT_Ptr);533    ParamOffsets.push_back(ParamOffset);534    ParamOffset += align(primSize(PT_Ptr));535  }536 537  // If the function decl is a member decl, the next parameter is538  // the 'this' pointer. This parameter is pop()ed from the539  // InterpStack when calling the function.540  bool HasThisPointer = false;541  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {542    if (!IsLambdaStaticInvoker) {543      HasThisPointer = MD->isInstance();544      if (MD->isImplicitObjectMemberFunction()) {545        ParamTypes.push_back(PT_Ptr);546        ParamOffsets.push_back(ParamOffset);547        ParamOffset += align(primSize(PT_Ptr));548      }549    }550 551    if (isLambdaCallOperator(MD)) {552      // The parent record needs to be complete, we need to know about all553      // the lambda captures.554      if (!MD->getParent()->isCompleteDefinition())555        return nullptr;556      llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;557      FieldDecl *LTC;558 559      MD->getParent()->getCaptureFields(LC, LTC);560 561      if (MD->isStatic() && !LC.empty()) {562        // Static lambdas cannot have any captures. If this one does,563        // it has already been diagnosed and we can only ignore it.564        return nullptr;565      }566    }567  }568 569  // Assign descriptors to all parameters.570  // Composite objects are lowered to pointers.571  const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>();572  for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) {573    bool IsConst = PD->getType().isConstQualified();574    bool IsVolatile = PD->getType().isVolatileQualified();575 576    if (!getASTContext().hasSameType(PD->getType(),577                                     FuncProto->getParamType(ParamIndex)))578      return nullptr;579 580    OptPrimType T = classify(PD->getType());581    PrimType PT = T.value_or(PT_Ptr);582    Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,583                                           IsConst, /*IsTemporary=*/false,584                                           /*IsMutable=*/false, IsVolatile);585 586    ParamDescriptors.insert({ParamOffset, {PT, Desc}});587    ParamOffsets.push_back(ParamOffset);588    ParamOffset += align(primSize(PT));589    ParamTypes.push_back(PT);590  }591 592  // Create a handle over the emitted code.593  assert(!P->getFunction(FuncDecl));594  const Function *Func = P->createFunction(595      FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),596      std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);597  return Func;598}599 600const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) {601  const BlockDecl *BD = E->getBlockDecl();602  // Set up argument indices.603  unsigned ParamOffset = 0;604  SmallVector<PrimType, 8> ParamTypes;605  SmallVector<unsigned, 8> ParamOffsets;606  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;607 608  // Assign descriptors to all parameters.609  // Composite objects are lowered to pointers.610  for (const ParmVarDecl *PD : BD->parameters()) {611    bool IsConst = PD->getType().isConstQualified();612    bool IsVolatile = PD->getType().isVolatileQualified();613 614    OptPrimType T = classify(PD->getType());615    PrimType PT = T.value_or(PT_Ptr);616    Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,617                                           IsConst, /*IsTemporary=*/false,618                                           /*IsMutable=*/false, IsVolatile);619    ParamDescriptors.insert({ParamOffset, {PT, Desc}});620    ParamOffsets.push_back(ParamOffset);621    ParamOffset += align(primSize(PT));622    ParamTypes.push_back(PT);623  }624 625  if (BD->hasCaptures())626    return nullptr;627 628  // Create a handle over the emitted code.629  Function *Func =630      P->createFunction(E, ParamOffset, std::move(ParamTypes),631                        std::move(ParamDescriptors), std::move(ParamOffsets),632                        /*HasThisPointer=*/false, /*HasRVO=*/false,633                        /*IsLambdaStaticInvoker=*/false);634 635  assert(Func);636  Func->setDefined(true);637  // We don't compile the BlockDecl code at all right now.638  Func->setIsFullyCompiled(true);639  return Func;640}641 642unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,643                                    const RecordDecl *DerivedDecl) const {644  assert(BaseDecl);645  assert(DerivedDecl);646  const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);647  const RecordDecl *CurDecl = DerivedDecl;648  const Record *CurRecord = P->getOrCreateRecord(CurDecl);649  assert(CurDecl && FinalDecl);650 651  unsigned OffsetSum = 0;652  for (;;) {653    assert(CurRecord->getNumBases() > 0);654    // One level up655    for (const Record::Base &B : CurRecord->bases()) {656      const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);657 658      if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {659        OffsetSum += B.Offset;660        CurRecord = B.R;661        CurDecl = BaseDecl;662        break;663      }664    }665    if (CurDecl == FinalDecl)666      break;667  }668 669  assert(OffsetSum > 0);670  return OffsetSum;671}672 673const Record *Context::getRecord(const RecordDecl *D) const {674  return P->getOrCreateRecord(D);675}676 677bool Context::isUnevaluatedBuiltin(unsigned ID) {678  return ID == Builtin::BI__builtin_classify_type ||679         ID == Builtin::BI__builtin_os_log_format_buffer_size ||680         ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;681}682