diff options
Diffstat (limited to 'clang/lib/AST/ByteCode')
| -rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 145 | ||||
| -rw-r--r-- | clang/lib/AST/ByteCode/Interp.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltin.cpp | 63 | ||||
| -rw-r--r-- | clang/lib/AST/ByteCode/Opcodes.td | 10 |
4 files changed, 149 insertions, 78 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index f15b3c1..f4ddbf4 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -1842,7 +1842,6 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, const Expr *Init, PrimType T, bool Activate = false) -> bool { InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init)); - InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset)); if (!this->visit(Init)) return false; @@ -3274,34 +3273,43 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { } if (T->isArrayType()) { - const ConstantArrayType *CAT = - Ctx.getASTContext().getAsConstantArrayType(E->getType()); - if (!CAT) - return false; - - size_t NumElems = CAT->getZExtSize(); const Function *Func = getFunction(E->getConstructor()); if (!Func) return false; - // FIXME(perf): We're calling the constructor once per array element here, - // in the old intepreter we had a special-case for trivial constructors. - for (size_t I = 0; I != NumElems; ++I) { - if (!this->emitConstUint64(I, E)) - return false; - if (!this->emitArrayElemPtrUint64(E)) - return false; + if (!this->emitDupPtr(E)) + return false; - // Constructor arguments. - for (const auto *Arg : E->arguments()) { - if (!this->visit(Arg)) - return false; + std::function<bool(QualType)> initArrayDimension; + initArrayDimension = [&](QualType T) -> bool { + if (!T->isArrayType()) { + // Constructor arguments. + for (const auto *Arg : E->arguments()) { + if (!this->visit(Arg)) + return false; + } + + return this->emitCall(Func, 0, E); } - if (!this->emitCall(Func, 0, E)) + const ConstantArrayType *CAT = + Ctx.getASTContext().getAsConstantArrayType(T); + if (!CAT) return false; - } - return true; + QualType ElemTy = CAT->getElementType(); + unsigned NumElems = CAT->getZExtSize(); + for (size_t I = 0; I != NumElems; ++I) { + if (!this->emitConstUint64(I, E)) + return false; + if (!this->emitArrayElemPtrUint64(E)) + return false; + if (!initArrayDimension(ElemTy)) + return false; + } + return this->emitPopPtr(E); + }; + + return initArrayDimension(E->getType()); } return false; @@ -3600,8 +3608,6 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { if (PlacementDest) { if (!this->visit(PlacementDest)) return false; - if (!this->emitStartLifetime(E)) - return false; if (!this->emitGetLocal(SizeT, ArrayLen, E)) return false; if (!this->emitCheckNewTypeMismatchArray(SizeT, E, E)) @@ -3741,10 +3747,9 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { if (PlacementDest) { if (!this->visit(PlacementDest)) return false; - if (!this->emitStartLifetime(E)) - return false; if (!this->emitCheckNewTypeMismatch(E, E)) return false; + } else { // Allocate just one element. if (!this->emitAlloc(Desc, E)) @@ -5385,55 +5390,57 @@ bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) { // instance pointer of the current function frame, but e.g. to the declaration // currently being initialized. Here we emit the necessary instruction(s) for // this scenario. - if (!InitStackActive) + if (!InitStackActive || InitStack.empty()) return this->emitThis(E); - if (!InitStack.empty()) { - // If our init stack is, for example: - // 0 Stack: 3 (decl) - // 1 Stack: 6 (init list) - // 2 Stack: 1 (field) - // 3 Stack: 6 (init list) - // 4 Stack: 1 (field) - // - // We want to find the LAST element in it that's an init list, - // which is marked with the K_InitList marker. The index right - // before that points to an init list. We need to find the - // elements before the K_InitList element that point to a base - // (e.g. a decl or This), optionally followed by field, elem, etc. - // In the example above, we want to emit elements [0..2]. - unsigned StartIndex = 0; - unsigned EndIndex = 0; - // Find the init list. - for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) { - if (InitStack[StartIndex].Kind == InitLink::K_InitList || - InitStack[StartIndex].Kind == InitLink::K_This) { - EndIndex = StartIndex; - --StartIndex; - break; - } + // If our init stack is, for example: + // 0 Stack: 3 (decl) + // 1 Stack: 6 (init list) + // 2 Stack: 1 (field) + // 3 Stack: 6 (init list) + // 4 Stack: 1 (field) + // + // We want to find the LAST element in it that's an init list, + // which is marked with the K_InitList marker. The index right + // before that points to an init list. We need to find the + // elements before the K_InitList element that point to a base + // (e.g. a decl or This), optionally followed by field, elem, etc. + // In the example above, we want to emit elements [0..2]. + unsigned StartIndex = 0; + unsigned EndIndex = 0; + // Find the init list. + for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) { + if (InitStack[StartIndex].Kind == InitLink::K_InitList || + InitStack[StartIndex].Kind == InitLink::K_This) { + EndIndex = StartIndex; + --StartIndex; + break; } + } - // Walk backwards to find the base. - for (; StartIndex > 0; --StartIndex) { - if (InitStack[StartIndex].Kind == InitLink::K_InitList) - continue; + // Walk backwards to find the base. + for (; StartIndex > 0; --StartIndex) { + if (InitStack[StartIndex].Kind == InitLink::K_InitList) + continue; - if (InitStack[StartIndex].Kind != InitLink::K_Field && - InitStack[StartIndex].Kind != InitLink::K_Elem) - break; - } + if (InitStack[StartIndex].Kind != InitLink::K_Field && + InitStack[StartIndex].Kind != InitLink::K_Elem) + break; + } - // Emit the instructions. - for (unsigned I = StartIndex; I != EndIndex; ++I) { - if (InitStack[I].Kind == InitLink::K_InitList) - continue; - if (!InitStack[I].template emit<Emitter>(this, E)) - return false; - } - return true; + if (StartIndex == 0 && EndIndex == 0) + EndIndex = InitStack.size() - 1; + + assert(StartIndex < EndIndex); + + // Emit the instructions. + for (unsigned I = StartIndex; I != (EndIndex + 1); ++I) { + if (InitStack[I].Kind == InitLink::K_InitList) + continue; + if (!InitStack[I].template emit<Emitter>(this, E)) + return false; } - return this->emitThis(E); + return true; } template <class Emitter> bool Compiler<Emitter>::visitStmt(const Stmt *S) { @@ -6295,6 +6302,10 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { } assert(NestedField); + unsigned FirstLinkOffset = + R->getField(cast<FieldDecl>(IFD->chain()[0]))->Offset; + InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(InitExpr)); + InitLinkScope<Emitter> ILS(this, InitLink::Field(FirstLinkOffset)); if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr, IsUnion)) return false; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index a72282c..169a9a2 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1903,12 +1903,19 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion()) Ptr.activate(); + if (Ptr.isZero()) { + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null) + << AK_Construct; + return false; + } + if (!Ptr.isBlockPointer()) return false; + startLifetimeRecurse(Ptr); + // Similar to CheckStore(), but with the additional CheckTemporary() call and // the AccessKinds are different. - if (!Ptr.block()->isAccessible()) { if (!CheckExtern(S, OpPC, Ptr)) return false; diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index ff83c52..ff50e6d 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -12,12 +12,14 @@ #include "InterpHelpers.h" #include "PrimType.h" #include "Program.h" +#include "clang/AST/InferAlloc.h" #include "clang/AST/OSLog.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/AllocToken.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SipHash.h" @@ -1307,6 +1309,45 @@ interp__builtin_ptrauth_string_discriminator(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_infer_alloc_token(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const ASTContext &ASTCtx = S.getASTContext(); + uint64_t BitWidth = ASTCtx.getTypeSize(ASTCtx.getSizeType()); + auto Mode = + ASTCtx.getLangOpts().AllocTokenMode.value_or(llvm::DefaultAllocTokenMode); + uint64_t MaxTokens = + ASTCtx.getLangOpts().AllocTokenMax.value_or(~0ULL >> (64 - BitWidth)); + + // We do not read any of the arguments; discard them. + for (int I = Call->getNumArgs() - 1; I >= 0; --I) + discard(S.Stk, *S.getContext().classify(Call->getArg(I))); + + // Note: Type inference from a surrounding cast is not supported in + // constexpr evaluation. + QualType AllocType = infer_alloc::inferPossibleType(Call, ASTCtx, nullptr); + if (AllocType.isNull()) { + S.CCEDiag(Call, + diag::note_constexpr_infer_alloc_token_type_inference_failed); + return false; + } + + auto ATMD = infer_alloc::getAllocTokenMetadata(AllocType, ASTCtx); + if (!ATMD) { + S.CCEDiag(Call, diag::note_constexpr_infer_alloc_token_no_metadata); + return false; + } + + auto MaybeToken = llvm::getAllocToken(Mode, *ATMD, MaxTokens); + if (!MaybeToken) { + S.CCEDiag(Call, diag::note_constexpr_infer_alloc_token_stateful_mode); + return false; + } + + pushInteger(S, llvm::APInt(BitWidth, *MaybeToken), ASTCtx.getSizeType()); + return true; +} + static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { @@ -3471,7 +3512,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI_lrotl: case Builtin::BI_rotl64: return interp__builtin_elementwise_int_binop( - S, OpPC, Call, [](const APSInt &Value, const APSInt &Amount) -> APInt { + S, OpPC, Call, [](const APSInt &Value, const APSInt &Amount) { return Value.rotl(Amount); }); @@ -3485,7 +3526,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI_lrotr: case Builtin::BI_rotr64: return interp__builtin_elementwise_int_binop( - S, OpPC, Call, [](const APSInt &Value, const APSInt &Amount) -> APInt { + S, OpPC, Call, [](const APSInt &Value, const APSInt &Amount) { return Value.rotr(Amount); }); @@ -3694,6 +3735,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_ptrauth_string_discriminator: return interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, Call); + case Builtin::BI__builtin_infer_alloc_token: + return interp__builtin_infer_alloc_token(S, OpPC, Frame, Call); + case Builtin::BI__noop: pushInteger(S, 0, Call->getType()); return true; @@ -3809,6 +3853,21 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return interp__builtin_ia32_movmsk_op(S, OpPC, Call); } + case X86::BI__builtin_ia32_psignb128: + case X86::BI__builtin_ia32_psignb256: + case X86::BI__builtin_ia32_psignw128: + case X86::BI__builtin_ia32_psignw256: + case X86::BI__builtin_ia32_psignd128: + case X86::BI__builtin_ia32_psignd256: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, [](const APInt &AElem, const APInt &BElem) { + if (BElem.isZero()) + return APInt::getZero(AElem.getBitWidth()); + if (BElem.isNegative()) + return -AElem; + return AElem; + }); + case clang::X86::BI__builtin_ia32_pavgb128: case clang::X86::BI__builtin_ia32_pavgw128: case clang::X86::BI__builtin_ia32_pavgb256: diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 406feb5..1c17ad9e 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -866,19 +866,13 @@ def Free : Opcode { let Args = [ArgBool, ArgBool]; } -def CheckNewTypeMismatch : Opcode { - let Args = [ArgExpr]; -} - -def InvalidNewDeleteExpr : Opcode { - let Args = [ArgExpr]; -} - +def CheckNewTypeMismatch : Opcode { let Args = [ArgExpr]; } def CheckNewTypeMismatchArray : Opcode { let Types = [IntegerTypeClass]; let Args = [ArgExpr]; let HasGroup = 1; } +def InvalidNewDeleteExpr : Opcode { let Args = [ArgExpr]; } def IsConstantContext: Opcode; def CheckAllocations : Opcode; |
