diff options
Diffstat (limited to 'clang/lib/AST/Interp/ByteCodeEmitter.cpp')
| -rw-r--r-- | clang/lib/AST/Interp/ByteCodeEmitter.cpp | 99 |
1 files changed, 67 insertions, 32 deletions
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index f2072f974c40..89b7708c0c2a 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -7,20 +7,19 @@ //===----------------------------------------------------------------------===// #include "ByteCodeEmitter.h" +#include "ByteCodeGenError.h" #include "Context.h" #include "Floating.h" #include "Opcode.h" #include "Program.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/DeclCXX.h" +#include "clang/Basic/Builtins.h" #include <type_traits> using namespace clang; using namespace clang::interp; -using APSInt = llvm::APSInt; -using Error = llvm::Error; - Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { // Set up argument indices. @@ -46,7 +45,7 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { // InterpStack when calling the function. bool HasThisPointer = false; if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) { - if (MD->isInstance()) { + if (MD->isImplicitObjectMemberFunction()) { HasThisPointer = true; ParamTypes.push_back(PT_Ptr); ParamOffsets.push_back(ParamOffset); @@ -66,58 +65,75 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { this->LambdaCaptures[Cap.first] = { Offset, Cap.second->getType()->isReferenceType()}; } - // FIXME: LambdaThisCapture - (void)LTC; + if (LTC) + this->LambdaThisCapture = R->getField(LTC)->Offset; } } // Assign descriptors to all parameters. // Composite objects are lowered to pointers. for (const ParmVarDecl *PD : FuncDecl->parameters()) { - PrimType Ty = Ctx.classify(PD->getType()).value_or(PT_Ptr); - Descriptor *Desc = P.createDescriptor(PD, Ty); - ParamDescriptors.insert({ParamOffset, {Ty, Desc}}); - Params.insert({PD, ParamOffset}); + std::optional<PrimType> T = Ctx.classify(PD->getType()); + PrimType PT = T.value_or(PT_Ptr); + Descriptor *Desc = P.createDescriptor(PD, PT); + ParamDescriptors.insert({ParamOffset, {PT, Desc}}); + Params.insert({PD, {ParamOffset, T != std::nullopt}}); ParamOffsets.push_back(ParamOffset); - ParamOffset += align(primSize(Ty)); - ParamTypes.push_back(Ty); + ParamOffset += align(primSize(PT)); + ParamTypes.push_back(PT); } // Create a handle over the emitted code. Function *Func = P.getFunction(FuncDecl); - if (!Func) - Func = P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), - std::move(ParamDescriptors), - std::move(ParamOffsets), HasThisPointer, HasRVO); + if (!Func) { + bool IsUnevaluatedBuiltin = false; + if (unsigned BI = FuncDecl->getBuiltinID()) + IsUnevaluatedBuiltin = Ctx.getASTContext().BuiltinInfo.isUnevaluated(BI); + + Func = + P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), + std::move(ParamDescriptors), std::move(ParamOffsets), + HasThisPointer, HasRVO, IsUnevaluatedBuiltin); + } assert(Func); // For not-yet-defined functions, we only create a Function instance and // compile their body later. - if (!FuncDecl->isDefined()) + if (!FuncDecl->isDefined()) { + Func->setDefined(false); return Func; + } + + Func->setDefined(true); + + // Lambda static invokers are a special case that we emit custom code for. + bool IsEligibleForCompilation = false; + if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) + IsEligibleForCompilation = MD->isLambdaStaticInvoker(); + if (!IsEligibleForCompilation) + IsEligibleForCompilation = FuncDecl->isConstexpr(); // Compile the function body. - if (!FuncDecl->isConstexpr() || !visitFunc(FuncDecl)) { + if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) { // Return a dummy function if compilation failed. if (BailLocation) return llvm::make_error<ByteCodeGenError>(*BailLocation); - else { - Func->setIsFullyCompiled(true); - return Func; - } - } else { - // Create scopes from descriptors. - llvm::SmallVector<Scope, 2> Scopes; - for (auto &DS : Descriptors) { - Scopes.emplace_back(std::move(DS)); - } - // Set the function's code. - Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), - std::move(Scopes), FuncDecl->hasBody()); Func->setIsFullyCompiled(true); return Func; } + + // Create scopes from descriptors. + llvm::SmallVector<Scope, 2> Scopes; + for (auto &DS : Descriptors) { + Scopes.emplace_back(std::move(DS)); + } + + // Set the function's code. + Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap), + std::move(Scopes), FuncDecl->hasBody()); + Func->setIsFullyCompiled(true); + return Func; } Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) { @@ -140,7 +156,7 @@ void ByteCodeEmitter::emitLabel(LabelTy Label) { void *Location = Code.data() + Reloc - align(sizeof(int32_t)); assert(aligned(Location)); const int32_t Offset = Target - static_cast<int64_t>(Reloc); - endian::write<int32_t, endianness::native, 1>(Location, Offset); + endian::write<int32_t, llvm::endianness::native>(Location, Offset); } LabelRelocs.erase(It); } @@ -199,6 +215,25 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, } } +template <> +void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, + bool &Success) { + size_t Size = Val.bytesToSerialize(); + + if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + Success = false; + return; + } + + // Access must be aligned! + size_t ValPos = align(Code.size()); + Size = align(Size); + assert(aligned(ValPos + Size)); + Code.resize(ValPos + Size); + + Val.serialize(Code.data() + ValPos); +} + template <typename... Tys> bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { bool Success = true; |
