diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1478,6 +1478,14 @@ * ``maytrap`` The compiler avoids transformations that may raise exceptions that would not have been raised by the original code. Constant folding performed by the compiler is exempt from this option. * ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code. +.. option:: -f[no-]protect-parens: + + Where unsafe floating point optimizations are enabled, this option + determines whether the optimizer honors parentheses when floating-point + expressions are evaluated. If unsafe floating point optimizations are + disabled, the option has no effect. If unsafe floating point optimizations + are enabled, the default value is ``fno-protect-parens``. + .. _fp-constant-eval: diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -1657,6 +1657,9 @@ BUILTIN(__builtin_ms_va_end, "vc*&", "n") BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") +// Arithmetic Fence: to prevent FP reordering and reassociation optimizations +LANGBUILTIN(__arithmetic_fence, "v.", "t", ALL_LANGUAGES) + #undef BUILTIN #undef LIBBUILTIN #undef LANGBUILTIN diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8466,6 +8466,9 @@ "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types%diff{ ($ and $)|}0,1">; +def err_typecheck_expect_flt_or_vector : Error< + "operand of type %0 where floating, complex or " + "a vector of such types is required (%0 invalid)">; def err_cast_selector_expr : Error< "cannot type cast @selector expression">; def ext_typecheck_cond_incompatible_pointers : ExtWarn< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -196,6 +196,8 @@ COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro") COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") +COMPATIBLE_LANGOPT(ProtectParens , 1, 0, "optimizer honors parentheses " + "when floating-point expressions are evaluated") BENIGN_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation") BENIGN_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN") BENIGN_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities") diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1159,7 +1159,7 @@ /// Apply changes to the target information with respect to certain /// language options which change the target configuration and adjust /// the language based on the target options where applicable. - virtual void adjust(LangOptions &Opts); + virtual void adjust(DiagnosticsEngine &Diags, LangOptions &Opts); /// Adjust target options based on codegen options. virtual void adjustTargetOptions(const CodeGenOptions &CGOpts, @@ -1412,6 +1412,9 @@ bool isBigEndian() const { return BigEndian; } bool isLittleEndian() const { return !BigEndian; } + /// Controls if __arithmetic_fence is supported in the targetted backend. + virtual bool checkArithmeticFenceSupported() const { return false; } + /// Gets the default calling convention for the given target and /// declaration context. virtual CallingConv getDefaultCallingConv() const { diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1698,6 +1698,13 @@ " of the target's native float-to-int conversion instructions">, PosFlag>; +defm protect_parens : BoolFOption<"protect-parens", + LangOpts<"ProtectParens">, DefaultFalse, + PosFlag, + NegFlag>; + def ffor_scope : Flag<["-"], "ffor-scope">, Group; def fno_for_scope : Flag<["-"], "fno-for-scope">, Group; @@ -4290,7 +4297,7 @@ defm max_identifier_length : BooleanFFlag<"max-identifier-length">, Group; defm module_private : BooleanFFlag<"module-private">, Group; defm pack_derived : BooleanFFlag<"pack-derived">, Group; -defm protect_parens : BooleanFFlag<"protect-parens">, Group; +//defm protect_parens : BooleanFFlag<"protect-parens">, Group; defm range_check : BooleanFFlag<"range-check">, Group; defm real_4_real_10 : BooleanFFlag<"real-4-real-10">, Group; defm real_4_real_16 : BooleanFFlag<"real-4-real-16">, Group; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -35,6 +35,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/BitmaskEnum.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenCLOptions.h" @@ -5373,6 +5374,8 @@ Expr *ExecConfig = nullptr, bool IsExecConfig = false, bool AllowRecovery = false); + ExprResult BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id, + MultiExprArg CallArgs); enum class AtomicArgumentOrder { API, AST }; ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, @@ -12521,6 +12524,7 @@ private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); + bool SemaBuiltinArithmeticFence(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9306,6 +9306,9 @@ } } + case Builtin::BI__arithmetic_fence: + return false; + default: break; } diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -344,7 +344,7 @@ /// Apply changes to the target information with respect to certain /// language options which change the target configuration and adjust /// the language based on the target options where applicable. -void TargetInfo::adjust(LangOptions &Opts) { +void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { if (Opts.NoBitFieldTypeAlign) UseBitFieldTypeAlignment = false; @@ -428,6 +428,11 @@ // its corresponding signed type. PaddingOnUnsignedFixedPoint |= Opts.PaddingOnUnsignedFixedPoint; CheckFixedPointBits(); + + if (Opts.ProtectParens && !checkArithmeticFenceSupported()) { + Diags.Report(diag::err_opt_not_valid_on_target) << "-fprotect-parens"; + Opts.ProtectParens = false; + } } bool TargetInfo::initFeatureMap( diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -93,7 +93,7 @@ void setAddressSpaceMap(bool DefaultIsPrivate); - void adjust(LangOptions &Opts) override; + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (isR600(getTriple())) diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -353,8 +353,8 @@ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } -void AMDGPUTargetInfo::adjust(LangOptions &Opts) { - TargetInfo::adjust(Opts); +void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { + TargetInfo::adjust(Diags, Opts); // ToDo: There are still a few places using default address space as private // address space in OpenCL, which needs to be cleaned up, then Opts.OpenCL // can be removed from the following line. diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -88,7 +88,7 @@ } // Set the language option for altivec based on our value. - void adjust(LangOptions &Opts) override; + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; // Note: GCC recognizes the following additional cpus: // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -573,10 +573,10 @@ Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } -void PPCTargetInfo::adjust(LangOptions &Opts) { +void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { if (HasAltivec) Opts.AltiVec = 1; - TargetInfo::adjust(Opts); + TargetInfo::adjust(Diags, Opts); if (LongDoubleFormat != &llvm::APFloat::IEEEdouble()) LongDoubleFormat = Opts.PPCIEEELongDouble ? &llvm::APFloat::IEEEquad() diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -126,8 +126,8 @@ AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap; } - void adjust(LangOptions &Opts) override { - TargetInfo::adjust(Opts); + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override { + TargetInfo::adjust(Diags, Opts); // FIXME: SYCL specification considers unannotated pointers and references // to be pointing to the generic address space. See section 5.9.3 of // SYCL 2020 specification. diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -138,7 +138,7 @@ bool hasProtectedVisibility() const override { return false; } - void adjust(LangOptions &Opts) override; + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; }; class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -234,7 +234,8 @@ Builtin::FirstTSBuiltin); } -void WebAssemblyTargetInfo::adjust(LangOptions &Opts) { +void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, + LangOptions &Opts) { // If the Atomics feature isn't available, turn off POSIXThreads and // ThreadModel, so that we don't predefine _REENTRANT or __STDCPP_THREADS__. if (!HasAtomics) { diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -356,6 +356,8 @@ } } + bool checkArithmeticFenceSupported() const override { return true; } + CallingConv getDefaultCallingConv() const override { return CC_C; } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2833,6 +2833,33 @@ Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume); return RValue::get(Builder.CreateCall(FnAssume, ArgValue)); } + case Builtin::BI__arithmetic_fence: { + // If FastMath is not selected, the builtin call is skipped. + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + auto FMF = Builder.getFastMathFlags(); + bool isArithmeticFenceEnabled = FMF.allowReassoc(); + QualType ArgType = E->getArg(0)->getType(); + if (ArgType->isComplexType()) { + if (isArithmeticFenceEnabled) { + QualType ElementType = ArgType->castAs()->getElementType(); + ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); + Value *Real = Builder.CreateArithmeticFence(ComplexVal.first, + ConvertType(ElementType)); + Value *Imag = Builder.CreateArithmeticFence(ComplexVal.second, + ConvertType(ElementType)); + return RValue::getComplex(std::make_pair(Real, Imag)); + } + ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); + Value *Real = ComplexVal.first; + Value *Imag = ComplexVal.second; + return RValue::getComplex(std::make_pair(Real, Imag)); + } + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + if (isArithmeticFenceEnabled) + return RValue::get( + Builder.CreateArithmeticFence(ArgValue, ConvertType(ArgType))); + return RValue::get(ArgValue); + } case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2692,6 +2692,10 @@ // If this isn't an FP option skip the claim below default: continue; + case options::OPT_fprotect_parens: + case options::OPT_fno_protect_parens: + break; + // Options controlling individual features case options::OPT_fhonor_infinities: HonorINFs = true; break; case options::OPT_fno_honor_infinities: HonorINFs = false; break; @@ -4906,6 +4910,11 @@ false)) CmdArgs.push_back("-fsplit-stack"); + // -fprotect-parens=0 is default. + if (Args.hasFlag(options::OPT_fprotect_parens, + options::OPT_fno_protect_parens, false)) + CmdArgs.push_back("-fprotect-parens"); + RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs, JA); if (Arg *A = Args.getLastArg(options::OPT_mdouble_EQ)) { diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -588,7 +588,7 @@ // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - Target->adjust(LangOpt); + Target->adjust(PP.getDiagnostics(), LangOpt); // Initialize the preprocessor. PP.Initialize(*Target); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -136,7 +136,7 @@ // Inform the target of the language options. // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - getTarget().adjust(getLangOpts()); + getTarget().adjust(getDiagnostics(), getLangOpts()); // Adjust target options based on codegen options. getTarget().adjustTargetOptions(getCodeGenOpts(), getTargetOpts()); @@ -451,7 +451,7 @@ getSourceManager(), *HeaderInfo, *this, /*IdentifierInfoLookup=*/nullptr, /*OwnsHeaderSearch=*/true, TUKind); - getTarget().adjust(getLangOpts()); + getTarget().adjust(getDiagnostics(), getLangOpts()); PP->Initialize(getTarget(), getAuxTarget()); if (PPOpts.DetailedRecord) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1555,6 +1555,10 @@ Diag(TheCall->getBeginLoc(), diag::warn_alloca) << TheCall->getDirectCallee(); break; + case Builtin::BI__arithmetic_fence: + if (SemaBuiltinArithmeticFence(TheCall)) + return ExprError(); + break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: if (SemaBuiltinAssume(TheCall)) @@ -6378,6 +6382,32 @@ return false; } +/// SemaBuiltinArithmeticFence - Handle __arithmetic_fence. +bool Sema::SemaBuiltinArithmeticFence(CallExpr *TheCall) { + if (!Context.getTargetInfo().checkArithmeticFenceSupported()) + return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) + << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); + Expr *Arg = TheCall->getArg(0); + if (Arg->isInstantiationDependent()) + return false; + + const QualType ArgTy = TheCall->getArg(0)->getType(); + bool IsFloating = [&]() { + if (const VectorType *VT = dyn_cast(ArgTy.getCanonicalType())) + return VT->getElementType().getTypePtr()->isFloatingType(); + if (const ComplexType *CT = dyn_cast(ArgTy.getCanonicalType())) + return CT->getElementType().getTypePtr()->isFloatingType(); + return ArgTy->isFloatingType(); + }(); + if (!IsFloating) + return Diag(TheCall->getEndLoc(), diag::err_typecheck_expect_flt_or_vector) + << ArgTy; + if (checkArgCount(*this, TheCall, 1)) + return true; + TheCall->setType(ArgTy); + return false; +} + /// SemaBuiltinAssume - Handle __assume (MS Extension). // __assume does not evaluate its arguments, and should warn if its argument // has side effects. diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -291,26 +291,6 @@ cast(R.get())); } -static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id, - MultiExprArg CallArgs) { - StringRef Name = S.Context.BuiltinInfo.getName(Id); - LookupResult R(S, &S.Context.Idents.get(Name), Loc, Sema::LookupOrdinaryName); - S.LookupName(R, S.TUScope, /*AllowBuiltinCreation=*/true); - - auto *BuiltInDecl = R.getAsSingle(); - assert(BuiltInDecl && "failed to find builtin declaration"); - - ExprResult DeclRef = - S.BuildDeclRefExpr(BuiltInDecl, BuiltInDecl->getType(), VK_LValue, Loc); - assert(DeclRef.isUsable() && "Builtin reference cannot fail"); - - ExprResult Call = - S.BuildCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc); - - assert(!Call.isInvalid() && "Call to builtin cannot fail!"); - return Call.get(); -} - static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType, SourceLocation Loc) { QualType CoroHandleType = lookupCoroutineHandleType(S, PromiseType, Loc); @@ -327,7 +307,7 @@ } Expr *FramePtr = - buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {}); + S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {}).get(); CXXScopeSpec SS; ExprResult FromAddr = @@ -404,8 +384,8 @@ // the resume call and return instruction, which would interfere with the // musttail call contract. JustAddress = S.MaybeCreateExprWithCleanups(JustAddress); - return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, - JustAddress); + return S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_resume, + JustAddress).get(); } /// Build calls to await_ready, await_suspend, and await_resume for a co_await @@ -1373,10 +1353,10 @@ return false; Expr *FramePtr = - buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {}); + S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {}).get(); Expr *FrameSize = - buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_size, {}); + S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {}).get(); // Make new call. @@ -1405,7 +1385,8 @@ return false; Expr *CoroFree = - buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_free, {FramePtr}); + S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_free, {FramePtr}) + .get(); SmallVector DeleteArgs{CoroFree}; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4006,6 +4006,11 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) { assert(E && "ActOnParenExpr() missing expr"); + QualType ExprTy = E->getType(); + if (getLangOpts().ProtectParens && CurFPFeatures.getAllowFPReassociate() && + (ExprTy->isFloatingType() || (ExprTy->isComplexType()))) { + return BuildBuiltinCallExpr(R, Builtin::BI__arithmetic_fence, E); + } return new (Context) ParenExpr(L, R, E); } @@ -6512,6 +6517,29 @@ ExecConfig, IsExecConfig); } +/// BuildBuiltinCallExpr - Create a call to a builtin function specified by Id +// with the specified CallArgs +ExprResult Sema::BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id, + MultiExprArg CallArgs) { + StringRef Name = Context.BuiltinInfo.getName(Id); + LookupResult R(*this, &Context.Idents.get(Name), Loc, + Sema::LookupOrdinaryName); + LookupName(R, TUScope, /*AllowBuiltinCreation=*/true); + + auto *BuiltInDecl = R.getAsSingle(); + assert(BuiltInDecl && "failed to find builtin declaration"); + + ExprResult DeclRef = + BuildDeclRefExpr(BuiltInDecl, BuiltInDecl->getType(), VK_LValue, Loc); + assert(DeclRef.isUsable() && "Builtin reference cannot fail"); + + ExprResult Call = + BuildCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc); + + assert(!Call.isInvalid() && "Call to builtin cannot fail!"); + return Call; +} + /// Parse a __builtin_astype expression. /// /// __builtin_astype( value, dst type ) diff --git a/clang/test/CodeGen/arithmetic-fence-builtin.c b/clang/test/CodeGen/arithmetic-fence-builtin.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arithmetic-fence-builtin.c @@ -0,0 +1,50 @@ +// Test with fast math +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -DFAST \ +// RUN: -mreassociate \ +// RUN: -o - %s | FileCheck --check-prefixes CHECK,CHECKFAST %s +// +// Test with fast math and fprotect-parens +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -DFAST \ +// RUN: -mreassociate -fprotect-parens\ +// RUN: -o - %s | FileCheck --check-prefixes CHECK,CHECKFAST,CHECKPP %s +// +// Test without fast math: llvm intrinsic not created +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -fprotect-parens\ +// RUN: -o - %s | FileCheck --implicit-check-not="llvm.arithmetic.fence" %s +// +int v; +int addit(float a, float b) { + // CHECK: define {{.*}}@addit(float %a, float %b) #0 { + _Complex double cd, cd1; + cd = __arithmetic_fence(cd1); + // CHECKFAST: call{{.*}} double @llvm.arithmetic.fence.f64({{.*}}real) + // CHECKFAST: call{{.*}} double @llvm.arithmetic.fence.f64({{.*}}imag) + // Vector should be supported. + typedef float __v2f32 __attribute__((__vector_size__(8))); + __v2f32 vec1, vec2; + vec1 = __arithmetic_fence(vec2); + // CHECKFAST: call{{.*}} <2 x float> @llvm.arithmetic.fence.v2f32 + + v = __arithmetic_fence(a + b); + // CHECKFAST: call{{.*}} float @llvm.arithmetic.fence.f32(float %add) + + v = (a + b); + // CHECKPP: call{{.*}} float @llvm.arithmetic.fence.f32(float %add1) + return 0; +} +int addit1(int a, int b) { + // CHECK: define {{.*}}@addit1(i32 %a, i32 %b{{.*}} + v = (a + b); + // CHECK-NOT: call{{.*}} float @llvm.arithmetic.fence.int(float %add) + return 0; +} +#ifdef FAST +#pragma float_control(precise, on) +int subit(float a, float b, float *fp) { + // CHECKFAST: define {{.*}}@subit(float %a, float %b{{.*}} + *fp = __arithmetic_fence(a - b); + *fp = (a + b); + // CHECK-NOT: call{{.*}} float @llvm.arithmetic.fence.f32(float %add) + return 0; +} +#endif diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -1,13 +1,14 @@ // REQUIRES: clang-driver // RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fsplit-stack %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s -// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s +// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-enums -fprotect-parens %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s // CHECK-OPTIONS1: -fsplit-stack // CHECK-OPTIONS1: -fgnu-keywords // CHECK-OPTIONS1: -fblocks // CHECK-OPTIONS1: -fpascal-strings +// CHECK-OPTIONS2: -fprotect-parens // CHECK-OPTIONS2: -fmath-errno // CHECK-OPTIONS2: -fno-gnu-keywords // CHECK-OPTIONS2: -fno-builtin diff --git a/clang/test/Sema/arithmetic-fence-builtin.c b/clang/test/Sema/arithmetic-fence-builtin.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arithmetic-fence-builtin.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - -verify -x c++ %s +// RUN: %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -verify -x c++ %s +// RUN: not %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -x c++ %s \ +// RUN: -fprotect-parens 2>&1 | FileCheck -check-prefix=PPC %s +#ifndef PPC +int v; +template T addT(T a, T b) { + T *q = __arithmetic_fence(&a); + // expected-error@-1 {{operand of type 'float *' where floating, complex or a vector of such types is required ('float *' invalid)}} + // expected-error@-2 {{operand of type 'int *' where floating, complex or a vector of such types is required ('int *' invalid)}} + return __arithmetic_fence(a + b); + // expected-error@-1 {{operand of type 'int' where floating, complex or a vector of such types is required ('int' invalid)}} +} +int addit(int a, int b) { + float x, y; + typedef struct { + int a, b; + } stype; + stype s; + s = __arithmetic_fence(s); // expected-error {{operand of type 'stype' where floating, complex or a vector of such types is required ('stype' invalid)}} + x = __arithmetic_fence(x, y); // expected-error {{too many arguments to function call, expected 1, have 2}} + // Complex is supported. + _Complex double cd, cd1; + cd = __arithmetic_fence(cd1); + // Vector is supported. + typedef float __v4hi __attribute__((__vector_size__(8))); + __v4hi vec1, vec2; + vec1 = __arithmetic_fence(vec2); + + v = __arithmetic_fence(a + b); // expected-error {{operand of type 'int' where floating, complex or a vector of such types is required ('int' invalid)}} + float f = addT(a, b); // expected-note {{in instantiation of function template specialization 'addT' requested here}} + int i = addT(1, 2); // expected-note {{in instantiation of function template specialization 'addT' requested here}} + constexpr float d = 1.0 + 2.0; + constexpr float c = __arithmetic_fence(1.0 + 2.0); + // expected-error@-1 {{constexpr variable 'c' must be initialized by a constant expression}} + return 0; +} +// expected-error@+1 {{static_assert expression is not an integral constant expression}} +static_assert( __arithmetic_fence(1.0 + 2.0), "message" ); +#else +float addit(float a, float b) { + return __arithmetic_fence(a+b); // expected-error {{builtin is not supported on this target}} +} +#endif +//PPC: error: option '-fprotect-parens' cannot be specified on this target diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -208,7 +208,7 @@ TargetInfo *TI = TargetInfo::CreateTargetInfo( Ins->getDiagnostics(), Ins->getInvocation().TargetOpts); Ins->setTarget(TI); - Ins->getTarget().adjust(Ins->getLangOpts()); + Ins->getTarget().adjust(Ins->getDiagnostics(), Ins->getLangOpts()); Ins->createFileManager(); Ins->createSourceManager(Ins->getFileManager()); Ins->createPreprocessor(TU_Complete);