brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · ed74376 Raw
259 lines · cpp
1//===--- ByteCodeEmitter.cpp - Instruction emitter for the 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 "ByteCodeEmitter.h"10#include "Context.h"11#include "Floating.h"12#include "IntegralAP.h"13#include "Opcode.h"14#include "Program.h"15#include "clang/AST/ASTLambda.h"16#include "clang/AST/Attr.h"17#include "clang/AST/DeclCXX.h"18#include <type_traits>19 20using namespace clang;21using namespace clang::interp;22 23void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl,24                                  Function *Func) {25  assert(FuncDecl);26  assert(Func);27  assert(FuncDecl->isThisDeclarationADefinition());28 29  // Manually created functions that haven't been assigned proper30  // parameters yet.31  if (!FuncDecl->param_empty() && !FuncDecl->param_begin())32    return;33 34  // Set up lambda captures.35  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);36      MD && isLambdaCallOperator(MD)) {37    // Set up lambda capture to closure record field mapping.38    const Record *R = P.getOrCreateRecord(MD->getParent());39    assert(R);40    llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;41    FieldDecl *LTC;42 43    MD->getParent()->getCaptureFields(LC, LTC);44 45    for (auto Cap : LC) {46      unsigned Offset = R->getField(Cap.second)->Offset;47      this->LambdaCaptures[Cap.first] = {48          Offset, Cap.second->getType()->isReferenceType()};49    }50    if (LTC) {51      QualType CaptureType = R->getField(LTC)->Decl->getType();52      this->LambdaThisCapture = {R->getField(LTC)->Offset,53                                 CaptureType->isPointerOrReferenceType()};54    }55  }56 57  // Register parameters with their offset.58  unsigned ParamIndex = 0;59  unsigned Drop = Func->hasRVO() +60                  (Func->hasThisPointer() && !Func->isThisPointerExplicit());61  for (auto ParamOffset : llvm::drop_begin(Func->ParamOffsets, Drop)) {62    const ParmVarDecl *PD = FuncDecl->parameters()[ParamIndex];63    OptPrimType T = Ctx.classify(PD->getType());64    this->Params.insert({PD, {ParamOffset, T != std::nullopt}});65    ++ParamIndex;66  }67 68  Func->setDefined(true);69 70  // Lambda static invokers are a special case that we emit custom code for.71  bool IsEligibleForCompilation = Func->isLambdaStaticInvoker() ||72                                  FuncDecl->isConstexpr() ||73                                  FuncDecl->hasAttr<MSConstexprAttr>();74 75  // Compile the function body.76  if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) {77    Func->setIsFullyCompiled(true);78    return;79  }80 81  // Create scopes from descriptors.82  llvm::SmallVector<Scope, 2> Scopes;83  for (auto &DS : Descriptors) {84    Scopes.emplace_back(std::move(DS));85  }86 87  // Set the function's code.88  Func->setCode(FuncDecl, NextLocalOffset, std::move(Code), std::move(SrcMap),89                std::move(Scopes), FuncDecl->hasBody());90  Func->setIsFullyCompiled(true);91}92 93Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {94  NextLocalOffset += sizeof(Block);95  unsigned Location = NextLocalOffset;96  NextLocalOffset += align(D->getAllocSize());97  return {Location, D};98}99 100void ByteCodeEmitter::emitLabel(LabelTy Label) {101  const size_t Target = Code.size();102  LabelOffsets.insert({Label, Target});103 104  if (auto It = LabelRelocs.find(Label); It != LabelRelocs.end()) {105    for (unsigned Reloc : It->second) {106      using namespace llvm::support;107 108      // Rewrite the operand of all jumps to this label.109      void *Location = Code.data() + Reloc - align(sizeof(int32_t));110      assert(aligned(Location));111      const int32_t Offset = Target - static_cast<int64_t>(Reloc);112      endian::write<int32_t, llvm::endianness::native>(Location, Offset);113    }114    LabelRelocs.erase(It);115  }116}117 118int32_t ByteCodeEmitter::getOffset(LabelTy Label) {119  // Compute the PC offset which the jump is relative to.120  const int64_t Position =121      Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));122  assert(aligned(Position));123 124  // If target is known, compute jump offset.125  if (auto It = LabelOffsets.find(Label); It != LabelOffsets.end())126    return It->second - Position;127 128  // Otherwise, record relocation and return dummy offset.129  LabelRelocs[Label].push_back(Position);130  return 0ull;131}132 133/// Helper to write bytecode and bail out if 32-bit offsets become invalid.134/// Pointers will be automatically marshalled as 32-bit IDs.135template <typename T>136static void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code,137                 const T &Val, bool &Success) {138  size_t ValPos = Code.size();139  size_t Size;140 141  if constexpr (std::is_pointer_v<T>)142    Size = align(sizeof(uint32_t));143  else144    Size = align(sizeof(T));145 146  if (ValPos + Size > std::numeric_limits<unsigned>::max()) {147    Success = false;148    return;149  }150 151  // Access must be aligned!152  assert(aligned(ValPos));153  assert(aligned(ValPos + Size));154  Code.resize_for_overwrite(ValPos + Size);155 156  if constexpr (!std::is_pointer_v<T>) {157    new (Code.data() + ValPos) T(Val);158  } else {159    uint32_t ID = P.getOrCreateNativePointer(Val);160    new (Code.data() + ValPos) uint32_t(ID);161  }162}163 164/// Emits a serializable value. These usually (potentially) contain165/// heap-allocated memory and aren't trivially copyable.166template <typename T>167static void emitSerialized(llvm::SmallVectorImpl<std::byte> &Code, const T &Val,168                           bool &Success) {169  size_t ValPos = Code.size();170  size_t Size = align(Val.bytesToSerialize());171 172  if (ValPos + Size > std::numeric_limits<unsigned>::max()) {173    Success = false;174    return;175  }176 177  // Access must be aligned!178  assert(aligned(ValPos));179  assert(aligned(ValPos + Size));180  Code.resize_for_overwrite(ValPos + Size);181 182  Val.serialize(Code.data() + ValPos);183}184 185template <>186void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code,187          const Floating &Val, bool &Success) {188  emitSerialized(Code, Val, Success);189}190 191template <>192void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code,193          const IntegralAP<false> &Val, bool &Success) {194  emitSerialized(Code, Val, Success);195}196 197template <>198void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code,199          const IntegralAP<true> &Val, bool &Success) {200  emitSerialized(Code, Val, Success);201}202 203template <>204void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code,205          const FixedPoint &Val, bool &Success) {206  emitSerialized(Code, Val, Success);207}208 209template <typename... Tys>210bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &...Args, SourceInfo SI) {211  bool Success = true;212 213  // The opcode is followed by arguments. The source info is214  // attached to the address after the opcode.215  emit(P, Code, Op, Success);216  if (LocOverride)217    SrcMap.emplace_back(Code.size(), *LocOverride);218  else if (SI)219    SrcMap.emplace_back(Code.size(), SI);220 221  (..., emit(P, Code, Args, Success));222  return Success;223}224 225bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {226  return emitJt(getOffset(Label), SourceInfo{});227}228 229bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {230  return emitJf(getOffset(Label), SourceInfo{});231}232 233bool ByteCodeEmitter::jump(const LabelTy &Label) {234  return emitJmp(getOffset(Label), SourceInfo{});235}236 237bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {238  emitLabel(Label);239  return true;240}241 242bool ByteCodeEmitter::speculate(const CallExpr *E, const LabelTy &EndLabel) {243  const Expr *Arg = E->getArg(0);244  PrimType T = Ctx.classify(Arg->getType()).value_or(PT_Ptr);245  if (!this->emitBCP(getOffset(EndLabel), T, E))246    return false;247  if (!this->visit(Arg))248    return false;249  return true;250}251 252//===----------------------------------------------------------------------===//253// Opcode emitters254//===----------------------------------------------------------------------===//255 256#define GET_LINK_IMPL257#include "Opcodes.inc"258#undef GET_LINK_IMPL259