sepavloff created this revision. sepavloff added reviewers: rsmith, rjmccall, andrew.w.kaylor, efriedma, mibintc, kpn, sammccall, hokein. Herald added subscribers: martong, arphaman. Herald added a project: clang.
Now FPOption object is stored in the bits of Stmt class. The space there is limited by 7 bits, which is by far not enough as FPOption is supposed to grow incorporating other options related to floating point operations. The problem was discussed in http://lists.llvm.org/pipermail/cfe-dev/2020-March/064850.html. In short, attempts to put FPOption as a field to relevant AST classes result in substantial increase of AST size because such field would consume memory even for nodes that do not deal with FP operations. As a solution, a new statement node `FloatingPragmaStmt` has been added. It represents a pragma that modifies floating point options. This statement is placed at the beginning of corresponding `CompoundStmt`. It provides persistency for the FP options and allows to maintain actual FP state. Other nodes such as BinaryOperator do not have to have a copy of FPOption, thus no unnecessary memory consumption occurs. If more than one pragma are specified in a compound statement, there is a separate node for each. Each node keeps FP options accumulated from all previous pragma nodes and from this one. Pragma specified at file level results in pragma nodes implicitly inserted into every function body affected by the pragma. In compilation option result in non-default FP options, the synthesized pragma is inserted as well. There are cases when an expression occurs outside compound statement. These are global variable initializers, default arguments and some other. This solution does not work for them, a special expression node is required for them, it will be implemented later. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D76599 Files: clang/include/clang-c/Index.h clang/include/clang/AST/Expr.h clang/include/clang/AST/ExprCXX.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/Stmt.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/Basic/LangOptions.h clang/include/clang/Basic/StmtNodes.td clang/include/clang/Sema/Sema.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ExprConstant.cpp clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/Basic/LangOptions.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Parse/ParsePragma.cpp clang/lib/Parse/ParseStmt.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaStmt.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/test/AST/ast-dump-pragma.cpp clang/test/CodeGen/fp-contract-pragma.cpp clang/test/Coverage/c-language-features.inc clang/tools/libclang/CIndex.cpp clang/tools/libclang/CXCursor.cpp
Index: clang/tools/libclang/CXCursor.cpp =================================================================== --- clang/tools/libclang/CXCursor.cpp +++ clang/tools/libclang/CXCursor.cpp @@ -742,6 +742,10 @@ break; case Stmt::BuiltinBitCastExprClass: K = CXCursor_BuiltinBitCastExpr; + break; + case Stmt::FloatingPragmaStmtClass: + K = CXcursor_FloatingPragmaStmt; + break; } CXCursor C = { K, 0, { Parent, S, TU } }; Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -5612,6 +5612,8 @@ return cxstring::createRef("attribute(warn_unused_result)"); case CXCursor_AlignedAttr: return cxstring::createRef("attribute(aligned)"); + case CXcursor_FloatingPragmaStmt: + return cxstring::createRef("FloatingPragma"); } llvm_unreachable("Unhandled CXCursorKind"); Index: clang/test/Coverage/c-language-features.inc =================================================================== --- clang/test/Coverage/c-language-features.inc +++ clang/test/Coverage/c-language-features.inc @@ -210,3 +210,9 @@ void f11() { struct s12 var = { .aa = 33 }; } + +float pragma_01(float x, float y, float z) { + #pragma clang fp contract(on) + #pragma STDC FP_CONTRACT OFF + return x + y * z; +} Index: clang/test/CodeGen/fp-contract-pragma.cpp =================================================================== --- clang/test/CodeGen/fp-contract-pragma.cpp +++ clang/test/CodeGen/fp-contract-pragma.cpp @@ -89,3 +89,20 @@ #pragma STDC FP_CONTRACT ON return c - a * b; } + +float fp_contract_10(float a, float x, float y, float z) { +// CHECK-LABEL: _Z14fp_contract_10ffff +// CHECK: call float @llvm.fmuladd.f32 +// CHECK: fmul float +// CHECK: fadd float +// CHECK: fadd float +// CHECK: call float @llvm.fmuladd.f32 + #pragma STDC FP_CONTRACT ON + float r = x + y * z; + { + #pragma STDC FP_CONTRACT OFF + r += a + x * y; + } + r += z + x * a; + return r; +} Index: clang/test/AST/ast-dump-pragma.cpp =================================================================== --- /dev/null +++ clang/test/AST/ast-dump-pragma.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefixes=CHECK,NOOPT %s +// RUN: %clang_cc1 -ffp-contract=on -ast-dump %s | FileCheck --check-prefix=FPCONTRACT %s + + +float func_00(float x, float y, float z) { + return x + y * z; +} +// NOOPT-LABEL: FunctionDecl {{.*}} func_00 +// NOOPT: CompoundStmt +// NOOPT-NEXT: ReturnStmt + +// FPCONTRACT-LABEL: FunctionDecl {{.*}} func_00 +// FPCONTRACT: CompoundStmt +// FPCONTRACT-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// FPCONTRACT-NEXT: ReturnStmt + + +float func_01(float x, float y, float z) { + #pragma clang fp contract(on) + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_01 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// CHECK-NEXT: ReturnStmt + + +float func_03(float x, float y, float z) { + #pragma STDC FP_CONTRACT ON + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_03 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma fp_contract ON +// CHECK-NEXT: ReturnStmt + + +float func_05(float x, float y, float z) { + #pragma clang fp contract(on) + #pragma clang fp contract(off) + #pragma clang fp contract(fast) + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_05 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(off) +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(fast) +// CHECK-NEXT: ReturnStmt + + +constexpr float func_06(float x, float y, float z) { + #pragma clang fp contract(on) + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_06 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// CHECK-NEXT: ReturnStmt + + +#pragma clang fp contract(on) + + +float func_07(float x, float y, float z) { + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_07 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// CHECK-NEXT: ReturnStmt + + +float func_08(float x, float y, float z) { + #pragma clang fp contract(off) + return x + y * z; +} +// CHECK-LABEL: FunctionDecl {{.*}} func_08 +// CHECK: CompoundStmt +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(on) +// CHECK-NEXT: FloatingPragmaStmt {{.*}} pragma clang fp contract(off) +// CHECK-NEXT: ReturnStmt Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1395,6 +1395,7 @@ case Stmt::PredefinedExprClass: case Stmt::AddrLabelExprClass: case Stmt::AttributedStmtClass: + case Stmt::FloatingPragmaStmtClass: case Stmt::IntegerLiteralClass: case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -2059,6 +2059,14 @@ Code = serialization::STMT_SEH_LEAVE; } +void ASTStmtWriter::VisitFloatingPragmaStmt(FloatingPragmaStmt *S) { + VisitStmt(S); + Record.writeEnum(S->getKind()); + Record.push_back(S->getFPOptions().getInt()); + Record.AddSourceLocation(S->getPragmaLoc()); + Code = serialization::STMT_FLOATING_PRAGMA; +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -567,6 +567,7 @@ RECORD(STMT_DECL); RECORD(STMT_GCCASM); RECORD(STMT_MSASM); + RECORD(STMT_FLOATING_PRAGMA); RECORD(EXPR_PREDEFINED); RECORD(EXPR_DECL_REF); RECORD(EXPR_INTEGER_LITERAL); Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -2119,6 +2119,13 @@ S->setLeaveLoc(readSourceLocation()); } +void ASTStmtReader::VisitFloatingPragmaStmt(FloatingPragmaStmt *S) { + VisitStmt(S); + S->setKind(static_cast<FloatingPragmaStmt::PragmaKind>(Record.readInt())); + S->getFPOptions() = FPOptions(Record.readInt()); + S->setPragmaLoc(readSourceLocation()); +} + void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) { VisitStmt(S); S->Loc = readSourceLocation(); @@ -3743,7 +3750,7 @@ break; } - case EXPR_REQUIRES: + case EXPR_REQUIRES: { unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; S = RequiresExpr::Create(Context, Empty, numLocalParameters, @@ -3751,6 +3758,11 @@ break; } + case STMT_FLOATING_PRAGMA: + S = new (Context) FloatingPragmaStmt(Empty); + break; + } + // We hit a STMT_STOP, so we're done with this expression. if (Finished) break; Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -8035,6 +8035,12 @@ return S; } +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformFloatingPragmaStmt(FloatingPragmaStmt *S) { + return S; +} + //===----------------------------------------------------------------------===// // OpenMP directive transformation //===----------------------------------------------------------------------===// Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -4467,3 +4467,27 @@ return Res; } + +void Sema::insertPragmaStatements(SmallVectorImpl<Stmt*> &Stmts) { + if (!PragmaStatements.empty()) { + Stmts.insert(Stmts.begin(), PragmaStatements.begin(), + PragmaStatements.end()); + } + PragmaStatements.clear(); +} + +StmtResult Sema::ActOnFloatingPragmaStmt(SourceLocation PragmaLoc, + FloatingPragmaStmt::PragmaKind K) { + if (getCurScope()->getFnParent()) { + auto S = new (Context) FloatingPragmaStmt(K, PragmaLoc, FPFeatures); + PragmaStatements.push_back(S); + return S; + } + return StmtEmpty(); +} + +void Sema::ActOnFPContract(StmtResult S, LangOptions::FPContractModeKind X) { + if (S.isUsable()) + cast<FloatingPragmaStmt>(S.get())->setContract(X); + FPFeatures.setContract(X); +} Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -1566,6 +1566,9 @@ return mergeCanThrow(CT, canThrow(TS->getTryBody())); } + case Stmt::FloatingPragmaStmtClass: + return CT_Cannot; + case Stmt::NoStmtClass: llvm_unreachable("Invalid class for statement"); } Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -2090,6 +2090,9 @@ return false; return true; + case Stmt::FloatingPragmaStmtClass: + return true; + default: if (!isa<Expr>(S)) break; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -13777,6 +13777,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, SkipBodyInfo *SkipBody) { + PragmaStatements.clear(); + if (!D) { // Parsing the function declaration failed in some way. Push on a fake scope // anyway so we can try to parse the function body. @@ -13925,6 +13927,12 @@ getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation) Diag(FD->getLocation(), diag::warn_function_def_in_objc_container); + // If compilation options or file scope pragmas modified floating point state, + // create pragma statement to represent this state. + if (!FPFeatures.isDefault()) + PragmaStatements.push_back(new (Context) FloatingPragmaStmt( + FloatingPragmaStmt::Synthesized, SourceLocation(), FPFeatures)); + return D; } Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -1030,6 +1030,9 @@ StmtVector Stmts; + // If parsing leading pragmas created statements, put them into the body. + Actions.insertPragmaStatements(Stmts); + // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are // only allowed at the start of a compound stmt regardless of the language. while (Tok.is(tok::kw___label__)) { Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -642,7 +642,10 @@ break; } - Actions.ActOnPragmaFPContract(FPC); + StmtResult S = Actions.ActOnFloatingPragmaStmt( + Tok.getLocation(), FloatingPragmaStmt::PragmaFPContract); + Actions.ActOnFPContract(S, FPC); + ConsumeAnnotationToken(); } @@ -2790,7 +2793,9 @@ break; } - Actions.ActOnPragmaFPContract(FPC); + StmtResult S = Actions.ActOnFloatingPragmaStmt( + Tok.getLocation(), FloatingPragmaStmt::PragmaClangFP); + Actions.ActOnFPContract(S, FPC); ConsumeAnnotationToken(); } Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -366,6 +366,7 @@ CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; + FPOptions FPFeatures; typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy; LoopInfoStack LoopStack; @@ -3009,6 +3010,7 @@ void EmitCaseStmt(const CaseStmt &S); void EmitCaseStmtRange(const CaseStmt &S); void EmitAsmStmt(const AsmStmt &S); + void EmitFloatingPragmaStmt(const FloatingPragmaStmt &S); void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -159,6 +159,9 @@ EmitCapturedStmt(*CS, CS->getCapturedRegionKind()); } break; + case Stmt::FloatingPragmaStmtClass: + EmitFloatingPragmaStmt(cast<FloatingPragmaStmt>(*S)); + break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S)); break; @@ -411,6 +414,7 @@ assert((!GetLast || (GetLast && ExprResult)) && "If GetLast is true then the CompoundStmt must have a StmtExprResult"); + FPOptions SaveFPFeatures = FPFeatures; Address RetAlloca = Address::invalid(); for (auto *CurStmt : S.body()) { @@ -451,6 +455,7 @@ EmitStmt(CurStmt); } } + FPFeatures = SaveFPFeatures; return RetAlloca; } @@ -2368,6 +2373,10 @@ } } +void CodeGenFunction::EmitFloatingPragmaStmt(const FloatingPragmaStmt& S) { + FPFeatures = S.getFPOptions(); +} + LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) { const RecordDecl *RD = S.getCapturedRecordDecl(); QualType RecordTy = getContext().getRecordType(RD); Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -213,17 +213,12 @@ (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize; } -/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions. -static void updateFastMathFlags(llvm::FastMathFlags &FMF, - FPOptions FPFeatures) { - FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement()); -} - -/// Propagate fast-math flags from \p Op to the instruction in \p V. -static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) { +/// Propagate fast-math flags from the current FPOtions to the instruction +/// in \p V. +static Value *propagateFMFlags(Value *V, CodeGenFunction &CGF) { if (auto *I = dyn_cast<llvm::Instruction>(V)) { llvm::FastMathFlags FMF = I->getFastMathFlags(); - updateFastMathFlags(FMF, Op.FPFeatures); + FMF.setAllowContract(CGF.FPFeatures.allowFPContractAcrossStatement()); I->setFastMathFlags(FMF); } return V; @@ -744,7 +739,7 @@ if (Ops.LHS->getType()->isFPOrFPVectorTy()) { Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); - return propagateFMFlags(V, Ops); + return propagateFMFlags(V, CGF); } return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } @@ -3416,7 +3411,7 @@ "Only fadd/fsub can be the root of an fmuladd."); // Check whether this op is marked as fusable. - if (!op.FPFeatures.allowFPContractWithinStatement()) + if (!CGF.FPFeatures.allowFPContractWithinStatement()) return nullptr; // We have a potentially fusable op. Look for a mul on one of the operands. @@ -3480,7 +3475,7 @@ return FMulAdd; Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add"); - return propagateFMFlags(V, op); + return propagateFMFlags(V, CGF); } if (op.isFixedPointBinOp()) @@ -3624,7 +3619,7 @@ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) return FMulAdd; Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub"); - return propagateFMFlags(V, op); + return propagateFMFlags(V, CGF); } if (op.isFixedPointBinOp()) Index: clang/lib/Basic/LangOptions.cpp =================================================================== --- clang/lib/Basic/LangOptions.cpp +++ clang/lib/Basic/LangOptions.cpp @@ -47,3 +47,15 @@ const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion; return VersionTuple(Ver / 100, (Ver % 100) / 10); } + +StringRef clang::spell(LangOptions::FPContractModeKind X, bool ShortForm) { + switch (X) { + case LangOptions::FPC_Off: + return ShortForm ? "OFF" : "contract(off)"; + case LangOptions::FPC_On: + return ShortForm ? "ON" : "contract(on)"; + case LangOptions::FPC_Fast: + return ShortForm ? "FAST" : "contract(fast)"; + } + llvm_unreachable("Unexpected value"); +} Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -707,6 +707,22 @@ OS << " gnu_range"; } +void TextNodeDumper::VisitFloatingPragmaStmt(const FloatingPragmaStmt *Node) { + switch (Node->getKind()) { + case FloatingPragmaStmt::Synthesized: + case FloatingPragmaStmt::PragmaClangFP: + OS << " pragma clang fp " + << spell(Node->getFPOptions().getContract(), false); + break; + case FloatingPragmaStmt::PragmaFPContract: + OS << " pragma fp_contract " + << spell(Node->getFPOptions().getContract(), true); + break; + default: + break; + } +} + void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { if (Node->getResultAPValueKind() != APValue::None) { ColorScope Color(OS, ShowColors, ValueColor); Index: clang/lib/AST/StmtProfile.cpp =================================================================== --- clang/lib/AST/StmtProfile.cpp +++ clang/lib/AST/StmtProfile.cpp @@ -405,6 +405,10 @@ VisitStmt(S); } +void StmtProfiler::VisitFloatingPragmaStmt(const FloatingPragmaStmt *S) { + VisitStmt(S); +} + namespace { class OMPClauseProfiler : public ConstOMPClauseVisitor<OMPClauseProfiler> { StmtProfiler *Profiler; Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ clang/lib/AST/StmtPrinter.cpp @@ -954,6 +954,28 @@ } //===----------------------------------------------------------------------===// +// Miscellaneous directives printing methods +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitFloatingPragmaStmt(FloatingPragmaStmt *Node) { + switch (Node->getKind()) { + case FloatingPragmaStmt::PragmaClangFP: + case FloatingPragmaStmt::Synthesized: + Indent() << "#pragma clang fp " + << spell(Node->getFPOptions().getContract(), false); + break; + case FloatingPragmaStmt::PragmaFPContract: + Indent() << "#pragma STDC FP_CONTRACT " + << spell(Node->getFPOptions().getContract(), true); + break; + default: + llvm_unreachable("Unexpected pragma kind"); + } + if (Policy.IncludeNewlines) + OS << NL; +} + +//===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -748,6 +748,9 @@ public: ASTContext &Ctx; + /// Keeps floating point options used in evaluation. + FPOptions FPFeatures; + /// EvalStatus - Contains information about the evaluation. Expr::EvalStatus &EvalStatus; @@ -1335,6 +1338,18 @@ }; typedef ScopeRAII<false> BlockScopeRAII; typedef ScopeRAII<true> FullExpressionRAII; + + class FPOptionsStateRAII { + EvalInfo &Info; + FPOptions SavedState; + + public: + explicit FPOptionsStateRAII(EvalInfo &Info) + : Info(Info), SavedState(Info.FPFeatures) { + } + + ~FPOptionsStateRAII() { Info.FPFeatures = SavedState; } + }; } bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, @@ -4690,6 +4705,7 @@ case Stmt::CompoundStmtClass: { BlockScopeRAII Scope(Info); + FPOptionsStateRAII SavedFPFeatures(Info); const CompoundStmt *CS = cast<CompoundStmt>(S); for (const auto *BI : CS->body()) { @@ -4913,6 +4929,10 @@ case Stmt::CXXTryStmtClass: // Evaluate try blocks by evaluating all sub statements. return EvaluateStmt(Result, Info, cast<CXXTryStmt>(S)->getTryBlock(), Case); + + case Stmt::FloatingPragmaStmtClass: + Info.FPFeatures = cast<FloatingPragmaStmt>(S)->getFPOptions(); + return ESR_Succeeded; } } Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1505,6 +1505,9 @@ /// A MS-style AsmStmt record. STMT_MSASM, + /// A floating point option pragma. + STMT_FLOATING_PRAGMA, + /// A constant expression context. EXPR_CONSTANT, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4417,6 +4417,17 @@ SourceLocation Location, bool AlwaysCreate); + /// Statements created by floating point pragmas inside the current function. + /// The first element may be synthesized to represent file scope pragmas or + /// compilation options. The last element must be in sync with FPFeatures. + SmallVector<FloatingPragmaStmt *, 2> PragmaStatements; + + void insertPragmaStatements(SmallVectorImpl<Stmt *> &Stmts); + + StmtResult ActOnFloatingPragmaStmt(SourceLocation PragmaLoc, + FloatingPragmaStmt::PragmaKind K); + void ActOnFPContract(StmtResult S, LangOptions::FPContractModeKind X); + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, Index: clang/include/clang/Basic/StmtNodes.td =================================================================== --- clang/include/clang/Basic/StmtNodes.td +++ clang/include/clang/Basic/StmtNodes.td @@ -24,6 +24,7 @@ def CaseStmt : StmtNode<SwitchCase>; def DefaultStmt : StmtNode<SwitchCase>; def CapturedStmt : StmtNode<Stmt>; +def FloatingPragmaStmt : StmtNode<Stmt>; // Statements that might produce a value (for example, as the last non-null // statement in a GNU statement-expression). Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -353,6 +353,12 @@ VersionTuple getOpenCLVersionTuple() const; }; +/// Returns text representation for the given contract mode value. +/// If \a ShortMode is true, only corresponding switch value ("ON", "OFF" or +/// "FAST") is returned, otherwise the output string looks like "contract(on)". +/// +StringRef spell(LangOptions::FPContractModeKind X, bool ShortForm); + /// Floating point control options class FPOptions { public: @@ -396,6 +402,14 @@ void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; } + LangOptions::FPContractModeKind getContract() const { + return static_cast<LangOptions::FPContractModeKind>(fp_contract); + } + + void setContract(LangOptions::FPContractModeKind X) { + fp_contract = X; + } + bool allowFEnvAccess() const { return fenv_access == LangOptions::FEA_On; } @@ -428,12 +442,25 @@ allowFEnvAccess(); } + bool isDefault() const { + return *this == FPOptions(); + } + /// Used to serialize this. unsigned getInt() const { return fp_contract | (fenv_access << 2) | (rounding << 3) | (exceptions << 6); } + bool operator == (const FPOptions &O) const { + return fp_contract == O.fp_contract && + fenv_access == O.fenv_access && + rounding == O.rounding && + exceptions == O.exceptions; + } + + bool operator != (const FPOptions &O) const { return !operator==(O); } + private: /// Adjust BinaryOperatorBitfields::FPFeatures and /// CXXOperatorCallExprBitfields::FPFeatures to match the total bit-field size Index: clang/include/clang/AST/TextNodeDumper.h =================================================================== --- clang/include/clang/AST/TextNodeDumper.h +++ clang/include/clang/AST/TextNodeDumper.h @@ -229,6 +229,7 @@ void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); void VisitCaseStmt(const CaseStmt *Node); + void VisitFloatingPragmaStmt(const FloatingPragmaStmt *Node); void VisitConstantExpr(const ConstantExpr *Node); void VisitCallExpr(const CallExpr *Node); void VisitCastExpr(const CastExpr *Node); Index: clang/include/clang/AST/Stmt.h =================================================================== --- clang/include/clang/AST/Stmt.h +++ clang/include/clang/AST/Stmt.h @@ -18,6 +18,7 @@ #include "clang/AST/StmtIterator.h" #include "clang/Basic/CapturedStmt.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" @@ -3590,6 +3591,88 @@ const_child_range children() const; }; +/// This represents a pragma that affects interpretations of the subsequent AST +/// nodes that specify floating point operations. +/// +/// An example of such pragma is 'pragma STDC FE_CONTRACT', which specifies +/// whether operations may be contracted. It results in different code generated +/// for some floating point operations. This and similar pragmas affect the AST +/// nodes contained in the same compound statement where the pragma occurs. +/// +/// Object of this class keeps the state of all properties, that can be modified +/// using pragmas. If more than one of such pragma act in the same compound +/// statement, each subsequent pragma keep options set by this and all preceding +/// pragmas. If a pragma is specified at file level, each affected function will +/// have synthesized pragma statement in its body. Similarly, if FP options +/// differ from defaults because of compilation options, each function body +/// receives such synthesized pragma statement. +/// +class FloatingPragmaStmt : public Stmt { + friend class ASTReader; + friend class ASTStmtReader; + +public: + + /// Enumerates possible pragma representations in source code. + enum PragmaKind { + /// This statement do not correspond to any pragma inside function + /// definition, it represents either pragmas at global level, or changes to + /// floating point environment made by compilation options. + Synthesized, + /// #pragma clang fp + PragmaClangFP, + /// #pragma STDC FP_CONTRACT + PragmaFPContract + }; + +private: + + PragmaKind Kind; + SourceLocation PragmaLoc; + FPOptions FPFeatures; + +public: + + FloatingPragmaStmt(PragmaKind K, SourceLocation Loc, const FPOptions &FPO) + : Stmt(FloatingPragmaStmtClass), Kind(K), PragmaLoc(Loc), FPFeatures(FPO) {} + + explicit FloatingPragmaStmt(EmptyShell E) : Stmt(FloatingPragmaStmtClass, E) {} + + PragmaKind getKind() const { return Kind; } + void setKind(PragmaKind K) { Kind = K; } + + SourceLocation getPragmaLoc() const { return PragmaLoc; } + void setPragmaLoc(SourceLocation L) { PragmaLoc = L; } + + const FPOptions &getFPOptions() const { return FPFeatures; } + FPOptions &getFPOptions() { return FPFeatures; } + + LangOptions::FPContractModeKind getContract() const { + return FPFeatures.getContract(); + } + void setContract(LangOptions::FPContractModeKind X) { + FPFeatures.setContract(X); + } + + SourceLocation getBeginLoc() const LLVM_READONLY { return PragmaLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return PragmaLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FloatingPragmaStmtClass; + } + + static bool classof(FloatingPragmaStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_STMT_H Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -2655,6 +2655,7 @@ DEF_TRAVERSE_STMT(SEHFinallyStmt, {}) DEF_TRAVERSE_STMT(SEHLeaveStmt, {}) DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); }) +DEF_TRAVERSE_STMT(FloatingPragmaStmt, {}) DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {}) DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, { Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -171,12 +171,6 @@ FPOptions getFPFeatures() const { return FPOptions(CXXOperatorCallExprBits.FPFeatures); } - - // Get the FP contractability status of this operator. Only meaningful for - // operations on floating point types. - bool isFPContractableWithinStatement() const { - return getFPFeatures().allowFPContractWithinStatement(); - } }; /// Represents a call to a member function that Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -3573,12 +3573,6 @@ return FPOptions(BinaryOperatorBits.FPFeatures); } - // Get the FP contractability status of this operator. Only meaningful for - // operations on floating point types. - bool isFPContractableWithinStatement() const { - return getFPFeatures().allowFPContractWithinStatement(); - } - // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); } Index: clang/include/clang-c/Index.h =================================================================== --- clang/include/clang-c/Index.h +++ clang/include/clang-c/Index.h @@ -2582,7 +2582,11 @@ */ CXCursor_OMPScanDirective = 287, - CXCursor_LastStmt = CXCursor_OMPScanDirective, + /** Pragma changing floating point options. + */ + CXcursor_FloatingPragmaStmt = 288, + + CXCursor_LastStmt = CXcursor_FloatingPragmaStmt, /** * Cursor that represents the translation unit itself.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits