tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, shafik, cor3ntin. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This is a bit awkward, since we get an `APValue` from the expression, which we then need to re-integrate into our bytecode/primtype based interpreter. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D155627 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/Program.cpp clang/test/AST/Interp/builtin-functions.cpp
Index: clang/test/AST/Interp/builtin-functions.cpp =================================================================== --- clang/test/AST/Interp/builtin-functions.cpp +++ clang/test/AST/Interp/builtin-functions.cpp @@ -129,3 +129,25 @@ _Complex double CD = __arithmetic_fence(CD); #endif } + +namespace std { +struct source_location { + struct __impl { + unsigned int _M_line; + const char *_M_file_name; + signed char _M_column; + const char *_M_function_name; + }; + using BuiltinT = decltype(__builtin_source_location()); // OK. +}; +} + +namespace SourceLocation { + constexpr auto A = __builtin_source_location(); + static_assert(A->_M_line == 146, ""); + static_assert(A->_M_column == 22, ""); + static_assert(__builtin_strcmp(A->_M_function_name, "") == 0, ""); + static_assert(__builtin_strcmp(A->_M_file_name, __FILE__) == 0, ""); + + static_assert(__builtin_LINE() == 152, ""); +} Index: clang/lib/AST/Interp/Program.cpp =================================================================== --- clang/lib/AST/Interp/Program.cpp +++ clang/lib/AST/Interp/Program.cpp @@ -161,9 +161,12 @@ const Expr *Init) { assert(!getGlobal(VD)); bool IsStatic, IsExtern; - if (auto *Var = dyn_cast<VarDecl>(VD)) { + if (const auto *Var = dyn_cast<VarDecl>(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); IsExtern = !Var->getAnyInitializer(); + } else if (isa<UnnamedGlobalConstantDecl>(VD)) { + IsStatic = true; + IsExtern = false; } else { IsStatic = false; IsExtern = true; Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -100,6 +100,7 @@ bool VisitPredefinedExpr(const PredefinedExpr *E); bool VisitCXXThrowExpr(const CXXThrowExpr *E); bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E); + bool VisitSourceLocExpr(const SourceLocExpr *E); protected: bool visitExpr(const Expr *E) override; @@ -148,6 +149,8 @@ bool visitRecordInitializer(const Expr *Initializer); /// Creates and initializes a variable from the given decl. bool visitVarDecl(const VarDecl *VD); + /// Visit an APValue. + bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); /// Visits an expression and converts it to a boolean. bool visitBool(const Expr *E); @@ -235,12 +238,14 @@ llvm::function_ref<bool(PrimType)> Indirect); /// Emits an APSInt constant. + bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E); bool emitConst(const llvm::APSInt &Value, const Expr *E); bool emitConst(const llvm::APInt &Value, const Expr *E) { return emitConst(static_cast<llvm::APSInt>(Value), E); } /// Emits an integer constant. + template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E); template <typename T> bool emitConst(T Value, const Expr *E); /// Returns the CXXRecordDecl for the type of the given expression, Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1136,6 +1136,61 @@ return this->emitInvalidCast(CastKind::Reinterpret, E); } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) { + if (DiscardResult) + return true; + + // FIXME: Supply default expression. + const APValue Val = E->EvaluateInContext(Ctx.getASTContext(), nullptr); + // Things like __builtin_LINE(). + if (E->getType()->isIntegerType()) { + assert(Val.isInt()); + const APSInt &I = Val.getInt(); + return this->emitConst(I, E); + } + // Otherwise, the APValue is an LValue, with only one element. + // Theoretically, we don't need the APValue at all of course. + assert(E->getType()->isPointerType()); + assert(Val.isLValue()); + const APValue::LValueBase &Base = Val.getLValueBase(); + if (const Expr *LValueExpr = Base.dyn_cast<const Expr *>()) + return this->visit(LValueExpr); + + // Otherwise, we have a decl (which is the case for + // __builtin_source_location). + assert(Base.is<const ValueDecl *>()); + assert(Val.getLValuePath().size() == 0); + const auto *BaseDecl = Base.dyn_cast<const ValueDecl *>(); + assert(BaseDecl); + + auto *UGCD = cast<UnnamedGlobalConstantDecl>(BaseDecl); + + std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(UGCD); + if (!GlobalIndex) + return false; + + if (!this->emitGetPtrGlobal(*GlobalIndex, E)) + return false; + + const Record *R = getRecord(E->getType()); + const APValue &V = UGCD->getValue(); + for (unsigned I = 0, N = R->getNumFields(); I != N; ++I) { + const Record::Field *F = R->getField(I); + const APValue &FieldValue = V.getStructField(I); + + PrimType FieldT = classifyPrim(F->Decl->getType()); + + if (!this->visitAPValue(FieldValue, FieldT, E)) + return false; + if (!this->emitInitField(FieldT, F->Offset, E)) + return false; + } + + // Leave the pointer to the global on the stack. + return true; +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { if (E->containsErrors()) return false; @@ -1382,8 +1437,8 @@ template <class Emitter> template <typename T> -bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) { - switch (classifyPrim(E->getType())) { +bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) { + switch (Ty) { case PT_Sint8: return this->emitConstSint8(Value, E); case PT_Uint8: @@ -1412,10 +1467,22 @@ } template <class Emitter> -bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) { +template <typename T> +bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) { + return this->emitConst(Value, classifyPrim(E->getType()), E); +} + +template <class Emitter> +bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty, + const Expr *E) { if (Value.isSigned()) - return this->emitConst(Value.getSExtValue(), E); - return this->emitConst(Value.getZExtValue(), E); + return this->emitConst(Value.getSExtValue(), Ty, E); + return this->emitConst(Value.getZExtValue(), Ty, E); +} + +template <class Emitter> +bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) { + return this->emitConst(Value, classifyPrim(E->getType()), E); } template <class Emitter> @@ -1894,6 +1961,22 @@ return false; } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val, + PrimType ValType, const Expr *E) { + assert(!DiscardResult); + if (Val.isInt()) + return this->emitConst(Val.getInt(), ValType, E); + + if (Val.isLValue()) { + APValue::LValueBase Base = Val.getLValueBase(); + if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>()) + return this->visit(BaseExpr); + } + + return false; +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) { const Function *Func = getFunction(E->getDirectCallee());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits