https://github.com/yaohuihan-iluvatar updated https://github.com/llvm/llvm-project/pull/201805
>From f9be617d78b666c9c235e9ee653f45cff36b5eb8 Mon Sep 17 00:00:00 2001 From: "yaohui.han" <[email protected]> Date: Fri, 5 Jun 2026 17:58:06 +0800 Subject: [PATCH 1/4] [Clang][ExprConstant] Normalize aux target builtin IDs before dispatch When compiling for a device target that has an auxiliary host target (for example OpenMP or CUDA offload), builtins of the auxiliary target are registered with IDs shifted past the primary target's builtins. The constant evaluator passed the raw ID straight into the target-specific evaluation switches in the Pointer/Int/Vector/Float expression evaluators, so a shifted auxiliary ID could fall through to an unrelated builtin's case (or miss its case entirely) and fail to fold. Add a getConstantEvaluatedBuiltinID() helper that translates auxiliary builtin IDs back to their canonical target IDs via BuiltinInfo::getAuxBuiltinID(), and use it before dispatching in each of those evaluators. --- clang/lib/AST/ExprConstant.cpp | 54 +++++++++++-------- .../Sema/aux-target-builtin-constexpr.cpp | 20 +++++++ 2 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 clang/test/Sema/aux-target-builtin-constexpr.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 1642c41a99a2f..b7e2aa8ea9dcc 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8452,6 +8452,13 @@ class ExprEvaluatorBase Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp); } + unsigned getConstantEvaluatedBuiltinID(const CallExpr *E) { + unsigned BuiltinOp = E->getBuiltinCallee(); + if (Info.Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) + BuiltinOp = Info.Ctx.BuiltinInfo.getAuxBuiltinID(BuiltinOp); + return BuiltinOp; + } + public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -10338,7 +10345,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return visitNonBuiltinCallExpr(E); - return VisitBuiltinCallExpr(E, E->getBuiltinCallee()); + return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(E)); } // Determine if T is a character type for which we guarantee that @@ -12275,6 +12282,8 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); + unsigned BuiltinOp = getConstantEvaluatedBuiltinID(E); + auto EvaluateBinOpExpr = [&](llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) { APValue SourceLHS, SourceRHS; @@ -12402,7 +12411,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(V, E); }; - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { default: return false; case Builtin::BI__builtin_elementwise_popcount: @@ -12418,7 +12427,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { APSInt Elt = Source.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case Builtin::BI__builtin_elementwise_popcount: ResultElements.push_back(APValue( APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()), @@ -12610,7 +12619,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { const APSInt &HiRHS = SourceRHS.getVectorElt(EltNum + 1).getInt(); unsigned BitWidth = 2 * LoLHS.getBitWidth(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_pmaddubsw128: case clang::X86::BI__builtin_ia32_pmaddubsw256: case clang::X86::BI__builtin_ia32_pmaddubsw512: @@ -12822,7 +12831,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_pmuludq128: case clang::X86::BI__builtin_ia32_pmuludq256: case clang::X86::BI__builtin_ia32_pmuludq512: @@ -12929,7 +12938,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case Builtin::BI__builtin_elementwise_max: ResultElements.push_back( APValue(APSInt(std::max(LHS, RHS), @@ -13287,7 +13296,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case X86::BI__builtin_ia32_cvtpd2ps_mask: case X86::BI__builtin_ia32_cvtpd2ps512_mask: { - const auto BuiltinID = E->getBuiltinCallee(); + const auto BuiltinID = BuiltinOp; bool IsMasked = (BuiltinID == X86::BI__builtin_ia32_cvtpd2ps_mask || BuiltinID == X86::BI__builtin_ia32_cvtpd2ps512_mask); @@ -13823,14 +13832,14 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { // Without a fallback, a zero element is undefined if (!Fallback) { Info.FFDiag(E, diag::note_constexpr_countzeroes_zero) - << /*IsTrailing=*/(E->getBuiltinCallee() == + << /*IsTrailing=*/(BuiltinOp == Builtin::BI__builtin_elementwise_ctzg); return false; } ResultElements.push_back(Fallback->getVectorElt(EltNum)); continue; } - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case Builtin::BI__builtin_elementwise_clzg: ResultElements.push_back(APValue( APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), LHS.countl_zero()), @@ -13900,7 +13909,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned I = 0; I != EltsPerLane; I += 2) { APSInt LHSA = SourceLHS.getVectorElt(LaneStart + I).getInt(); APSInt LHSB = SourceLHS.getVectorElt(LaneStart + I + 1).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_phaddw128: case clang::X86::BI__builtin_ia32_phaddw256: case clang::X86::BI__builtin_ia32_phaddd128: @@ -13934,7 +13943,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned I = 0; I != EltsPerLane; I += 2) { APSInt RHSA = SourceRHS.getVectorElt(LaneStart + I).getInt(); APSInt RHSB = SourceRHS.getVectorElt(LaneStart + I + 1).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_phaddw128: case clang::X86::BI__builtin_ia32_phaddw256: case clang::X86::BI__builtin_ia32_phaddd128: @@ -13994,7 +14003,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned I = 0; I != HalfElemsPerLane; ++I) { APFloat LHSA = SourceLHS.getVectorElt(L + (2 * I) + 0).getFloat(); APFloat LHSB = SourceLHS.getVectorElt(L + (2 * I) + 1).getFloat(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_haddpd: case clang::X86::BI__builtin_ia32_haddps: case clang::X86::BI__builtin_ia32_haddps256: @@ -14013,7 +14022,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned I = 0; I != HalfElemsPerLane; ++I) { APFloat RHSA = SourceRHS.getVectorElt(L + (2 * I) + 0).getFloat(); APFloat RHSB = SourceRHS.getVectorElt(L + (2 * I) + 1).getFloat(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case clang::X86::BI__builtin_ia32_haddpd: case clang::X86::BI__builtin_ia32_haddps: case clang::X86::BI__builtin_ia32_haddps256: @@ -14137,7 +14146,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { const APSInt &Hi = SourceHi.getVectorElt(EltNum).getInt(); const APSInt &Lo = SourceLo.getVectorElt(EltNum).getInt(); const APSInt &Shift = SourceShift.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case Builtin::BI__builtin_elementwise_fshl: ResultElements.push_back(APValue( APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned()))); @@ -14220,7 +14229,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { assert(X.getVectorLength() == A.getVectorLength()); bool IsInverse = false; - switch (E->getBuiltinCallee()) { + switch (BuiltinOp) { case X86::BI__builtin_ia32_vgf2p8affineinvqb_v16qi: case X86::BI__builtin_ia32_vgf2p8affineinvqb_v32qi: case X86::BI__builtin_ia32_vgf2p8affineinvqb_v64qi: { @@ -14624,12 +14633,9 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_maxsd_round_mask: case clang::X86::BI__builtin_ia32_maxss_round_mask: case clang::X86::BI__builtin_ia32_maxsh_round_mask: { - bool IsMin = - E->getBuiltinCallee() == - clang::X86::BI__builtin_ia32_minsd_round_mask || - E->getBuiltinCallee() == - clang::X86::BI__builtin_ia32_minss_round_mask || - E->getBuiltinCallee() == clang::X86::BI__builtin_ia32_minsh_round_mask; + bool IsMin = BuiltinOp == clang::X86::BI__builtin_ia32_minsd_round_mask || + BuiltinOp == clang::X86::BI__builtin_ia32_minss_round_mask || + BuiltinOp == clang::X86::BI__builtin_ia32_minsh_round_mask; return EvaluateScalarFpRoundMaskBinOp( [IsMin](const APFloat &A, const APFloat &B, std::optional<APSInt> RoundingMode) -> std::optional<APFloat> { @@ -16355,7 +16361,7 @@ tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, EvalInfo &Info, bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); - return VisitBuiltinCallExpr(E, E->getBuiltinCallee()); + return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(E)); } static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info, @@ -19926,7 +19932,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); - switch (E->getBuiltinCallee()) { + unsigned BuiltinOp = getConstantEvaluatedBuiltinID(E); + + switch (BuiltinOp) { default: return false; diff --git a/clang/test/Sema/aux-target-builtin-constexpr.cpp b/clang/test/Sema/aux-target-builtin-constexpr.cpp new file mode 100644 index 0000000000000..38d2f02343b49 --- /dev/null +++ b/clang/test/Sema/aux-target-builtin-constexpr.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fopenmp -fopenmp-is-target-device \ +// RUN: -triple aarch64 -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -aux-target-feature +avx512f -std=c++17 -fsyntax-only -verify %s + +// expected-no-diagnostics + +// When compiling for a device target (here aarch64) with an auxiliary x86 +// target, x86 builtins are registered as auxiliary builtins whose IDs are +// shifted past the primary target's builtins. The constant evaluator must +// translate such aux IDs back to their canonical X86::BI* values before +// dispatching the target-specific constexpr switches. Without that +// normalization the shifted ID misses its intended case and the call fails to +// fold ("not an integral constant expression"). + +typedef short __v8hi __attribute__((__vector_size__(16))); + +constexpr __v8hi V = {0, 10, 20, 30, 40, 50, 60, 70}; + +static_assert(__builtin_ia32_vec_ext_v8hi(V, 3) == 30); +static_assert(__builtin_ia32_vec_ext_v8hi(V, 7) == 70); >From 6d692e11d11972c7a2391372f3eef86bf9ff5a33 Mon Sep 17 00:00:00 2001 From: "yaohui.han" <[email protected]> Date: Wed, 17 Jun 2026 17:18:00 +0800 Subject: [PATCH 2/4] [Clang][ExprConstant] Add aux target check in getConstantEvaluatedBuiltinID --- clang/lib/AST/ExprConstant.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index b7e2aa8ea9dcc..44250d9fcee37 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8454,8 +8454,33 @@ class ExprEvaluatorBase unsigned getConstantEvaluatedBuiltinID(const CallExpr *E) { unsigned BuiltinOp = E->getBuiltinCallee(); - if (Info.Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) + + // Target-independent builtins have the same ID regardless of the target, so + // they can be dispatched as-is. + if (BuiltinOp < Builtin::FirstTSBuiltin) + return BuiltinOp; + + // Target-specific builtin IDs of different targets overlap (each target + // numbers its builtins from Builtin::FirstTSBuiltin), and the + // target-specific constant-evaluation cases dispatched on this ID are + // X86-only. A target builtin ID may therefore only be treated as an X86 + // builtin when the target that owns it is actually x86; otherwise the + // overlapping ID could be misinterpreted as an unrelated X86 builtin. + // Determine the owning target (translating an auxiliary ID back to its + // canonical value) and only keep the ID when that target is x86; for any + // other target return 0 so dispatch falls through to the default case + // ("cannot constant-fold") instead of matching an X86 case by accident. + const TargetInfo *OwningTarget; + if (Info.Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) { + OwningTarget = Info.Ctx.getAuxTargetInfo(); BuiltinOp = Info.Ctx.BuiltinInfo.getAuxBuiltinID(BuiltinOp); + } else { + OwningTarget = &Info.Ctx.getTargetInfo(); + } + + if (!OwningTarget || !OwningTarget->getTriple().isX86()) + return 0; + return BuiltinOp; } >From 671b8e562249bcd5dde55cd0ac819e56cddd02bb Mon Sep 17 00:00:00 2001 From: "yaohui.han" <[email protected]> Date: Thu, 18 Jun 2026 14:53:27 +0800 Subject: [PATCH 3/4] [Clang][ExprConstant] Add target switch in getConstantEvaluatedBuiltinID Now dispatch the ID for x86, waiting for other targets work. --- clang/lib/AST/ExprConstant.cpp | 38 +++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 44250d9fcee37..7315eb88025e0 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8452,6 +8452,17 @@ class ExprEvaluatorBase Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp); } + // Return the target builtin ID to dispatch on in the constant evaluator's + // target-specific cases, or 0 if \p E does not name a builtin those cases + // should handle. + // + // Target-specific builtin IDs of different targets overlap (each target + // numbers its builtins from Builtin::FirstTSBuiltin), so a target builtin ID + // is only meaningful for the target that owns it. Determine the owning target + // (translating an auxiliary ID back to its canonical value) and only return + // the ID for architectures whose target-specific builtins the constant + // evaluator knows how to fold; otherwise an overlapping ID could be + // misinterpreted as an unrelated builtin of another target. unsigned getConstantEvaluatedBuiltinID(const CallExpr *E) { unsigned BuiltinOp = E->getBuiltinCallee(); @@ -8460,16 +8471,8 @@ class ExprEvaluatorBase if (BuiltinOp < Builtin::FirstTSBuiltin) return BuiltinOp; - // Target-specific builtin IDs of different targets overlap (each target - // numbers its builtins from Builtin::FirstTSBuiltin), and the - // target-specific constant-evaluation cases dispatched on this ID are - // X86-only. A target builtin ID may therefore only be treated as an X86 - // builtin when the target that owns it is actually x86; otherwise the - // overlapping ID could be misinterpreted as an unrelated X86 builtin. - // Determine the owning target (translating an auxiliary ID back to its - // canonical value) and only keep the ID when that target is x86; for any - // other target return 0 so dispatch falls through to the default case - // ("cannot constant-fold") instead of matching an X86 case by accident. + // Determine the target that owns this builtin, translating an auxiliary ID + // back to its canonical value. const TargetInfo *OwningTarget; if (Info.Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) { OwningTarget = Info.Ctx.getAuxTargetInfo(); @@ -8478,10 +8481,21 @@ class ExprEvaluatorBase OwningTarget = &Info.Ctx.getTargetInfo(); } - if (!OwningTarget || !OwningTarget->getTriple().isX86()) + if (!OwningTarget) return 0; - return BuiltinOp; + // Only dispatch the ID for architectures whose target-specific builtins the + // constant evaluator can fold. x86 and x86_64 share a single builtin set and + // are the only such architectures today; as other targets gain + // constant-evaluation support for their builtins, add the corresponding + // cases here so their IDs are dispatched too. + switch (OwningTarget->getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return BuiltinOp; + default: + return 0; + } } public: >From d93c7d37b3a0205be5a240f8e190e7f1a31d1a0d Mon Sep 17 00:00:00 2001 From: "yaohui.han" <[email protected]> Date: Thu, 18 Jun 2026 16:49:35 +0800 Subject: [PATCH 4/4] [clang][bytecode] Share getConstantEvaluatedBuiltinID with the bytecode interpreter Make getConstantEvaluatedBuiltinID a free function in ExprConstShared.h and use it in the bytecode interpreter so auxiliary x86 builtin IDs are normalized to their canonical X86::BI* value before dispatch. As the baked ID is now canonical, InterpretBuiltin's isConstantEvaluated gate uses the raw builtin ID. --- clang/lib/AST/ByteCode/Compiler.cpp | 7 +- clang/lib/AST/ByteCode/Interp.cpp | 3 +- clang/lib/AST/ByteCode/Interp.h | 7 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 11 +- clang/lib/AST/ExprConstShared.h | 9 ++ clang/lib/AST/ExprConstant.cpp | 101 +++++++++--------- .../Sema/aux-target-builtin-constexpr.cpp | 4 + 7 files changed, 85 insertions(+), 57 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 8ea42fea03bee..b9a3d3fe68869 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Compiler.h" +#include "../ExprConstShared.h" #include "ByteCodeEmitter.h" #include "Context.h" #include "FixedPoint.h" @@ -2820,7 +2821,8 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator( bool IsBcpCall = false; if (const auto *CE = dyn_cast<CallExpr>(Condition->IgnoreParenCasts()); - CE && CE->getBuiltinCallee() == Builtin::BI__builtin_constant_p) { + CE && getConstantEvaluatedBuiltinID(Ctx.getASTContext(), CE) == + Builtin::BI__builtin_constant_p) { IsBcpCall = true; } @@ -5708,7 +5710,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { const FunctionDecl *FuncDecl = E->getDirectCallee(); if (FuncDecl) { - if (unsigned BuiltinID = FuncDecl->getBuiltinID()) + if (unsigned BuiltinID = + getConstantEvaluatedBuiltinID(Ctx.getASTContext(), E)) return VisitBuiltinCallExpr(E, BuiltinID); // Calls to replaceable operator new/operator delete. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 754046be06d05..96c6d2287970e 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1180,7 +1180,8 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, return true; // operator new. if (const auto *CE = dyn_cast_if_present<CallExpr>(Source); - CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new) + CE && getConstantEvaluatedBuiltinID(S.getASTContext(), CE) == + Builtin::BI__builtin_operator_new) return true; // std::allocator.allocate() call if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index b6377e22f0db6..40e404d3db73f 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1280,8 +1280,9 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { return true; } -static inline bool IsOpaqueConstantCall(const CallExpr *E) { - unsigned Builtin = E->getBuiltinCallee(); +static inline bool IsOpaqueConstantCall(const ASTContext &Ctx, + const CallExpr *E) { + unsigned Builtin = getConstantEvaluatedBuiltinID(Ctx, E); return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || Builtin == Builtin::BI__builtin___NSStringMakeConstantString || Builtin == Builtin::BI__builtin_ptrauth_sign_constant || @@ -1384,7 +1385,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { return false; } if (const auto *CE = dyn_cast<CallExpr>(E); - CE && IsOpaqueConstantCall(CE)) { + CE && IsOpaqueConstantCall(S.getASTContext(), CE)) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison) << P.toDiagnosticString(S.getASTContext()); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 5076d27766e25..176c1e0e7f343 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -4443,7 +4443,16 @@ static bool interp__builtin_ia32_gfni_mul(InterpState &S, CodePtr OpPC, bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID) { - if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID)) + // BuiltinID has already been normalized (see getConstantEvaluatedBuiltinID), + // i.e. an auxiliary target builtin ID has been translated to its canonical + // value. The "is constant evaluated" check below needs the *raw* builtin ID + // so that aux-target IDs resolve into the correct (aux-target) builtin + // records; recover it from the call, falling back to BuiltinID for builtins + // emitted without a direct callee (e.g. operator new/delete). + unsigned RawBuiltinID = Call->getBuiltinCallee(); + if (!RawBuiltinID) + RawBuiltinID = BuiltinID; + if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(RawBuiltinID)) return Invalid(S, OpPC); const InterpFrame *Frame = S.Current; diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h index 619c79a1408f3..afea0ceeb6571 100644 --- a/clang/lib/AST/ExprConstShared.h +++ b/clang/lib/AST/ExprConstShared.h @@ -29,6 +29,7 @@ class LangOptions; class ASTContext; class CharUnits; class Expr; +class CallExpr; } // namespace clang using namespace clang; /// Values returned by __builtin_classify_type, chosen to match the values @@ -78,6 +79,14 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C, CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, UnaryExprOrTypeTrait ExprKind); +/// Return the (normalized) builtin ID to dispatch on in the constant +/// evaluators' target-specific cases, or 0 if \p E does not name a builtin +/// those cases should handle. Translates an auxiliary target builtin ID back to +/// its canonical value and only returns IDs for architectures the constant +/// evaluators can fold (currently x86/x86_64). +unsigned getConstantEvaluatedBuiltinID(const ASTContext &Ctx, + const CallExpr *E); + uint8_t GFNIMultiplicativeInverse(uint8_t Byte); uint8_t GFNIMul(uint8_t AByte, uint8_t BByte); uint8_t GFNIAffine(uint8_t XByte, const llvm::APInt &AQword, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 7315eb88025e0..e1d5a1fd547fc 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8452,52 +8452,6 @@ class ExprEvaluatorBase Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp); } - // Return the target builtin ID to dispatch on in the constant evaluator's - // target-specific cases, or 0 if \p E does not name a builtin those cases - // should handle. - // - // Target-specific builtin IDs of different targets overlap (each target - // numbers its builtins from Builtin::FirstTSBuiltin), so a target builtin ID - // is only meaningful for the target that owns it. Determine the owning target - // (translating an auxiliary ID back to its canonical value) and only return - // the ID for architectures whose target-specific builtins the constant - // evaluator knows how to fold; otherwise an overlapping ID could be - // misinterpreted as an unrelated builtin of another target. - unsigned getConstantEvaluatedBuiltinID(const CallExpr *E) { - unsigned BuiltinOp = E->getBuiltinCallee(); - - // Target-independent builtins have the same ID regardless of the target, so - // they can be dispatched as-is. - if (BuiltinOp < Builtin::FirstTSBuiltin) - return BuiltinOp; - - // Determine the target that owns this builtin, translating an auxiliary ID - // back to its canonical value. - const TargetInfo *OwningTarget; - if (Info.Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) { - OwningTarget = Info.Ctx.getAuxTargetInfo(); - BuiltinOp = Info.Ctx.BuiltinInfo.getAuxBuiltinID(BuiltinOp); - } else { - OwningTarget = &Info.Ctx.getTargetInfo(); - } - - if (!OwningTarget) - return 0; - - // Only dispatch the ID for architectures whose target-specific builtins the - // constant evaluator can fold. x86 and x86_64 share a single builtin set and - // are the only such architectures today; as other targets gain - // constant-evaluation support for their builtins, add the corresponding - // cases here so their IDs are dispatched too. - switch (OwningTarget->getTriple().getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return BuiltinOp; - default: - return 0; - } - } - public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -10310,6 +10264,53 @@ static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T, llvm_unreachable("GetAlignOfType on a non-alignment ExprKind"); } +// Return the target builtin ID to dispatch on in the constant evaluators' +// target-specific cases, or 0 if \p E does not name a builtin those cases +// should handle. +// +// Target-specific builtin IDs of different targets overlap (each target numbers +// its builtins from Builtin::FirstTSBuiltin), so a target builtin ID is only +// meaningful for the target that owns it. Determine the owning target +// (translating an auxiliary ID back to its canonical value) and only return the +// ID for architectures whose target-specific builtins the constant evaluators +// know how to fold; otherwise an overlapping ID could be misinterpreted as an +// unrelated builtin of another target. +unsigned getConstantEvaluatedBuiltinID(const ASTContext &Ctx, + const CallExpr *E) { + unsigned BuiltinOp = E->getBuiltinCallee(); + + // Target-independent builtins have the same ID regardless of the target, so + // they can be dispatched as-is. + if (BuiltinOp < Builtin::FirstTSBuiltin) + return BuiltinOp; + + // Determine the target that owns this builtin, translating an auxiliary ID + // back to its canonical value. + const TargetInfo *OwningTarget; + if (Ctx.BuiltinInfo.isAuxBuiltinID(BuiltinOp)) { + OwningTarget = Ctx.getAuxTargetInfo(); + BuiltinOp = Ctx.BuiltinInfo.getAuxBuiltinID(BuiltinOp); + } else { + OwningTarget = &Ctx.getTargetInfo(); + } + + if (!OwningTarget) + return 0; + + // Only dispatch the ID for architectures whose target-specific builtins the + // constant evaluators can fold. x86 and x86_64 share a single builtin set and + // are the only such architectures today; as other targets gain + // constant-evaluation support for their builtins, add the corresponding cases + // here so their IDs are dispatched too. + switch (OwningTarget->getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return BuiltinOp; + default: + return 0; + } +} + CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, UnaryExprOrTypeTrait ExprKind) { E = E->IgnoreParens(); @@ -10384,7 +10385,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return visitNonBuiltinCallExpr(E); - return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(E)); + return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(Info.Ctx, E)); } // Determine if T is a character type for which we guarantee that @@ -12321,7 +12322,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); - unsigned BuiltinOp = getConstantEvaluatedBuiltinID(E); + unsigned BuiltinOp = getConstantEvaluatedBuiltinID(Info.Ctx, E); auto EvaluateBinOpExpr = [&](llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) { @@ -16400,7 +16401,7 @@ tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, EvalInfo &Info, bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); - return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(E)); + return VisitBuiltinCallExpr(E, getConstantEvaluatedBuiltinID(Info.Ctx, E)); } static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info, @@ -19971,7 +19972,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); - unsigned BuiltinOp = getConstantEvaluatedBuiltinID(E); + unsigned BuiltinOp = getConstantEvaluatedBuiltinID(Info.Ctx, E); switch (BuiltinOp) { default: diff --git a/clang/test/Sema/aux-target-builtin-constexpr.cpp b/clang/test/Sema/aux-target-builtin-constexpr.cpp index 38d2f02343b49..96af00e161a40 100644 --- a/clang/test/Sema/aux-target-builtin-constexpr.cpp +++ b/clang/test/Sema/aux-target-builtin-constexpr.cpp @@ -1,6 +1,10 @@ // RUN: %clang_cc1 -fopenmp -fopenmp-is-target-device \ // RUN: -triple aarch64 -aux-triple x86_64-unknown-linux-gnu \ // RUN: -aux-target-feature +avx512f -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fopenmp -fopenmp-is-target-device \ +// RUN: -triple aarch64 -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -aux-target-feature +avx512f -std=c++17 -fsyntax-only -verify \ +// RUN: -fexperimental-new-constant-interpreter %s // expected-no-diagnostics _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
