mibintc updated this revision to Diff 256648. mibintc added a comment. I finally decided that combining BinaryOperator and CompoundAssignOperator was too difficult, this patch uses the trailing object approach similar to that used in CallExpr. @rjmccall thank you once again for all your reviews in developing this patch. I hope that this version is acceptable or within a hair's breadth of acceptable. As an experiment to confirm to myself that the trailing storage was only active in the pragma case, i added a "assert(0)" to getStoredFPFeatures. In that case check-clang showed 5 expected fails for the pragma tests cases. ( Clang :: CodeGen/constrained-math-builtins.c Clang :: CodeGen/fp-contract-fast-pragma.cpp Clang :: CodeGen/fp-contract-on-asm.c Clang :: CodeGen/fp-contract-on-pragma.cpp Clang :: CodeGen/fp-contract-pragma.cpp)
Then i removed that assert before submitting this to review. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D76384/new/ https://reviews.llvm.org/D76384 Files: clang/include/clang/AST/Expr.h clang/include/clang/AST/ExprCXX.h clang/include/clang/AST/Stmt.h clang/include/clang/Basic/LangOptions.h clang/lib/AST/ASTImporter.cpp clang/lib/AST/Expr.cpp clang/lib/AST/ExprCXX.cpp clang/lib/Analysis/BodyFarm.cpp clang/lib/Basic/LangOptions.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGObjC.cpp clang/lib/CodeGen/CGStmtOpenMP.cpp clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp clang/lib/Frontend/Rewrite/RewriteObjC.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaPseudoObject.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterStmt.cpp
Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -918,11 +918,16 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) { VisitExpr(E); + bool HasFPFeatures = E->hasStoredFPFeatures(); + // Write this first for easy access when deserializing, as they affect the + // size of the UnaryOperator. + Record.push_back(HasFPFeatures); + Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.AddStmt(E->getLHS()); Record.AddStmt(E->getRHS()); - Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.AddSourceLocation(E->getOperatorLoc()); - Record.push_back(E->getFPFeatures().getInt()); + if (HasFPFeatures) + Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt()); Code = serialization::EXPR_BINARY_OPERATOR; } @@ -1513,7 +1518,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); Record.push_back(E->getOperator()); - Record.push_back(E->getFPFeatures().getInt()); + Record.push_back(E->getFPFeatures().getAsOpaqueInt()); Record.AddSourceRange(E->Range); Code = serialization::EXPR_CXX_OPERATOR_CALL; } Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -3905,7 +3905,7 @@ /// Write an FP_PRAGMA_OPTIONS block for the given FPOptions. void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { - RecordData::value_type Record[] = {Opts.getInt()}; + RecordData::value_type Record[] = {Opts.getAsOpaqueInt()}; Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -1050,12 +1050,16 @@ } void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { + bool hasFP_Features; + BinaryOperator::Opcode opc; VisitExpr(E); + E->setHasStoredFPFeatures(hasFP_Features = Record.readInt()); + E->setOpcode(opc = (BinaryOperator::Opcode)Record.readInt()); E->setLHS(Record.readSubExpr()); E->setRHS(Record.readSubExpr()); - E->setOpcode((BinaryOperator::Opcode)Record.readInt()); E->setOperatorLoc(readSourceLocation()); - E->setFPFeatures(FPOptions(Record.readInt())); + if (hasFP_Features) + E->setStoredFPFeatures(FPOptions(Record.readInt())); } void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -2937,11 +2941,13 @@ break; case EXPR_BINARY_OPERATOR: - S = new (Context) BinaryOperator(Empty); + S = BinaryOperator::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); break; case EXPR_COMPOUND_ASSIGN_OPERATOR: - S = new (Context) CompoundAssignOperator(Empty); + S = CompoundAssignOperator::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); break; case EXPR_CONDITIONAL_OPERATOR: Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -10267,11 +10267,15 @@ RHS.get() == E->getRHS()) return E; + if (E->isCompoundAssignmentOp()) + // FPFeatures has already been established from trailing storage + return getDerived().RebuildBinaryOperator( + E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - getSema().FPFeatures = E->getFPFeatures(); + getSema().FPFeatures = E->getFPFeatures(getSema().getASTContext()); - return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), - LHS.get(), RHS.get()); + return getDerived().RebuildBinaryOperator( + E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); } template <typename Derived> @@ -10322,6 +10326,8 @@ ExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( CompoundAssignOperator *E) { + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); + getSema().FPFeatures = E->getFPFeatures(getSema().getASTContext()); return getDerived().TransformBinaryOperator(E); } Index: clang/lib/Sema/SemaPseudoObject.cpp =================================================================== --- clang/lib/Sema/SemaPseudoObject.cpp +++ clang/lib/Sema/SemaPseudoObject.cpp @@ -448,11 +448,11 @@ ExprResult result; if (opcode == BO_Assign) { result = semanticRHS; - syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, - opcode, capturedRHS->getType(), - capturedRHS->getValueKind(), - OK_Ordinary, opcLoc, - FPOptions()); + syntactic = BinaryOperator::Create( + S.Context, syntacticLHS, capturedRHS, opcode, capturedRHS->getType(), + capturedRHS->getValueKind(), OK_Ordinary, opcLoc, + FPOptions::defaultWithoutTrailingStorage(S.Context)); + } else { ExprResult opLHS = buildGet(); if (opLHS.isInvalid()) return ExprError(); @@ -463,14 +463,13 @@ result = S.BuildBinOp(Sc, opcLoc, nonCompound, opLHS.get(), semanticRHS); if (result.isInvalid()) return ExprError(); - syntactic = - new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, - result.get()->getType(), - result.get()->getValueKind(), - OK_Ordinary, - opLHS.get()->getType(), - result.get()->getType(), - opcLoc, FPOptions()); + syntactic = CompoundAssignOperator::Create( + S.Context, syntacticLHS, capturedRHS, opcode, result.get()->getType(), + result.get()->getValueKind(), OK_Ordinary, opcLoc, + FPOptions::defaultWithoutTrailingStorage(S.Context), + opLHS.get()->getType(), + result.get()->getType()); + } // The result of the assignment, if not void, is the value set into @@ -1586,9 +1585,9 @@ Expr *LHS, Expr *RHS) { // Do nothing if either argument is dependent. if (LHS->isTypeDependent() || RHS->isTypeDependent()) - return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc, - FPOptions()); + return BinaryOperator::Create(Context, LHS, RHS, opcode, + Context.DependentTy, VK_RValue, OK_Ordinary, opcLoc, + FPOptions::defaultWithoutTrailingStorage(Context)); // Filter out non-overload placeholder types in the RHS. if (RHS->getType()->isNonOverloadPlaceholderType()) { @@ -1648,21 +1647,25 @@ = dyn_cast<CompoundAssignOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); - return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), - cop->getType(), - cop->getValueKind(), - cop->getObjectKind(), - cop->getComputationLHSType(), - cop->getComputationResultType(), - cop->getOperatorLoc(), - FPOptions()); + return CompoundAssignOperator::Create(Context, + lhs, rhs, cop->getOpcode(), + cop->getType(), + cop->getValueKind(), + cop->getObjectKind(), + cop->getOperatorLoc(), + FPOptions::defaultWithoutTrailingStorage(Context), + cop->getComputationLHSType(), + cop->getComputationResultType()); + } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); - return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), - bop->getType(), bop->getValueKind(), - bop->getObjectKind(), - bop->getOperatorLoc(), FPOptions()); + return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(), + bop->getType(), bop->getValueKind(), + bop->getObjectKind(), + bop->getOperatorLoc(), + FPOptions::defaultWithoutTrailingStorage(Context)); + } else if (isa<CallExpr>(syntax)) { return syntax; } else { Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -12974,8 +12974,8 @@ Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray, - Context.DependentTy, VK_RValue, OpLoc, - FPOptions()); + Context.DependentTy, VK_RValue, OpLoc, + FPOptions::defaultWithoutTrailingStorage(Context)); } // Build an empty overload set. @@ -13049,7 +13049,7 @@ Args[0] = Input; CallExpr *TheCall = CXXOperatorCallExpr::Create( Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc, - FPOptions(), Best->IsADLCandidate); + FPFeatures, Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -13218,14 +13218,12 @@ // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BO_Assign || Opc > BO_OrAssign) - return new (Context) BinaryOperator( - Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary, - OpLoc, FPFeatures); - - return new (Context) CompoundAssignOperator( + return BinaryOperator::Create(Context, Args[0], Args[1], Opc, + Context.DependentTy, VK_RValue, + OK_Ordinary, OpLoc, FPFeatures); + return CompoundAssignOperator::Create(Context, Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary, - Context.DependentTy, Context.DependentTy, OpLoc, - FPFeatures); + OpLoc, FPFeatures, Context.DependentTy, Context.DependentTy); } // FIXME: save results of ADL from here? @@ -13672,8 +13670,8 @@ // Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to // bind the OpaqueValueExprs before they're (repeatedly) used. - Expr *SyntacticForm = new (Context) - BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), + Expr *SyntacticForm = BinaryOperator::Create(Context, + OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), Result.get()->getValueKind(), Result.get()->getObjectKind(), OpLoc, FPFeatures); Expr *SemanticForm[] = {LHS, RHS, Result.get()}; @@ -13705,8 +13703,8 @@ // Can't add any actual overloads yet return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args, - Context.DependentTy, VK_RValue, RLoc, - FPOptions()); + Context.DependentTy, VK_RValue, RLoc, + FPOptions::defaultWithoutTrailingStorage(Context)); } // Handle placeholders on both operands. @@ -14405,7 +14403,8 @@ CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), MethodArgs, - ResultTy, VK, RParenLoc, FPOptions()); + ResultTy, VK, RParenLoc, + FPOptions::defaultWithoutTrailingStorage(Context)); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; @@ -14522,7 +14521,7 @@ ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPOptions()); + Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPFeatures); if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method)) return ExprError(); Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -7001,9 +7001,11 @@ return ExprError(); if (RHS.get() == BO->getRHS()) return E; - return new (Context) BinaryOperator( - BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), - BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); + return BinaryOperator::Create( + Context, BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), + BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(), + BO->getFPFeatures(getASTContext())); + } } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -13358,13 +13358,13 @@ BinOpResTy = S.GetSignedVectorType(BinOpResTy); if (IsCompAssign) - return new (Context) CompoundAssignOperator( - LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, - OpLoc, FPFeatures); + return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy, + VK, OK, OpLoc, FPFeatures, + BinOpResTy, BinOpResTy); LHS = convertVector(LHS.get(), Context.FloatTy, S); - auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, - VK, OK, OpLoc, FPFeatures); + auto *BO = BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, + BinOpResTy, VK, OK, OpLoc, FPFeatures); return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S); } @@ -13686,8 +13686,8 @@ if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, OpLoc, FPFeatures); - return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, - OK, OpLoc, FPFeatures); + return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy, + VK, OK, OpLoc, FPFeatures); } // Handle compound assignments. @@ -13701,9 +13701,9 @@ return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, OpLoc, FPFeatures); - return new (Context) CompoundAssignOperator( - LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, - OpLoc, FPFeatures); + return CompoundAssignOperator::Create(Context, + LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, FPFeatures, + CompLHSTy, CompResultTy); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -13662,11 +13662,12 @@ // Create the comparison against the array bound. llvm::APInt Upper = ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType)); - Expr *Comparison - = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc), + Expr *Comparison = BinaryOperator::Create(S.Context, + IterationVarRefRVal.build(S, Loc), IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), - BO_NE, S.Context.BoolTy, - VK_RValue, OK_Ordinary, Loc, FPOptions()); + BO_NE, S.Context.BoolTy, + VK_RValue, OK_Ordinary, Loc, + FPOptions::defaultWithoutTrailingStorage(S.Context)); // Create the pre-increment of the iteration variable. We can determine // whether the increment will overflow based on the value of the array Index: clang/lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -2996,9 +2996,10 @@ Context->IntTy, SourceLocation()); BinaryOperator *lessThanExpr = - new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation(), - FPOptions()); + BinaryOperator::Create(*Context, + sizeofExpr, limit, BO_LE, Context->IntTy, + VK_RValue, OK_Ordinary, SourceLocation(), + FPOptions::defaultWithoutTrailingStorage(*Context)); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -7485,9 +7485,10 @@ DeclRefExpr(*Context, NewVD, false, Context->UnsignedLongTy, VK_LValue, SourceLocation()); BinaryOperator *addExpr = - new (Context) BinaryOperator(castExpr, DRE, BO_Add, - Context->getPointerType(Context->CharTy), - VK_RValue, OK_Ordinary, SourceLocation(), FPOptions()); + BinaryOperator::Create(*Context, castExpr, DRE, BO_Add, + Context->getPointerType(Context->CharTy), + VK_RValue, OK_Ordinary, SourceLocation(), + FPOptions::defaultWithoutTrailingStorage(*Context)); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), Index: clang/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- clang/lib/CodeGen/CGStmtOpenMP.cpp +++ clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -2908,7 +2908,7 @@ bool HasLastprivates = false; auto &&CodeGen = [&S, CapturedStmt, CS, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { - ASTContext &C = CGF.getContext(); + const ASTContext &C = CGF.getContext(); QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); // Emit helper vars inits. @@ -2930,8 +2930,10 @@ OpaqueValueExpr UBRefExpr(S.getBeginLoc(), KmpInt32Ty, VK_LValue); CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB); // Generate condition for loop. - BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, - OK_Ordinary, S.getBeginLoc(), FPOptions()); + BinaryOperator *Cond = BinaryOperator::Create(C, + &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, + OK_Ordinary, S.getBeginLoc(), + FPOptions::defaultWithoutTrailingStorage(C)); // Increment for loop counter. UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, S.getBeginLoc(), true); @@ -3004,7 +3006,7 @@ // IV = LB; CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV); // while (idx <= UB) { BODY; ++idx; } - CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen, + CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, &Inc, BodyGen, [](CodeGenFunction &) {}); // Tell the runtime we are done. auto &&CodeGen = [&S](CodeGenFunction &CGF) { Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -1492,10 +1492,12 @@ finalArg = &argCast; - BinaryOperator assign(&ivarRef, finalArg, BO_Assign, + BinaryOperator *assign = BinaryOperator::Create(getContext(), + &ivarRef, finalArg, BO_Assign, ivarRef.getType(), VK_RValue, OK_Ordinary, - SourceLocation(), FPOptions()); - EmitStmt(&assign); + SourceLocation(), + FPOptions::defaultWithoutTrailingStorage(getContext())); + EmitStmt(assign); } /// Generate an Objective-C property setter function. Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -2930,7 +2930,7 @@ Result.RHS = Visit(E->getRHS()); Result.Ty = E->getType(); Result.Opcode = E->getOpcode(); - Result.FPFeatures = E->getFPFeatures(); + Result.FPFeatures = E->getFPFeatures(CGF.getContext()); Result.E = E; return Result; } @@ -2950,7 +2950,7 @@ OpInfo.RHS = Visit(E->getRHS()); OpInfo.Ty = E->getComputationResultType(); OpInfo.Opcode = E->getOpcode(); - OpInfo.FPFeatures = E->getFPFeatures(); + OpInfo.FPFeatures = E->getFPFeatures(CGF.getContext()); OpInfo.E = E; // Load/convert the LHS. LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); Index: clang/lib/Basic/LangOptions.cpp =================================================================== --- clang/lib/Basic/LangOptions.cpp +++ clang/lib/Basic/LangOptions.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" #include "clang/Basic/LangOptions.h" using namespace clang; @@ -47,3 +48,12 @@ const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion; return VersionTuple(Ver / 100, (Ver % 100) / 10); } + +FPOptions FPOptions::defaultWithoutTrailingStorage(const ASTContext &C) { + FPOptions result(C.getLangOpts()); + return result; +} + +bool FPOptions::requiresTrailingStorage(const ASTContext &C) { + return getAsOpaqueInt() != defaultWithoutTrailingStorage(C).getAsOpaqueInt(); +} Index: clang/lib/Analysis/BodyFarm.cpp =================================================================== --- clang/lib/Analysis/BodyFarm.cpp +++ clang/lib/Analysis/BodyFarm.cpp @@ -114,21 +114,21 @@ BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty) { - return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS), - BO_Assign, Ty, VK_RValue, - OK_Ordinary, SourceLocation(), FPOptions()); + return BinaryOperator::Create( + C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty, + VK_RValue, OK_Ordinary, SourceLocation(), + FPOptions::defaultWithoutTrailingStorage(C)); } BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, BinaryOperator::Opcode Op) { assert(BinaryOperator::isLogicalOp(Op) || BinaryOperator::isComparisonOp(Op)); - return new (C) BinaryOperator(const_cast<Expr*>(LHS), - const_cast<Expr*>(RHS), - Op, - C.getLogicalOperationType(), - VK_RValue, - OK_Ordinary, SourceLocation(), FPOptions()); + return BinaryOperator::Create(C, const_cast<Expr *>(LHS), + const_cast<Expr *>(RHS), Op, + C.getLogicalOperationType(), VK_RValue, + OK_Ordinary, SourceLocation(), + FPOptions::defaultWithoutTrailingStorage(C)); } CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { @@ -296,7 +296,8 @@ /*Args=*/CallArgs, /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_RValue, - /*SourceLocation=*/SourceLocation(), FPOptions()); + /*SourceLocation=*/SourceLocation(), + /*FPFeatures=*/FPOptions::defaultWithoutTrailingStorage(C)); } /// Create a fake body for std::call_once. Index: clang/lib/AST/ExprCXX.cpp =================================================================== --- clang/lib/AST/ExprCXX.cpp +++ clang/lib/AST/ExprCXX.cpp @@ -530,11 +530,11 @@ : CallExpr(CXXOperatorCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, OperatorLoc, /*MinNumArgs=*/0, UsesADL) { CXXOperatorCallExprBits.OperatorKind = OpKind; - CXXOperatorCallExprBits.FPFeatures = FPFeatures.getInt(); + CXXOperatorCallExprBits.FPFeatures = FPFeatures.getAsOpaqueInt(); assert( (CXXOperatorCallExprBits.OperatorKind == static_cast<unsigned>(OpKind)) && "OperatorKind overflow!"); - assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getInt()) && + assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getAsOpaqueInt()) && "FPFeatures overflow!"); Range = getSourceRangeImpl(); } @@ -1639,4 +1639,4 @@ void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects, alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, Empty); -} \ No newline at end of file +} Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -4342,6 +4342,49 @@ return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } +BinaryOperator *BinaryOperator::CreateEmpty(const ASTContext &C, + unsigned HasFPFeatures) { + unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); + void *Mem = C.Allocate(sizeof(BinaryOperator) + Extra, + alignof(BinaryOperator)); + return new (Mem) BinaryOperator(EmptyShell()); +} + +BinaryOperator * BinaryOperator::Create(const ASTContext &C, + Expr *lhs, Expr *rhs, Opcode opc, + QualType ResTy, ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc, FPOptions FPFeatures) { + bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C); + unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); + void *Mem = C.Allocate(sizeof(BinaryOperator) + Extra, + alignof(BinaryOperator)); + return new (Mem) BinaryOperator(C, + lhs, rhs, opc, ResTy, VK, OK, opLoc, FPFeatures); +} + +CompoundAssignOperator *CompoundAssignOperator::CreateEmpty( + const ASTContext &C, + unsigned HasFPFeatures) { + unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); + void *Mem = C.Allocate(sizeof(CompoundAssignOperator) + Extra, + alignof(CompoundAssignOperator)); + return new (Mem) CompoundAssignOperator(C, EmptyShell(), HasFPFeatures); +} + +CompoundAssignOperator * +CompoundAssignOperator::Create(const ASTContext &C, + Expr *lhs, Expr *rhs, Opcode opc, + QualType ResTy, ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc, FPOptions FPFeatures, + QualType CompLHSType, QualType CompResultType) { + bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C); + unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); + void *Mem = C.Allocate(sizeof(CompoundAssignOperator) + Extra, + alignof(CompoundAssignOperator)); + return new (Mem) CompoundAssignOperator(C, lhs, rhs, opc, ResTy, VK, OK, + opLoc, FPFeatures, CompLHSType, CompResultType); +} + const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) e = ewc->getSubExpr(); Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -6688,9 +6688,10 @@ if (Err) return std::move(Err); - return new (Importer.getToContext()) BinaryOperator( - ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(), - E->getObjectKind(), ToOperatorLoc, E->getFPFeatures()); + return BinaryOperator::Create( + Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType, + E->getValueKind(), E->getObjectKind(), ToOperatorLoc, + E->getFPFeatures(Importer.getToContext())); } ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) { @@ -6798,10 +6799,12 @@ if (Err) return std::move(Err); - return new (Importer.getToContext()) CompoundAssignOperator( - ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(), - E->getObjectKind(), ToComputationLHSType, ToComputationResultType, - ToOperatorLoc, E->getFPFeatures()); + return CompoundAssignOperator::Create( + Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType, + E->getValueKind(), E->getObjectKind(), + ToOperatorLoc, E->getFPFeatures(Importer.getToContext()), + importChecked(Err, ToComputationLHSType), + importChecked(Err, ToComputationResultType)); } Expected<CXXCastPath> Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -27,6 +27,8 @@ namespace clang { +class ASTContext; + /// Bitfields of LangOptions, split out from LangOptions in order to ensure that /// this large collection of bitfields is a trivial class type. class LangOptionsBase { @@ -399,6 +401,15 @@ {} // FIXME: Use getDefaultFEnvAccessMode() when available. + + /// Return the default value of FPOptions that's used when trailing + /// storage isn't required. + static FPOptions defaultWithoutTrailingStorage(const ASTContext &C); + + /// Does this FPOptions require trailing storage when stored in various + /// AST nodes, or can it be recreated using `defaultWithoutTrailingStorage`? + bool requiresTrailingStorage(const ASTContext &C); + bool allowFPContractWithinStatement() const { return fp_contract == LangOptions::FPC_On; } @@ -450,9 +461,9 @@ } /// Used to serialize this. - unsigned getInt() const { - return fp_contract | (fenv_access << 2) | (rounding << 3) - | (exceptions << 6); + unsigned getAsOpaqueInt() const { + return fp_contract | (fenv_access << 2) | (rounding << 3) | + (exceptions << 6); } private: Index: clang/include/clang/AST/Stmt.h =================================================================== --- clang/include/clang/AST/Stmt.h +++ clang/include/clang/AST/Stmt.h @@ -525,8 +525,9 @@ unsigned Opc : 6; /// This is only meaningful for operations on floating point - /// types and 0 otherwise. - unsigned FPFeatures : 8; + /// types when additional values need to be in trailing storage. + /// It is 0 otherwise. + unsigned HasFPFeatures : 1; SourceLocation OpLoc; }; Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -166,7 +166,7 @@ // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. void setFPFeatures(FPOptions F) { - CXXOperatorCallExprBits.FPFeatures = F.getInt(); + CXXOperatorCallExprBits.FPFeatures = F.getAsOpaqueInt(); } FPOptions getFPFeatures() const { return FPOptions(CXXOperatorCallExprBits.FPFeatures); Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -3466,20 +3466,40 @@ enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; + /// Return a pointer to the trailing FPOptions + FPOptions *getTrailingFPFeatures() { + assert(BinaryOperatorBits.HasFPFeatures); + FPOptions *slot = reinterpret_cast<FPOptions *>( + reinterpret_cast<char *>(this) + sizeof(BinaryOperator)); + return slot; + } + const FPOptions *getTrailingFPFeatures() const { + assert(BinaryOperatorBits.HasFPFeatures); + const FPOptions *slot = reinterpret_cast<const FPOptions *>( + reinterpret_cast<const char *>(this) + sizeof(BinaryOperator)); + return slot; + } + public: typedef BinaryOperatorKind Opcode; - BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, +protected: + /// Build a binary operator, assuming that appropriate storage has been + /// allocated for the trailing objects when needed. + BinaryOperator(const ASTContext &Ctx, + Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptions FPFeatures) : Expr(BinaryOperatorClass, ResTy, VK, OK) { BinaryOperatorBits.Opc = opc; - BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); + assert(!isCompoundAssignmentOp() && + "Use CompoundAssignOperator for compound assignments"); BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - assert(!isCompoundAssignmentOp() && - "Use CompoundAssignOperator for compound assignments"); + BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(Ctx); + if (BinaryOperatorBits.HasFPFeatures) + *getTrailingFPFeatures() = FPFeatures; setDependence(computeDependence(this)); } @@ -3488,6 +3508,20 @@ BinaryOperatorBits.Opc = BO_Comma; } + /// Return the size in bytes needed for the trailing objects. + /// Used to allocate the right amount of storage. + static unsigned sizeOfTrailingObjects(unsigned HasFPFeatures) { + return HasFPFeatures * sizeof(FPOptions); + } + +public: + static BinaryOperator * + CreateEmpty(const ASTContext &C, unsigned hasFPFeatures); + + static BinaryOperator *Create(const ASTContext &C, Expr *lhs, Expr *rhs, + Opcode opc, QualType ResTy, ExprValueKind VK, + ExprObjectKind OK, + SourceLocation opLoc, FPOptions FPFeatures); SourceLocation getExprLoc() const { return getOperatorLoc(); } SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; } void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; } @@ -3628,39 +3662,61 @@ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } - // Set the FP contractability status of this operator. Only meaningful for - // operations on floating point types. - void setFPFeatures(FPOptions F) { - BinaryOperatorBits.FPFeatures = F.getInt(); + /// Set and fetch the bit that shows whether FPFeatures needs to be + /// allocated in Trailing Storage + void setHasStoredFPFeatures(bool B) { BinaryOperatorBits.HasFPFeatures = B; } + bool hasStoredFPFeatures() const { return BinaryOperatorBits.HasFPFeatures; } + + /// Get FPFeatures from trailing storage + FPOptions getStoredFPFeatures() const { + assert(hasStoredFPFeatures()); + return *getTrailingFPFeatures(); + } + /// Set FPFeatures in trailing storage, used only by Serialization + void setStoredFPFeatures(FPOptions F) { + assert(BinaryOperatorBits.HasFPFeatures); + *getTrailingFPFeatures() = F; } - FPOptions getFPFeatures() const { - return FPOptions(BinaryOperatorBits.FPFeatures); + // Get the FP features status of this operator. Only meaningful for + // operations on floating point types. + FPOptions getFPFeatures(const ASTContext &C) const { + if (BinaryOperatorBits.HasFPFeatures) + return getStoredFPFeatures(); + return FPOptions::defaultWithoutTrailingStorage(C); } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. - bool isFPContractableWithinStatement() const { - return getFPFeatures().allowFPContractWithinStatement(); + bool isFPContractableWithinStatement(const ASTContext &C) const { + return getFPFeatures(C).allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. - bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); } + bool isFEnvAccessOn(const ASTContext &C) const { + return getFPFeatures(C).allowFEnvAccess(); + } protected: - BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + BinaryOperator(const ASTContext &Ctx, + Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptions FPFeatures, bool dead2) : Expr(CompoundAssignOperatorClass, ResTy, VK, OK) { BinaryOperatorBits.Opc = opc; - BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); + assert(isCompoundAssignmentOp() && + "Use CompoundAssignOperator for compound assignments"); BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; + BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(Ctx); + if (BinaryOperatorBits.HasFPFeatures) + *getTrailingFPFeatures() = FPFeatures; setDependence(computeDependence(this)); } + /// Construct an empty BinaryOperator, SC is CompoundAssignOperator. BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { BinaryOperatorBits.Opc = BO_MulAssign; } @@ -3675,12 +3731,30 @@ class CompoundAssignOperator : public BinaryOperator { QualType ComputationLHSType; QualType ComputationResultType; -public: - CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, + + /// Return a pointer to the trailing FPOptions + FPOptions *getTrailingFPFeatures() { + FPOptions *slot = reinterpret_cast<FPOptions *>( + reinterpret_cast<char *>(this) + sizeof(CompoundAssignOperator)); + return slot; + } + const FPOptions *getTrailingFPFeatures() const { + const FPOptions *slot = reinterpret_cast<const FPOptions *>( + reinterpret_cast<const char *>(this) + sizeof(CompoundAssignOperator)); + return slot; + } + + /// Construct an empty CompoundAssignOperator. + explicit CompoundAssignOperator(const ASTContext &C, EmptyShell Empty, + unsigned hasFPFeatures) + : BinaryOperator(CompoundAssignOperatorClass, Empty) {} +protected: + CompoundAssignOperator(const ASTContext &C, + Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, ExprValueKind VK, ExprObjectKind OK, - QualType CompLHSType, QualType CompResultType, - SourceLocation OpLoc, FPOptions FPFeatures) - : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, + SourceLocation OpLoc, FPOptions FPFeatures, + QualType CompLHSType, QualType CompResultType) + : BinaryOperator(C, lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { @@ -3688,9 +3762,23 @@ "Only should be used for compound assignments"); } - /// Build an empty compound assignment operator expression. - explicit CompoundAssignOperator(EmptyShell Empty) - : BinaryOperator(CompoundAssignOperatorClass, Empty) { } + /// Return the size in bytes needed for the trailing objects. + /// Used to allocate the right amount of storage. + static unsigned sizeOfTrailingObjects(unsigned HasFPFeatures) { + return HasFPFeatures * sizeof(FPOptions); + } + +public: + static CompoundAssignOperator * + CreateEmpty(const ASTContext &C, unsigned hasFPFeatures); + + static CompoundAssignOperator *Create(const + ASTContext &C, Expr *lhs, Expr *rhs, + Opcode opc, QualType ResTy, ExprValueKind VK, + ExprObjectKind OK, + SourceLocation opLoc, FPOptions FPFeatures, + QualType CompLHSType = QualType(), + QualType CompResultType = QualType()); // The two computation types are the type the LHS is converted // to for the computation and the type of the result; the two are @@ -3704,6 +3792,23 @@ static bool classof(const Stmt *S) { return S->getStmtClass() == CompoundAssignOperatorClass; } + + /// Retrieve the FPFeatures from trailing storage + FPOptions getStoredFPFeatures() const { + assert(hasStoredFPFeatures()); + return *getTrailingFPFeatures(); + } + /// Set FPFeatures in trailing storage, used only by Serialization + void setStoredFPFeatures(FPOptions F) { + assert(hasStoredFPFeatures()); + *getTrailingFPFeatures() = F; + } + + FPOptions getFPFeatures(const ASTContext &C) const { + if (hasStoredFPFeatures()) + return getStoredFPFeatures(); + return FPOptions::defaultWithoutTrailingStorage(C); + } }; /// AbstractConditionalOperator - An abstract base class for
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits