mibintc created this revision. mibintc added reviewers: sepavloff, rjmccall. Herald added a project: clang. mibintc requested review of this revision.
I rebased https://reviews.llvm.org/D69272 to work on the blocking comment from @rsmith @sepavloff Is it OK if I continue work on this item? Not sure about the protocol when continuing someone else's patch. @rsmith asked "I don't see changes to the constant evaluator". The semantic rules for enabling this pragma require that strict or precise semantics be in effect., see SemaAttr.cpp And the floating point constant evaluation doesn't occur when strict or precise One of the test cases in this patch shows 1+2 isn't folded in strict mode. However, I don't see where is the decision about floating point constant folding, can someone tell me where that occurs? . I thought the constant folding was in AST/ExprConstant.cpp and indeed constant folding does occur there. But sometimes, if the floating point semantics are set to 'strict', even tho' folding has occurred successfully in ExprConstant.cpp, when i look at emit-llvm, there is arithmetic emitted for the floating point expression; For example if you use the command line option -ffp-exception-behavior=strict and you compile this function, it will emit the add instruction; but without the option you will see the folded expression 3.0. Either way (i.e. regardless of option) if you put a breakpoint inside ExprConstant.cpp the calculation of the floating sum does occur. The function is float myAdd(void) { return 1.0 + 2.0; } Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D87528 Files: clang/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Sema/Sema.h clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.h clang/lib/Parse/ParsePragma.cpp clang/lib/Parse/ParseStmt.cpp clang/lib/Sema/SemaStmt.cpp clang/test/CodeGen/fp-floatcontrol-pragma.cpp clang/test/CodeGen/pragma-fenv_access.c clang/test/Parser/fp-floatcontrol-syntax.cpp clang/test/Parser/pragma-fenv_access.c clang/test/Preprocessor/pragma_unknown.c
Index: clang/test/Preprocessor/pragma_unknown.c =================================================================== --- clang/test/Preprocessor/pragma_unknown.c +++ clang/test/Preprocessor/pragma_unknown.c @@ -16,15 +16,6 @@ // CHECK: {{^}}#pragma STDC FP_CONTRACT DEFAULT{{$}} // CHECK: {{^}}#pragma STDC FP_CONTRACT IN_BETWEEN{{$}} -#pragma STDC FENV_ACCESS ON // expected-warning {{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#pragma STDC FENV_ACCESS OFF -#pragma STDC FENV_ACCESS DEFAULT -#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS ON{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS OFF{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS DEFAULT{{$}} -// CHECK: {{^}}#pragma STDC FENV_ACCESS IN_BETWEEN{{$}} - #pragma STDC CX_LIMITED_RANGE ON #pragma STDC CX_LIMITED_RANGE OFF #pragma STDC CX_LIMITED_RANGE DEFAULT Index: clang/test/Parser/pragma-fenv_access.c =================================================================== --- /dev/null +++ clang/test/Parser/pragma-fenv_access.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}} + +#pragma STDC FENV_ACCESS OFF + +float func_04(int x, float y) { + if (x) + return y + 2; + #pragma STDC FENV_ACCESS ON // expected-error{{'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a compound statement}} + return x + y; +} Index: clang/test/Parser/fp-floatcontrol-syntax.cpp =================================================================== --- clang/test/Parser/fp-floatcontrol-syntax.cpp +++ clang/test/Parser/fp-floatcontrol-syntax.cpp @@ -26,19 +26,14 @@ double a = 0.0; double b = 1.0; -//FIXME At some point this warning will be removed, until then -// document the warning -#ifdef FAST -// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#pragma STDC FENV_ACCESS ON -#else -#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} -#endif #ifdef STRICT #pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}} #else +#ifndef FAST // Currently FENV_ACCESS cannot be enabled by pragma, skip error check -#pragma float_control(precise, off) // not-expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}} +#pragma STDC FENV_ACCESS ON +#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}} +#endif #endif #pragma float_control(precise, on) Index: clang/test/CodeGen/pragma-fenv_access.c =================================================================== --- /dev/null +++ clang/test/CodeGen/pragma-fenv_access.c @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -ffp-exception-behavior=strict -frounding-math -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s + +#pragma STDC FENV_ACCESS ON + +float func_01(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_01 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") + + +float func_02(float x, float y) { + #pragma STDC FENV_ACCESS OFF + return x + y; +} +// CHECK-LABEL: @func_02 +// CHECK: fadd float {{.*}} + + +float func_03(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_03 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") + + +#pragma STDC FENV_ACCESS OFF + +float func_04(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_04 +// CHECK: fadd float {{.*}} + + +float func_05(float x, float y) { + #pragma STDC FENV_ACCESS ON + return x + y; +} +// CHECK-LABEL: @func_05 +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") + + +float func_06(float x, float y) { + return x + y; +} +// CHECK-LABEL: @func_06 +// CHECK: fadd float {{.*}} + + +float func_07(float x, float y) { + x -= y; + if (x) { + #pragma STDC FENV_ACCESS ON + y *= 2; + } + return y + 4; +} +// CHECK-LABEL: @func_07 +// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") +// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict") Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp =================================================================== --- clang/test/CodeGen/fp-floatcontrol-pragma.cpp +++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -verify -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s // RUN: %clang_cc1 -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s // Verify float_control(precise, off) enables fast math flags on fp operations. @@ -138,7 +138,6 @@ // CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}} #if FENV_ON -// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} #pragma STDC FENV_ACCESS ON #endif // CHECK-LABEL: define {{.*}}callt{{.*}} @@ -146,7 +145,16 @@ void callt() { volatile float z; z = z * z; -//CHECK: = fmul float + //CHECK-FENV: llvm.experimental.constrained.fmul{{.*}} +} + +// CHECK-LABEL: define {{.*}}myAdd{{.*}} +float myAdd() { + return 1.0 + 2.0; + // Check that floating point constant folding doesn't occur if + // #pragma STC FENV_ACCESS is enabled. + //CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}} + //CHECK: ret float 3.0{{.*}} } #if EXCEPT Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -389,6 +389,13 @@ PopCompoundScope(); } +void Sema::ActOnAfterCompoundStatementLeadingPragmas() { + if (getCurFPFeatures().getAllowFEnvAccess()) { + FunctionDecl *F = getCurFunctionDecl(); + F->setUsesFPIntrin(true); + } +} + sema::CompoundScopeInfo &Sema::getCurCompoundScope() const { return getCurFunction()->CompoundScopes.back(); } Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -366,7 +366,8 @@ case tok::annot_pragma_fenv_access: ProhibitAttributes(Attrs); - HandlePragmaFEnvAccess(); + Diag(Tok, diag::err_pragma_stdc_fenv_access_scope); + ConsumeAnnotationToken(); return StmtEmpty(); case tok::annot_pragma_fenv_round: @@ -1033,9 +1034,9 @@ Tok.getLocation(), "in compound statement ('{}')"); - // Record the state of the FPFeatures, restore on leaving the + // Record the current FPFeatures, restore on leaving the // compound statement. - Sema::FPFeaturesStateRAII SaveFPContractState(Actions); + Sema::FPFeaturesStateRAII SaveFPFeatures(Actions); InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); @@ -1046,6 +1047,7 @@ // Parse any pragmas at the beginning of the compound statement. ParseCompoundStatementLeadingPragmas(); + Actions.ActOnAfterCompoundStatementLeadingPragmas(); StmtVector Stmts; Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -106,10 +106,6 @@ tok::OnOffSwitch OOS; if (PP.LexOnOffSwitch(OOS)) return; - if (OOS == tok::OOS_ON) { - PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported); - return; - } MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), 1); Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1137,6 +1137,10 @@ /// definition. void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F); + /// Set the LLVM function attributes that represent floating point + /// environment. + void setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F); + /// Return true iff the given type uses 'sret' when used as a return type. bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -1725,6 +1725,15 @@ } } +void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D, + llvm::Function *F) { + if (D->usesFPIntrin()) { + llvm::AttrBuilder FuncAttrs; + FuncAttrs.addAttribute("strictfp"); + F->addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); + } +} + void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) { const Decl *D = GD.getDecl(); if (dyn_cast_or_null<NamedDecl>(D)) @@ -4554,9 +4563,11 @@ MaybeHandleStaticInExternC(D, Fn); - maybeSetTrivialComdat(*D, *Fn); + // Set CodeGen attributes that represent floating point environment. + setLLVMFunctionFEnvAttributes(D, Fn); + CodeGenFunction(*this).GenerateCode(GD, Fn, FI); setNonAliasAttributes(GD, Fn); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -900,8 +900,10 @@ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { Builder.setIsFPConstrained(FD->usesFPIntrin()); - if (FD->usesFPIntrin()) + if (FD->usesFPIntrin()) { Fn->addFnAttr(llvm::Attribute::StrictFP); + Builder.setIsFPConstrained(true); + } } // If a custom alignment is used, force realigning to this alignment on Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4329,6 +4329,7 @@ void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr); + void ActOnAfterCompoundStatementLeadingPragmas(); /// A RAII object to enter scope of a compound statement. class CompoundScopeRAII { Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1133,9 +1133,9 @@ // - #pragma stdc unknown def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, InGroup<UnknownPragmas>; -def warn_stdc_fenv_access_not_supported : - Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, - InGroup<UnknownPragmas>; +def err_pragma_stdc_fenv_access_scope : Error< + "'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a " + "compound statement">; def warn_stdc_fenv_round_not_supported : Warning<"pragma STDC FENV_ROUND is not supported">, InGroup<UnknownPragmas>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits