[clang] 4f1238e - [clang][patch][fpenv] Add builtin __arithmetic_fence and option fprotect-parens
Melanie Blower via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 28 09:27:12 PDT 2021
Author: Melanie Blower
Date: 2021-06-28T12:26:53-04:00
New Revision: 4f1238e44d803b145997fa984677a6c5cdf1f417
URL: https://github.com/llvm/llvm-project/commit/4f1238e44d803b145997fa984677a6c5cdf1f417
DIFF: https://github.com/llvm/llvm-project/commit/4f1238e44d803b145997fa984677a6c5cdf1f417.diff
LOG: [clang][patch][fpenv] Add builtin __arithmetic_fence and option fprotect-parens
This patch adds a new clang builtin, __arithmetic_fence. The purpose of the
builtin is to provide the user fine control, at the expression level, over
floating point optimization when -ffast-math (-ffp-model=fast) is enabled.
The builtin prevents the optimizer from rearranging floating point expression
evaluation. The new option fprotect-parens has the same effect on
parenthesized expressions, forcing the optimizer to respect the parentheses.
Reviewed By: aaron.ballman, kpn
Differential Revision: https://reviews.llvm.org/D100118
Added:
clang/test/AST/arithmetic-fence-builtin.c
clang/test/CodeGen/arithmetic-fence-builtin.c
clang/test/Sema/arithmetic-fence-builtin.c
Modified:
clang/docs/UsersManual.rst
clang/include/clang/Basic/Builtins.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Basic/TargetInfo.h
clang/include/clang/Driver/Options.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/ExprConstant.cpp
clang/lib/Basic/TargetInfo.cpp
clang/lib/Basic/Targets/X86.h
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaCoroutine.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/Driver/clang_f_opts.c
Removed:
################################################################################
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 244212a1336d..9e8bac635337 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1478,6 +1478,26 @@ Note that floating-point operations performed as part of constant initialization
* ``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:
+
+ This option pertains to floating-point types, complex types with
+ floating-point components, and vectors of these types. Some arithmetic
+ expression transformations that are mathematically correct and permissible
+ according to the C and C++ language standards may be incorrect when dealing
+ with floating-point types, such as reassociation and distribution. Further,
+ the optimizer may ignore parentheses when computing arithmetic expressions
+ in circumstances where the parenthesized and unparenthesized expression
+ express the same mathematical value. For example (a+b)+c is the same
+ mathematical value as a+(b+c), but the optimizer is free to evaluate the
+ additions in any order regardless of the parentheses. When enabled, this
+ option forces the optimizer to honor the order of operations with respect
+ to parentheses in all circumstances.
+
+ Note that floating-point contraction (option `-ffp-contract=`) is disabled
+ when `-fprotect-parens` is enabled. Also note that in safe floating-point
+ modes, such as `-ffp-model=precise` or `-ffp-model=strict`, this option
+ has no effect because the optimizer is prohibited from making unsafe
+ transformations.
.. _fp-constant-eval:
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 5a9d0a001829..33d3e6dc4e7d 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -1657,6 +1657,9 @@ BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
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
index 70a22fd2506a..22c2a1a39ea1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8530,6 +8530,9 @@ def err_typecheck_expect_scalar_operand : Error<
"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<
+ "invalid operand of type %0 where floating, complex or "
+ "a vector of such types is required">;
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
index 465bad8d7d11..b18e957a58f4 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -199,6 +199,8 @@ COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
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
index 20f6afa76cbb..4f0cbf986b31 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1424,6 +1424,9 @@ class TargetInfo : public virtual TransferrableTargetInfo,
/// Whether the option -fextend-arguments={32,64} is supported on the target.
virtual bool supportsExtendIntArgs() const { return false; }
+ /// Controls if __arithmetic_fence is supported in the targeted 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
index f1455f546199..0b9596c68f5f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1762,6 +1762,13 @@ defm strict_float_cast_overflow : BoolFOption<"strict-float-cast-overflow",
" of the target's native float-to-int conversion instructions">,
PosFlag<SetTrue, [], "Assume that overflowing float-to-int casts are undefined (default)">>;
+defm protect_parens : BoolFOption<"protect-parens",
+ LangOpts<"ProtectParens">, DefaultFalse,
+ PosFlag<SetTrue, [CoreOption, CC1Option],
+ "Determines whether the optimizer honors parentheses when "
+ "floating-point expressions are evaluated">,
+ NegFlag<SetFalse>>;
+
def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
@@ -4408,7 +4415,7 @@ defm integer_4_integer_8 : BooleanFFlag<"integer-4-integer-8">, Group<gfortran_G
defm max_identifier_length : BooleanFFlag<"max-identifier-length">, Group<gfortran_Group>;
defm module_private : BooleanFFlag<"module-private">, Group<gfortran_Group>;
defm pack_derived : BooleanFFlag<"pack-derived">, Group<gfortran_Group>;
-defm protect_parens : BooleanFFlag<"protect-parens">, Group<gfortran_Group>;
+//defm protect_parens : BooleanFFlag<"protect-parens">, Group<gfortran_Group>;
defm range_check : BooleanFFlag<"range-check">, Group<gfortran_Group>;
defm real_4_real_10 : BooleanFFlag<"real-4-real-10">, Group<gfortran_Group>;
defm real_4_real_16 : BooleanFFlag<"real-4-real-16">, Group<gfortran_Group>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4c3a7035bcc9..3f7db9bc5be8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -36,6 +36,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"
@@ -5424,6 +5425,8 @@ class Sema final {
Expr *ExecConfig = nullptr,
bool IsExecConfig = false,
bool AllowRecovery = false);
+ Expr *BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id,
+ MultiExprArg CallArgs);
enum class AtomicArgumentOrder { API, AST };
ExprResult
BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
@@ -12583,6 +12586,7 @@ class Sema final {
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
index a4d8fec09748..01c0168d61a4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13692,6 +13692,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.changeSign();
return true;
+ case Builtin::BI__arithmetic_fence:
+ return EvaluateFloat(E->getArg(0), Result, Info);
+
// FIXME: Builtin::BI__builtin_powi
// FIXME: Builtin::BI__builtin_powif
// FIXME: Builtin::BI__builtin_powil
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 4c2859e5eda7..88086fa2fed7 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -430,6 +430,11 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
// 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/X86.h b/clang/lib/Basic/Targets/X86.h
index 7639ea835ebc..e798962617a3 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -362,6 +362,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
}
}
+ 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
index 2e9454921ffa..6702181e7b76 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2833,6 +2833,36 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
return RValue::get(Builder.CreateCall(FnAssume, ArgValue));
}
+ case Builtin::BI__arithmetic_fence: {
+ // Create the builtin call if FastMath is selected, and the target
+ // supports the builtin, otherwise just return the argument.
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
+ llvm::FastMathFlags FMF = Builder.getFastMathFlags();
+ bool isArithmeticFenceEnabled =
+ FMF.allowReassoc() &&
+ getContext().getTargetInfo().checkArithmeticFenceSupported();
+ QualType ArgType = E->getArg(0)->getType();
+ if (ArgType->isComplexType()) {
+ if (isArithmeticFenceEnabled) {
+ QualType ElementType = ArgType->castAs<ComplexType>()->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
index c265e1c4e53c..fd26d04e39bc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4975,6 +4975,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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_fextend_args_EQ)) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 17eeebb0c679..4d04f3017a2e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1554,6 +1554,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
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))
@@ -6549,6 +6553,29 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
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());
+ if (checkArgCount(*this, TheCall, 1))
+ return true;
+ Expr *Arg = TheCall->getArg(0);
+ if (Arg->isInstantiationDependent())
+ return false;
+
+ QualType ArgTy = Arg->getType();
+ if (!ArgTy->hasFloatingRepresentation())
+ return Diag(TheCall->getEndLoc(), diag::err_typecheck_expect_flt_or_vector)
+ << ArgTy;
+ if (Arg->isLValue()) {
+ ExprResult FirstArg = DefaultLvalueConversion(Arg);
+ TheCall->setArg(0, FirstArg.get());
+ }
+ TheCall->setType(TheCall->getArg(0)->getType());
+ 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
index cec80436d575..31a4092b5b60 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -291,26 +291,6 @@ static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
cast<UnresolvedLookupExpr>(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<FunctionDecl>();
- 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 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
}
Expr *FramePtr =
- buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {});
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {});
CXXScopeSpec SS;
ExprResult FromAddr =
@@ -404,8 +384,8 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
// 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);
}
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
@@ -1357,10 +1337,10 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
Expr *FramePtr =
- buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {});
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_frame, {});
Expr *FrameSize =
- buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_size, {});
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {});
// Make new call.
@@ -1389,7 +1369,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
Expr *CoroFree =
- buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_free, {FramePtr});
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_free, {FramePtr});
SmallVector<Expr *, 2> DeleteArgs{CoroFree};
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6031dff67335..3df74b5ea9db 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4054,6 +4054,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) {
assert(E && "ActOnParenExpr() missing expr");
+ QualType ExprTy = E->getType();
+ if (getLangOpts().ProtectParens && CurFPFeatures.getAllowFPReassociate() &&
+ !E->isLValue() && ExprTy->hasFloatingRepresentation())
+ return BuildBuiltinCallExpr(R, Builtin::BI__arithmetic_fence, E);
return new (Context) ParenExpr(L, R, E);
}
@@ -6560,6 +6564,29 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
ExecConfig, IsExecConfig);
}
+/// BuildBuiltinCallExpr - Create a call to a builtin function specified by Id
+// with the specified CallArgs
+Expr *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<FunctionDecl>();
+ 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.get();
+}
+
/// Parse a __builtin_astype expression.
///
/// __builtin_astype( value, dst type )
diff --git a/clang/test/AST/arithmetic-fence-builtin.c b/clang/test/AST/arithmetic-fence-builtin.c
new file mode 100644
index 000000000000..46666b3c8bed
--- /dev/null
+++ b/clang/test/AST/arithmetic-fence-builtin.c
@@ -0,0 +1,46 @@
+// Tests without serialization:
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu %s \
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK,CHECK1
+//
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu -DFAST -mreassociate %s \
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK,CHECK1
+//
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu -DFAST -mreassociate %s \
+// RUN: -fprotect-parens \
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK,CHECK2
+//
+// Tests with serialization:
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -include-pch %t -ast-dump-all /dev/null \
+// RUN: | FileCheck %s --strict-whitespace
+//
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu -DFAST -mreassociate %s \
+// RUN: -emit-pch -o %t
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -include-pch %t -ast-dump-all /dev/null \
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK,CHECK1
+//
+// RUN: %clang_cc1 -ast-dump -triple i386-pc-linux-gnu -DFAST -mreassociate %s \
+// RUN: -fprotect-parens \
+// RUN: -emit-pch -o %t
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -include-pch %t -ast-dump-all /dev/null -fprotect-parens\
+// RUN: | FileCheck %s --strict-whitespace --check-prefixes=CHECK,CHECK2
+
+//
+int v;
+int addit(float a, float b) {
+
+ v = __arithmetic_fence(a + b);
+
+ v = (a + b);
+
+ return 0;
+}
+//CHECK:| `-CompoundStmt {{.*}}
+//CHECK-NEXT:| |-BinaryOperator {{.*}} 'int' '='
+//CHECK-NEXT:| | |-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'v' 'int'
+//CHECK-NEXT:| | `-ImplicitCastExpr {{.*}}
+//CHECK-NEXT:| | `-CallExpr {{.*}} 'float'
+//CHECK-NEXT:| | |-ImplicitCastExpr {{.*}}
+//CHECK-NEXT:| | | `-DeclRefExpr {{.*}}' Function {{.*}} '__arithmetic_fence'{{.*}}
+//CHECK1-NOT:| | | `-DeclRefExpr {{.*}}' Function{{.*}} '__arithmetic_fence' 'void ()'
+//CHECK2:| | | `-DeclRefExpr {{.*}} Function{{.*}} '__arithmetic_fence' 'void ()'
diff --git a/clang/test/CodeGen/arithmetic-fence-builtin.c b/clang/test/CodeGen/arithmetic-fence-builtin.c
new file mode 100644
index 000000000000..6b5b5b4b9cef
--- /dev/null
+++ b/clang/test/CodeGen/arithmetic-fence-builtin.c
@@ -0,0 +1,74 @@
+// 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,CHECKNP %s
+//
+// Test with fast math and fprotect-parens
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -DFAST \
+// RUN: -mreassociate -fprotect-parens -ffp-contract=on\
+// 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
+ vec2 = (vec2 + vec1);
+ // CHECKPP: 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 %add{{.*}})
+ v = a + (b*b);
+ // CHECKPP: fmul reassoc
+ // CHECKPP-NEXT: call{{.*}} float @llvm.arithmetic.fence.f32(float %mul)
+ // CHECKNP: fmul
+ // CHECKNP: fadd
+ v = b + a*a;
+ // CHECKPP: call{{.*}} float @llvm.fmuladd.f32
+ // CHECKNP: fmul
+ // CHECKNP: fadd
+ v = b + __arithmetic_fence(a*a); // Fence blocks recognition of FMA
+ // CHECKPP: fmul
+ // CHECKNP: fmul
+
+ b = (a);
+ (a) = b;
+ // CHECK-NEXT fptosi
+ // CHECK-NEXT store i32
+ // CHECK-NEXT load float
+ // CHECK-NEXT store float
+ // CHECK-NEXT load float
+ // CHECK-NEXT store float
+ return 0;
+ // CHECK-NEXT ret i32 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
index a255f68713ae..d729378403f3 100644
--- 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
index 000000000000..4f4f0a02cde9
--- /dev/null
+++ b/clang/test/Sema/arithmetic-fence-builtin.c
@@ -0,0 +1,48 @@
+// 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 <typename T> T addT(T a, T b) {
+ T *q = __arithmetic_fence(&a);
+ // expected-error at -1 {{invalid operand of type 'float *' where floating, complex or a vector of such types is required}}
+ // expected-error at -2 {{invalid operand of type 'int *' where floating, complex or a vector of such types is required}}
+ return __arithmetic_fence(a + b);
+ // expected-error at -1 {{invalid operand of type 'int' where floating, complex or a vector of such types is required}}
+}
+int addit(int a, int b) {
+ float x, y;
+ typedef struct {
+ int a, b;
+ } stype;
+ stype s;
+ s = __arithmetic_fence(s); // expected-error {{invalid operand of type 'stype' where floating, complex or a vector of such types is required}}
+ x = __arithmetic_fence(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+ 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 {{invalid operand of type 'int' where floating, complex or a vector of such types is required}}
+ float f = addT<float>(a, b); // expected-note {{in instantiation of function template specialization 'addT<float>' requested here}}
+ int i = addT<int>(1, 2); // expected-note {{in instantiation of function template specialization 'addT<int>' requested here}}
+ constexpr float d = 1.0 + 2.0;
+ constexpr float c = __arithmetic_fence(1.0 + 2.0);
+ constexpr float e = __arithmetic_fence(d);
+ return 0;
+}
+bool func(float f1, float f2, float f3) {
+ return (f1 == f2 && f1 == f3) || f2 == f3; // Should not warn here
+}
+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
More information about the cfe-commits
mailing list