sepavloff created this revision.
sepavloff added reviewers: rsmith, rjmccall, andrew.w.kaylor, kpn, hfinkel, 
cameron.mcinally, uweigand.
Herald added a project: clang.

This change implements support of '#pragma STDC FENV_ACCESS' in
frontend. The pragma is supported only at namespace level and in
topmost block in functions.

Use of the pragma results in using constrained intrinsics to represent
floating point operations in the function to which it applies. Such
function is marked by the attribute 'FPEnvironment' in AST and
'fenv_access' in IR.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69272

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.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/SemaAttr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/CodeGen/pragma-fenv_access.c
  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,37 @@
+// 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 ON
+
+inline float func_01(float x) { // expected-warning {{'#pragma STDC FENV_ACCESS ON' cannot apply to inline functions, ignoring pragma}}
+  return x + 2;
+}
+
+inline float func_02(float x) {
+  #pragma STDC FENV_ACCESS OFF
+  return x + 2;
+}
+
+#pragma STDC FENV_ACCESS OFF
+
+inline float func_03(float x) {
+  #pragma STDC FENV_ACCESS ON // expected-warning {{'#pragma STDC FENV_ACCESS ON' cannot apply to inline functions}}
+  return x + 2;
+}
+
+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;
+}
+
+float func_05(int x, float y) {
+  if (x) {
+    #pragma STDC FENV_ACCESS ON // expected-warning {{in functions '#pragma STDC FENV_ACCESS ON' is supported only in topmost block}}
+    return y + 2;
+  }
+  return y;
+}
Index: clang/test/CodeGen/pragma-fenv_access.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/pragma-fenv_access.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -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")
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -9773,7 +9773,7 @@
       RHS.get() == E->getRHS())
     return E;
 
-  Sema::FPContractStateRAII FPContractState(getSema());
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
   getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
@@ -10299,7 +10299,7 @@
       (E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
     return SemaRef.MaybeBindToTemporary(E);
 
-  Sema::FPContractStateRAII FPContractState(getSema());
+  Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
   getSema().FPFeatures = E->getFPFeatures();
 
   return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -381,6 +381,21 @@
   PopCompoundScope();
 }
 
+void Sema::ActOnAfterCompoundStatementLeadingPragmas() {
+  if (FPFeatures.allowFEnvAccess() && getCurScope()->isFunctionScope()) {
+    FunctionDecl *F = getCurFunctionDecl();
+    if (F->isInlined() || F->hasAttr<AlwaysInlineAttr>() ||
+        F->hasAttr<GNUInlineAttr>()) {
+      Diag(F->getNameInfo().getLoc(),
+           diag::warn_pragma_fenv_access_cannot_apply);
+      return;
+    }
+
+    F->addAttr(NoInlineAttr::CreateImplicit(Context));
+    F->addAttr(FPEnvironmentAttr::CreateImplicit(Context, true));
+  }
+}
+
 sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
   return getCurFunction()->CompoundScopes.back();
 }
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -940,9 +940,18 @@
   }
 }
 
-void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
+void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC,
+                                 SourceLocation DiagLoc) {
   switch (FPC) {
   case LangOptions::FEA_On:
+    if (FunctionDecl *FD = getCurFunctionDecl()) {
+      if (FD->isInlined() || FD->hasAttr<AlwaysInlineAttr>() ||
+        FD->hasAttr<GNUInlineAttr>()) {
+        Diag(DiagLoc, diag::warn_pragma_fenv_access_cannot_apply);
+        FPFeatures.setDisallowFEnvAccess();
+        break;
+      }
+    }
     FPFeatures.setAllowFEnvAccess();
     break;
   case LangOptions::FEA_Off:
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -365,7 +365,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_opencl_extension:
@@ -1014,9 +1015,9 @@
                                 Tok.getLocation(),
                                 "in compound statement ('{}')");
 
-  // Record the state of the FP_CONTRACT pragma, restore on leaving the
+  // Record the current FPFeatures, restore on leaving the
   // compound statement.
-  Sema::FPContractStateRAII SaveFPContractState(Actions);
+  Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
 
   InMessageExpressionRAIIObject InMessage(*this, false);
   BalancedDelimiterTracker T(*this, tok::l_brace);
@@ -1027,6 +1028,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,9 +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);
-    }
 
     MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
                                 1);
@@ -641,7 +638,12 @@
     break;
   }
 
-  Actions.ActOnPragmaFEnvAccess(FPC);
+  if (Actions.getCurFunction() && !Actions.getCurScope()->isFunctionScope()) {
+    PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported);
+    FPC = LangOptions::FEA_Off;
+  }
+
+  Actions.ActOnPragmaFEnvAccess(FPC, Tok.getLocation());
   ConsumeAnnotationToken();
 }
 
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1092,6 +1092,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
@@ -1632,6 +1632,15 @@
   }
 }
 
+void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
+                                                  llvm::Function *F) {
+  if (D->hasAttr<FPEnvironmentAttr>()) {
+    llvm::AttrBuilder FuncAttrs;
+    FuncAttrs.addAttribute("fenv_access");
+    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))
@@ -4406,9 +4415,11 @@
 
   MaybeHandleStaticInExternC(D, Fn);
 
-
   maybeSetTrivialComdat(*D, *Fn);
 
+  // Set CodeGen attributes that represent floating point environment.
+  setLLVMFunctionFEnvAttributes(D, Fn);
+
   CodeGenFunction(*this).GenerateCode(D, Fn, FI);
 
   setNonAliasAttributes(GD, Fn);
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -827,6 +827,10 @@
         CGM.getCodeGenOpts().StackAlignment)
       Fn->addFnAttr("stackrealign");
 
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+    if (const auto *FEnv = FD->getAttr<FPEnvironmentAttr>())
+      Builder.setIsFPConstrained(FEnv->getAccess());
+
   llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
 
   // Create a marker to make it easy to insert allocas into the entryblock
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1259,12 +1259,12 @@
   /// should not be used elsewhere.
   void EmitCurrentDiagnostic(unsigned DiagID);
 
-  /// Records and restores the FP_CONTRACT state on entry/exit of compound
+  /// Records and restores the FPFeatures state on entry/exit of compound
   /// statements.
-  class FPContractStateRAII {
+  class FPFeaturesStateRAII {
   public:
-    FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
-    ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; }
+    FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
+    ~FPFeaturesStateRAII() { S.FPFeatures = OldFPFeaturesState; }
 
   private:
     Sema& S;
@@ -3986,6 +3986,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 {
@@ -8963,7 +8964,8 @@
 
   /// ActOnPragmaFenvAccess - Called on well formed
   /// \#pragma STDC FENV_ACCESS
-  void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC);
+  void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC,
+                             SourceLocation DiagLoc);
 
   /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
   /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -885,6 +885,9 @@
 def err_pragma_attr_attr_no_push : Error<
   "'#pragma clang attribute' attribute with no matching "
   "'#pragma clang attribute push'">;
+def warn_pragma_fenv_access_cannot_apply : Warning<"'#pragma STDC FENV_ACCESS ON' "
+  "cannot apply to inline functions, ignoring pragma">,
+   InGroup<IgnoredPragmas>;
 
 /// Objective-C parser diagnostics
 def err_duplicate_class_def : Error<
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1060,8 +1060,12 @@
 // - #pragma stdc unknown
 def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
    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_access_not_supported :
-   Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
+   Warning<"in functions '#pragma STDC FENV_ACCESS ON' is supported only "
+   "in topmost block, ignoring pragma">,
    InGroup<UnknownPragmas>;
 // - #pragma comment
 def err_pragma_comment_malformed : Error<
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3420,3 +3420,11 @@
   let Subjects = SubjectList<[NonParmVar, Function, Block, ObjCMethod]>;
   let Documentation = [ObjCExternallyRetainedDocs];
 }
+
+def FPEnvironment : InheritableAttr {
+  // This attribute has no spellings as it is only ever created implicitly.
+  let Spellings = [];
+  let Args = [BoolArgument<"Access">];  // TODO: Add Rounding and Exceptions.
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [Undocumented];
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to