[llvm] [SPIR-V] Implement SPV_KHR_float_controls2 (PR #146941)

Marcos Maronas via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 4 03:38:26 PDT 2025


https://github.com/maarquitos14 updated https://github.com/llvm/llvm-project/pull/146941

>From cbe7a07417b24e059843a1882bdb765adef5fd4b Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Wed, 25 Jun 2025 20:32:33 +0200
Subject: [PATCH 01/11] Initial support for SPV_KHR_float_controls2.

---
 llvm/docs/SPIRVUsage.rst                      |   2 +
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     | 148 +++++++++++-
 llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp       |  26 +-
 llvm/lib/Target/SPIRV/SPIRVBuiltins.h         |   2 +-
 llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp   |   6 +-
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |   4 +-
 llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp      |  17 ++
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |   4 +-
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 223 ++++++++++++++++--
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h   |  26 ++
 .../lib/Target/SPIRV/SPIRVSymbolicOperands.td |   8 +-
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  34 +++
 12 files changed, 466 insertions(+), 34 deletions(-)

diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 1858bda6160d4..a5f5d945da97c 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -217,6 +217,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
      - Adds an instruction to compute the matrix product of an M x K matrix with a K x N matrix and then add an M x N matrix. 
    * - ``SPV_INTEL_int4``
      - Adds support for 4-bit integer type, and allow this type to be used in cooperative matrices.
+   * - ``SPV_KHR_float_controls2``
+     - Adds execution modes and decorations to control floating-point computations.
 
 To enable multiple extensions, list them separated by comma. For example, to enable support for atomic operations on floating-point numbers and arbitrary precision integers, use:
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 26b94788b810e..9538ce6c8b9b2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -79,6 +79,7 @@ class SPIRVAsmPrinter : public AsmPrinter {
   void outputExecutionMode(const Module &M);
   void outputAnnotations(const Module &M);
   void outputModuleSections();
+  void outputFPFastMathDefaultInfo();
   bool isHidden() {
     return MF->getFunction()
         .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
@@ -457,6 +458,7 @@ void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
     unsigned ExpectMDOps, int64_t DefVal) {
   MCInst Inst;
   Inst.setOpcode(SPIRV::OpExecutionMode);
+
   Inst.addOperand(MCOperand::createReg(Reg));
   Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
   addOpsFromMDNode(Node, Inst, MAI);
@@ -496,11 +498,22 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
   NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
   if (Node) {
     for (unsigned i = 0; i < Node->getNumOperands(); i++) {
+      // If FPFastMathDefault, ContractionOff or SignedZeroInfNanPreserve
+      // execution modes, skip it, it'll be done somewhere else.
+      const auto EM =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>((Node->getOperand(i))->getOperand(1))
+                  ->getValue())
+              ->getZExtValue();
+      if (EM == SPIRV::ExecutionMode::FPFastMathDefault)
+        continue;
+
       MCInst Inst;
       Inst.setOpcode(SPIRV::OpExecutionMode);
       addOpsFromMDNode(cast<MDNode>(Node->getOperand(i)), Inst, MAI);
       outputMCInst(Inst);
     }
+    outputFPFastMathDefaultInfo();
   }
   for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
     const Function &F = *FI;
@@ -550,12 +563,72 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
     }
     if (ST->isKernel() && !M.getNamedMetadata("spirv.ExecutionMode") &&
         !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
-      MCInst Inst;
-      Inst.setOpcode(SPIRV::OpExecutionMode);
-      Inst.addOperand(MCOperand::createReg(FReg));
-      unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff);
-      Inst.addOperand(MCOperand::createImm(EM));
-      outputMCInst(Inst);
+      // ContractionOff is now deprecated. We need to use FPFastMathDefault with
+      // the appropriate flags instead. Since FPFastMathDefault takes a target
+      // type, we need to emit it for each floating-point type to match the
+      // effect of ContractionOff. As of now, there are 4 FP types: fp16, fp32,
+      // fp64 and fp128.
+      constexpr size_t NumFPTypes = 4;
+      for (size_t i = 0; i < NumFPTypes; ++i) {
+        MCInst Inst;
+        Inst.setOpcode(SPIRV::OpExecutionMode);
+        Inst.addOperand(MCOperand::createReg(FReg));
+        unsigned EM =
+            static_cast<unsigned>(SPIRV::ExecutionMode::FPFastMathDefault);
+        Inst.addOperand(MCOperand::createImm(EM));
+
+        Type *TargetType = nullptr;
+        switch (i) {
+        case 0:
+          TargetType = Type::getHalfTy(M.getContext());
+          break;
+        case 1:
+          TargetType = Type::getFloatTy(M.getContext());
+          break;
+        case 2:
+          TargetType = Type::getDoubleTy(M.getContext());
+          break;
+        case 3:
+          TargetType = Type::getFP128Ty(M.getContext());
+          break;
+        }
+        assert(TargetType && "Invalid target type for FPFastMathDefault");
+
+        // Find the SPIRV type matching the target type. We'll go over all the
+        // TypeConstVars instructions in the SPIRV module and find the one that
+        // matches the target type. We know the target type is a floating-point
+        // type, so we can skip anything different than OpTypeFloat. Then, we
+        // need to check the bitwidth.
+        bool SPIRVTypeFound = false;
+        for (const MachineInstr *MI :
+             MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
+          // Skip if the instruction is not OpTypeFloat.
+          if (MI->getOpcode() != SPIRV::OpTypeFloat)
+            continue;
+
+          // Skip if TargetTy bitwidth doesn't match MI->getOperand(1), which is
+          // the SPIRV type bit width.
+          if (TargetType->getScalarSizeInBits() != MI->getOperand(1).getImm())
+            continue;
+
+          SPIRVTypeFound = true;
+          const MachineFunction *MF = MI->getMF();
+          MCRegister TypeReg =
+              MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
+          Inst.addOperand(MCOperand::createReg(TypeReg));
+        }
+
+        if (!SPIRVTypeFound) {
+          // The module does not contain this FP type, so we don't need to emit
+          // FPFastMathDefault for it.
+          continue;
+        }
+        // We only end up here because there is no "spirv.ExecutionMode"
+        // metadata, so that means no FPFastMathDefault. Therefore, we only need
+        // to make sure AllowContract is set to 0, as the rest of flags.
+        Inst.addOperand(MCOperand::createImm(SPIRV::FPFastMathMode::None));
+        outputMCInst(Inst);
+      }
     }
   }
 }
@@ -602,6 +675,63 @@ void SPIRVAsmPrinter::outputAnnotations(const Module &M) {
   }
 }
 
+void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
+  for (const auto &[Func, FPFastMathDefaultInfoVec] :
+       MAI->FPFastMathDefaultInfoMap) {
+    for (const auto &FPFastMathDefaultInfo : FPFastMathDefaultInfoVec) {
+      MCInst Inst;
+      Inst.setOpcode(SPIRV::OpExecutionMode);
+      MCRegister FuncReg = MAI->getFuncReg(Func);
+      assert(FuncReg.isValid());
+      Inst.addOperand(MCOperand::createReg(FuncReg));
+      Inst.addOperand(
+          MCOperand::createImm(SPIRV::ExecutionMode::FPFastMathDefault));
+
+      // Find the SPIRV type matching the target type. We'll go over all the
+      // TypeConstVars instructions in the SPIRV module and find the one that
+      // matches the target type. We know the target type is a floating-point
+      // type, so we can skip anything different than OpTypeFloat. Then, we
+      // need to check the bitwidth.
+      const Type *TargetTy = FPFastMathDefaultInfo.Ty;
+      assert(TargetTy && "Expected target type");
+      bool SPIRVTypeFound = false;
+      for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
+        // Skip if the instruction is not OpTypeFloat.
+        if (MI->getOpcode() != SPIRV::OpTypeFloat)
+          continue;
+
+        // Skip if TargetTy bitwidth doesn't match MI->getOperand(1), which is
+        // the SPIRV type bit width.
+        if (TargetTy->getScalarSizeInBits() != MI->getOperand(1).getImm())
+          continue;
+
+        SPIRVTypeFound = true;
+        const MachineFunction *MF = MI->getMF();
+        MCRegister TypeReg =
+            MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
+        Inst.addOperand(MCOperand::createReg(TypeReg));
+      }
+      if (!SPIRVTypeFound) {
+        std::string DiagMsg;
+        raw_string_ostream OS(DiagMsg);
+        TargetTy->print(OS);
+        DiagMsg = "Could not find SPIRV type for target type: " + DiagMsg;
+        report_fatal_error(DiagMsg.c_str(), false);
+      }
+
+      unsigned Flags = FPFastMathDefaultInfo.FastMathFlags;
+      if (FPFastMathDefaultInfo.ContractionOff)
+        Flags &= ~SPIRV::FPFastMathMode::AllowContract;
+      if (FPFastMathDefaultInfo.SignedZeroInfNanPreserve)
+        Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
+                 SPIRV::FPFastMathMode::NSZ;
+
+      Inst.addOperand(MCOperand::createImm(Flags));
+      outputMCInst(Inst);
+    }
+  }
+}
+
 void SPIRVAsmPrinter::outputModuleSections() {
   const Module *M = MMI->getModule();
   // Get the global subtarget to output module-level info.
@@ -610,7 +740,8 @@ void SPIRVAsmPrinter::outputModuleSections() {
   MAI = &SPIRVModuleAnalysis::MAI;
   assert(ST && TII && MAI && M && "Module analysis is required");
   // Output instructions according to the Logical Layout of a Module:
-  // 1,2. All OpCapability instructions, then optional OpExtension instructions.
+  // 1,2. All OpCapability instructions, then optional OpExtension
+  // instructions.
   outputGlobalRequirements();
   // 3. Optional OpExtInstImport instructions.
   outputOpExtInstImports(*M);
@@ -618,7 +749,8 @@ void SPIRVAsmPrinter::outputModuleSections() {
   outputOpMemoryModel();
   // 5. All entry point declarations, using OpEntryPoint.
   outputEntryPoints();
-  // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId.
+  // 6. Execution-mode declarations, using OpExecutionMode or
+  // OpExecutionModeId.
   outputExecutionMode(*M);
   // 7a. Debug: all OpString, OpSourceExtension, OpSource, and
   // OpSourceContinued, without forward references.
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index f73a39c6ee9da..22217811e75f4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -697,7 +697,8 @@ static bool buildAtomicStoreInst(const SPIRV::IncomingCall *Call,
                                  MachineIRBuilder &MIRBuilder,
                                  SPIRVGlobalRegistry *GR) {
   if (Call->isSpirvOp())
-    return buildOpFromWrapper(MIRBuilder, SPIRV::OpAtomicStore, Call, Register(0));
+    return buildOpFromWrapper(MIRBuilder, SPIRV::OpAtomicStore, Call,
+                              Register(0));
 
   Register ScopeRegister =
       buildConstantIntReg32(SPIRV::Scope::Device, MIRBuilder, GR);
@@ -1125,11 +1126,21 @@ static unsigned getNumSizeComponents(SPIRVType *imgType) {
 
 static bool generateExtInst(const SPIRV::IncomingCall *Call,
                             MachineIRBuilder &MIRBuilder,
-                            SPIRVGlobalRegistry *GR) {
+                            SPIRVGlobalRegistry *GR, const CallBase &CB) {
   // Lookup the extended instruction number in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   uint32_t Number =
       SPIRV::lookupExtendedBuiltin(Builtin->Name, Builtin->Set)->Number;
+  // fmin_common and fmax_common are now deprecated, and we should use fmin and
+  // fmax with NotInf and NotNaN flags instead. Keep original number to add
+  // later the NoNans and NoInfs flags.
+  uint32_t OrigNumber = Number;
+  if (Number == SPIRV::OpenCLExtInst::fmin_common ||
+      Number == SPIRV::OpenCLExtInst::fmax_common) {
+    Number = (Number == SPIRV::OpenCLExtInst::fmin_common)
+                 ? SPIRV::OpenCLExtInst::fmin
+                 : SPIRV::OpenCLExtInst::fmax;
+  }
 
   // Build extended instruction.
   auto MIB =
@@ -1141,6 +1152,13 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call,
 
   for (auto Argument : Call->Arguments)
     MIB.addUse(Argument);
+  MIB.getInstr()->copyIRFlags(CB);
+  if (OrigNumber == SPIRV::OpenCLExtInst::fmin_common ||
+      OrigNumber == SPIRV::OpenCLExtInst::fmax_common) {
+    // Add NoNans and NoInfs flags to fmin/fmax instruction.
+    MIB.getInstr()->setFlag(MachineInstr::MIFlag::FmNoNans);
+    MIB.getInstr()->setFlag(MachineInstr::MIFlag::FmNoInfs);
+  }
   return true;
 }
 
@@ -2844,7 +2862,7 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
                                  MachineIRBuilder &MIRBuilder,
                                  const Register OrigRet, const Type *OrigRetTy,
                                  const SmallVectorImpl<Register> &Args,
-                                 SPIRVGlobalRegistry *GR) {
+                                 SPIRVGlobalRegistry *GR, const CallBase &CB) {
   LLVM_DEBUG(dbgs() << "Lowering builtin call: " << DemangledCall << "\n");
 
   // Lookup the builtin in the TableGen records.
@@ -2867,7 +2885,7 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
   // Match the builtin with implementation based on the grouping.
   switch (Call->Builtin->Group) {
   case SPIRV::Extended:
-    return generateExtInst(Call.get(), MIRBuilder, GR);
+    return generateExtInst(Call.get(), MIRBuilder, GR, CB);
   case SPIRV::Relational:
     return generateRelationalInst(Call.get(), MIRBuilder, GR);
   case SPIRV::Group:
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
index 1a8641a8328dd..f6a5234cd3c73 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
@@ -39,7 +39,7 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
                                  MachineIRBuilder &MIRBuilder,
                                  const Register OrigRet, const Type *OrigRetTy,
                                  const SmallVectorImpl<Register> &Args,
-                                 SPIRVGlobalRegistry *GR);
+                                 SPIRVGlobalRegistry *GR, const CallBase &CB);
 
 /// Helper function for finding a builtin function attributes
 /// by a demangled function name. Defined in SPIRVBuiltins.cpp.
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 36cc5cbe655bc..dd59943a2eae2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -640,9 +640,9 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
                                    GR->getPointerSize()));
       }
     }
-    if (auto Res =
-            SPIRV::lowerBuiltin(DemangledName, ST->getPreferredInstructionSet(),
-                                MIRBuilder, ResVReg, OrigRetTy, ArgVRegs, GR))
+    if (auto Res = SPIRV::lowerBuiltin(
+            DemangledName, ST->getPreferredInstructionSet(), MIRBuilder,
+            ResVReg, OrigRetTy, ArgVRegs, GR, *Info.CB))
       return *Res;
   }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index fbaca4e0e4d81..1d19bc4617c7d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -100,7 +100,9 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
          SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function},
         {"SPV_INTEL_2d_block_io",
          SPIRV::Extension::Extension::SPV_INTEL_2d_block_io},
-        {"SPV_INTEL_int4", SPIRV::Extension::Extension::SPV_INTEL_int4}};
+        {"SPV_INTEL_int4", SPIRV::Extension::Extension::SPV_INTEL_int4},
+        {"SPV_KHR_float_controls2",
+         SPIRV::Extension::Extension::SPV_KHR_float_controls2}};
 
 bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
                                   StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
index f658b67a4c2a5..411669aba6d44 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
@@ -142,7 +142,24 @@ bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
   case SPIRV::OpFMulV:
   case SPIRV::OpFDivV:
   case SPIRV::OpFRemV:
+  case SPIRV::OpFNegateV:
+  case SPIRV::OpFNegate:
   case SPIRV::OpFMod:
+  case SPIRV::OpOrdered:
+  case SPIRV::OpUnordered:
+  case SPIRV::OpFOrdEqual:
+  case SPIRV::OpFOrdNotEqual:
+  case SPIRV::OpFOrdLessThan:
+  case SPIRV::OpFOrdLessThanEqual:
+  case SPIRV::OpFOrdGreaterThan:
+  case SPIRV::OpFOrdGreaterThanEqual:
+  case SPIRV::OpFUnordEqual:
+  case SPIRV::OpFUnordNotEqual:
+  case SPIRV::OpFUnordLessThan:
+  case SPIRV::OpFUnordLessThanEqual:
+  case SPIRV::OpFUnordGreaterThan:
+  case SPIRV::OpFUnordGreaterThanEqual:
+  case SPIRV::OpExtInst:
     return true;
   default:
     return false;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 2dae0721886c7..61698b1445993 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1001,7 +1001,8 @@ bool SPIRVInstructionSelector::selectExtInst(Register ResVReg,
                      .addDef(ResVReg)
                      .addUse(GR.getSPIRVTypeID(ResType))
                      .addImm(static_cast<uint32_t>(Set))
-                     .addImm(Opcode);
+                     .addImm(Opcode)
+                     .setMIFlags(I.getFlags());
       const unsigned NumOps = I.getNumOperands();
       unsigned Index = 1;
       if (Index < NumOps &&
@@ -2449,6 +2450,7 @@ bool SPIRVInstructionSelector::selectCmp(Register ResVReg,
       .addUse(GR.getSPIRVTypeID(ResType))
       .addUse(Cmp0)
       .addUse(Cmp1)
+      .setMIFlags(I.getFlags())
       .constrainAllUses(TII, TRI, RBI);
 }
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index b71a9dd68dd44..c23da140e7efb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -920,6 +920,9 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
   } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
     Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
     Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
+  } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
+    Reqs.addRequirements(SPIRV::Capability::FloatControls2);
+    Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
   }
 }
 
@@ -1876,10 +1879,13 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
   // Collect requirements for OpExecutionMode instructions.
   auto Node = M.getNamedMetadata("spirv.ExecutionMode");
   if (Node) {
-    bool RequireFloatControls = false, RequireFloatControls2 = false,
+    bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
+         RequireKHRFloatControls2 = false,
          VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
-    bool HasFloatControls2 =
+    bool HasIntelFloatControls2 =
         ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
+    bool HasKHRFloatControls2 =
+        ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
     for (unsigned i = 0; i < Node->getNumOperands(); i++) {
       MDNode *MDN = cast<MDNode>(Node->getOperand(i));
       const MDOperand &MDOp = MDN->getOperand(1);
@@ -1892,7 +1898,6 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
           switch (EM) {
           case SPIRV::ExecutionMode::DenormPreserve:
           case SPIRV::ExecutionMode::DenormFlushToZero:
-          case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
           case SPIRV::ExecutionMode::RoundingModeRTE:
           case SPIRV::ExecutionMode::RoundingModeRTZ:
             RequireFloatControls = VerLower14;
@@ -1903,12 +1908,25 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
           case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
           case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
           case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
-            if (HasFloatControls2) {
-              RequireFloatControls2 = true;
+            if (HasIntelFloatControls2) {
+              RequireIntelFloatControls2 = true;
+              MAI.Reqs.getAndAddRequirements(
+                  SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
+            }
+            break;
+          // ContractionOff and SignedZeroInfNanPreserve are deprecated.
+          // FPFastMathDefault with the appropriate flags should be used
+          // instead.
+          case SPIRV::ExecutionMode::ContractionOff:
+          case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
+          case SPIRV::ExecutionMode::FPFastMathDefault: {
+            if (HasKHRFloatControls2) {
+              RequireKHRFloatControls2 = true;
               MAI.Reqs.getAndAddRequirements(
                   SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
             }
             break;
+          }
           default:
             MAI.Reqs.getAndAddRequirements(
                 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
@@ -1919,8 +1937,10 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
     if (RequireFloatControls &&
         ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
       MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
-    if (RequireFloatControls2)
+    if (RequireIntelFloatControls2)
       MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
+    if (RequireKHRFloatControls2)
+      MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
   }
   for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
     const Function &F = *FI;
@@ -1970,14 +1990,44 @@ static unsigned getFastMathFlags(const MachineInstr &I) {
     Flags |= SPIRV::FPFastMathMode::NSZ;
   if (I.getFlag(MachineInstr::MIFlag::FmArcp))
     Flags |= SPIRV::FPFastMathMode::AllowRecip;
+  if (I.getFlag(MachineInstr::MIFlag::FmContract))
+    Flags |= SPIRV::FPFastMathMode::AllowContract;
   if (I.getFlag(MachineInstr::MIFlag::FmReassoc))
-    Flags |= SPIRV::FPFastMathMode::Fast;
+    // LLVM reassoc maps to SPIRV transform, see
+    // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
+    // Because we are enabling AllowTransform, we must enable AllowReassoc and
+    // AllowContract too, as required by SPIRV spec. Also, we used to map
+    // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
+    // replaced by turning all the other bits instead. Therefore, we're enabling
+    // every bit here except None and Fast.
+    Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
+             SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
+             SPIRV::FPFastMathMode::AllowTransform |
+             SPIRV::FPFastMathMode::AllowReassoc |
+             SPIRV::FPFastMathMode::AllowContract;
+
+  // Error out if SPIRV::FPFastMathMode::Fast is enabled.
+  if (Flags & SPIRV::FPFastMathMode::Fast)
+    report_fatal_error("FPFastMathMode::Fast flag is deprecated and it is not "
+                       "valid to use anymore.");
+
+  // Error out if AllowTransform is enabled without AllowReassoc and
+  // AllowContract.
+  if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
+      !(Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
+      !(Flags & SPIRV::FPFastMathMode::AllowContract))
+    report_fatal_error(
+        "FPFastMathMode::AllowTransform flag requires AllowReassoc and "
+        "AllowContract flags to be enabled as well.");
+
   return Flags;
 }
 
-static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
-                                   const SPIRVInstrInfo &TII,
-                                   SPIRV::RequirementHandler &Reqs) {
+static void handleMIFlagDecoration(
+    MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
+    SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR,
+    const SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
+        &FPFastMathDefaultInfoVec) {
   if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
       getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
                                      SPIRV::Decoration::NoSignedWrap, ST, Reqs)
@@ -1995,9 +2045,46 @@ static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
   }
   if (!TII.canUseFastMathFlags(I))
     return;
+
   unsigned FMFlags = getFastMathFlags(I);
-  if (FMFlags == SPIRV::FPFastMathMode::None)
-    return;
+  if (FMFlags == SPIRV::FPFastMathMode::None) {
+    // We also need to check if any FPFastMathDefault info was set for the types
+    // used in this instruction.
+    if (FPFastMathDefaultInfoVec.empty())
+      return;
+
+    // There are three types of instructions that can use fast math flags:
+    // 1. Arithmetic instructions (FAdd, FMul, FSub, FDiv, FRem, etc.)
+    // 2. Relational instructions (FCmp, FOrd, FUnord, etc.)
+    // 3. Extended instructions (ExtInst)
+    // For arithmetic instructions, the floating point type can be in the
+    // result type or in the operands, but they all must be the same.
+    // For the relational and logical instructions, the floating point type can
+    // only be in the operands 1 and 2, not the result type. Also, the operands
+    // must have the same type.
+    // For the extended instructions, the floating point type can be in the
+    // result type or in the operands. It's unclear if the operands
+    // and the result type must be the same. Let's assume they must be.
+    // Therefore, for 1. and 2., we can check the first operand type,
+    // and for 3. we can check the result type.
+    assert(I.getNumOperands() >= 3 && "Expected at least 3 operands");
+    Register ResReg = I.getOpcode() == SPIRV::OpExtInst
+                          ? I.getOperand(1).getReg()
+                          : I.getOperand(2).getReg();
+    SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResReg, I.getMF());
+    const Type *Ty = GR->getTypeForSPIRVType(ResType);
+
+    // Match instruction type with the FPFastMathDefaultInfoVec.
+    for (const auto &Elem : FPFastMathDefaultInfoVec) {
+      if (Ty == Elem.Ty) {
+        FMFlags = Elem.FastMathFlags;
+        break;
+      }
+    }
+
+    if (FMFlags == SPIRV::FPFastMathMode::None)
+      return;
+  }
   Register DstReg = I.getOperand(0).getReg();
   buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags});
 }
@@ -2005,14 +2092,17 @@ static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
 // Walk all functions and add decorations related to MI flags.
 static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
                            MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
-                           SPIRV::ModuleAnalysisInfo &MAI) {
+                           SPIRV::ModuleAnalysisInfo &MAI,
+                           const SPIRVGlobalRegistry *GR) {
   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
     MachineFunction *MF = MMI->getMachineFunction(*F);
     if (!MF)
       continue;
+
     for (auto &MBB : *MF)
       for (auto &MI : MBB)
-        handleMIFlagDecoration(MI, ST, TII, MAI.Reqs);
+        handleMIFlagDecoration(MI, ST, TII, MAI.Reqs, GR,
+                               MAI.FPFastMathDefaultInfoMap[&(*F)]);
   }
 }
 
@@ -2058,6 +2148,108 @@ static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
   }
 }
 
+static void collectFPFastMathDefaults(const Module &M,
+                                      SPIRV::ModuleAnalysisInfo &MAI) {
+  // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
+  // We need the entry point (function) as the key, and the target
+  // type and flags as the value.
+  // We also need to check ContractionOff and SignedZeroInfNanPreserve
+  // execution modes, as they are now deprecated and must be replaced
+  // with FPFastMathDefaultInfo.
+  auto Node = M.getNamedMetadata("spirv.ExecutionMode");
+  if (Node) {
+    for (unsigned i = 0; i < Node->getNumOperands(); i++) {
+
+      MDNode *MDN = cast<MDNode>(Node->getOperand(i));
+      assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
+      const Function *F = cast<Function>(
+          cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
+      const auto EM =
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
+              ->getZExtValue();
+      if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
+        assert(MDN->getNumOperands() == 4 &&
+               "Expected 4 operands for FPFastMathDefault");
+
+        const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
+        unsigned Flags =
+            cast<ConstantInt>(
+                cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
+                ->getZExtValue();
+        SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
+            MAI.FPFastMathDefaultInfoMap[F];
+        FPFastMathDefaultInfoVec.emplace_back(T, Flags);
+      } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
+        assert(MDN->getNumOperands() == 4 &&
+               "Expected 2 operands for ContractionOff");
+
+        // We need to save this info for every possible FP type, i.e. {half,
+        // float, double, fp128}.
+        constexpr size_t NumFPTypes = 4;
+        for (size_t i = 0; i < NumFPTypes; ++i) {
+          Type *TargetType = nullptr;
+          switch (i) {
+          case 0:
+            TargetType = Type::getHalfTy(M.getContext());
+            break;
+          case 1:
+            TargetType = Type::getFloatTy(M.getContext());
+            break;
+          case 2:
+            TargetType = Type::getDoubleTy(M.getContext());
+            break;
+          case 3:
+            TargetType = Type::getFP128Ty(M.getContext());
+            break;
+          }
+          assert(TargetType && "Invalid target type for FPFastMathDefault");
+
+          SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
+              &FPFastMathDefaultInfoVec = MAI.FPFastMathDefaultInfoMap[F];
+          FPFastMathDefaultInfoVec.emplace_back(TargetType,
+                                                SPIRV::FPFastMathMode::None);
+          assert(FPFastMathDefaultInfoVec.size() == i + 1 &&
+                 "Expected one FPFastMathDefaultInfo per FP type");
+          MAI.FPFastMathDefaultInfoMap[F][i].ContractionOff = true;
+        }
+      } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
+        assert(MDN->getNumOperands() == 4 &&
+               "Expected 2 operands for SignedZeroInfNanPreserve");
+        // We need to save this info for every possible FP type, i.e. {half,
+        // float, double, fp128}.
+        constexpr size_t NumFPTypes = 4;
+        for (size_t i = 0; i < NumFPTypes; ++i) {
+          Type *TargetType = nullptr;
+          switch (i) {
+          case 0:
+            TargetType = Type::getHalfTy(M.getContext());
+            break;
+          case 1:
+            TargetType = Type::getFloatTy(M.getContext());
+            break;
+          case 2:
+            TargetType = Type::getDoubleTy(M.getContext());
+            break;
+          case 3:
+            TargetType = Type::getFP128Ty(M.getContext());
+            break;
+          }
+          assert(TargetType && "Invalid target type for FPFastMathDefault");
+
+          SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
+              &FPFastMathDefaultInfoVec = MAI.FPFastMathDefaultInfoMap[F];
+          FPFastMathDefaultInfoVec.emplace_back(TargetType,
+                                                SPIRV::FPFastMathMode::None);
+          assert(FPFastMathDefaultInfoVec.size() == i + 1 &&
+                 "Expected one FPFastMathDefaultInfo per FP type");
+          MAI.FPFastMathDefaultInfoMap[F][i].ContractionOff = true;
+        }
+      }
+    }
+  }
+}
+
 struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI;
 
 void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
@@ -2079,8 +2271,9 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
   patchPhis(M, GR, *TII, MMI);
 
   addMBBNames(M, *TII, MMI, *ST, MAI);
-  addDecorations(M, *TII, MMI, *ST, MAI);
+  addDecorations(M, *TII, MMI, *ST, MAI, GR);
 
+  collectFPFastMathDefaults(M, MAI);
   collectReqs(M, MAI, MMI, *ST);
 
   // Process type/const/global var/func decl instructions, number their
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index a0d47cb052b42..0e972bca07093 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -131,6 +131,29 @@ using LocalToGlobalRegTable = std::map<Register, MCRegister>;
 using RegisterAliasMapTy =
     std::map<const MachineFunction *, LocalToGlobalRegTable>;
 
+struct FPFastMathDefaultInfo {
+  const Type *Ty = nullptr;
+  unsigned FastMathFlags = 0;
+  // These can be represented with FastMathFlags, but since both ContractionOff
+  // and SignedZeroInfNanPreserve execution modes are deprecated, we will need
+  // to replace them with FPFastMath appropriate flags. However, we have no
+  // guarantee about the order in which we will process execution modes.
+  // Therefore it could happen that we first process ContractionOff, setting
+  // AllowContraction bit to 0, and then we process FPFastMathDefault enabling
+  // AllowContraction bit, effectively invalidating ContractionOff. Because of
+  // that, it's best to keep separate bits for the two deprecated options, and
+  // we will combine them later when we emit OpExecutionMode instructions.
+  bool ContractionOff = false;
+  bool SignedZeroInfNanPreserve = false;
+
+  FPFastMathDefaultInfo() = default;
+  FPFastMathDefaultInfo(const Type *Ty, unsigned FastMathFlags)
+      : Ty(Ty), FastMathFlags(FastMathFlags) {}
+  bool operator==(const FPFastMathDefaultInfo &Other) const {
+    return Ty == Other.Ty && FastMathFlags == Other.FastMathFlags;
+  }
+};
+
 // The struct contains results of the module analysis and methods
 // to access them.
 struct ModuleAnalysisInfo {
@@ -159,6 +182,9 @@ struct ModuleAnalysisInfo {
   InstrList MS[NUM_MODULE_SECTIONS];
   // The table maps MBB number to SPIR-V unique ID register.
   DenseMap<std::pair<const MachineFunction *, int>, MCRegister> BBNumToRegMap;
+  // The table maps function pointers to their default FP fast math info.
+  DenseMap<const Function *, SmallVector<FPFastMathDefaultInfo, 4>>
+      FPFastMathDefaultInfoMap;
 
   MCRegister getFuncReg(const Function *F) {
     assert(F && "Function is null");
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index f1aae42ea2be0..63adfdbbe4c6b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -319,6 +319,7 @@ defm SPV_INTEL_ternary_bitwise_function : ExtensionOperand<120>;
 defm SPV_INTEL_subgroup_matrix_multiply_accumulate : ExtensionOperand<121>;
 defm SPV_INTEL_2d_block_io : ExtensionOperand<122>;
 defm SPV_INTEL_int4 : ExtensionOperand<123>;
+defm SPV_KHR_float_controls2 : ExtensionOperand<124>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define Capabilities enum values and at the same time
@@ -526,6 +527,7 @@ defm Subgroup2DBlockTransformINTEL : CapabilityOperand<6229, 0, 0, [SPV_INTEL_2d
 defm Subgroup2DBlockTransposeINTEL : CapabilityOperand<6230, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>;
 defm Int4TypeINTEL : CapabilityOperand<5112, 0, 0, [SPV_INTEL_int4], []>;
 defm Int4CooperativeMatrixINTEL : CapabilityOperand<5114, 0, 0, [SPV_INTEL_int4], [Int4TypeINTEL, CooperativeMatrixKHR]>;
+defm FloatControls2 : CapabilityOperand<6029, 0, 0, [SPV_KHR_float_controls2], []>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define SourceLanguage enum values and at the same time
@@ -723,6 +725,7 @@ defm RoundingModeRTPINTEL : ExecutionModeOperand<5620, [RoundToInfinityINTEL]>;
 defm RoundingModeRTNINTEL : ExecutionModeOperand<5621, [RoundToInfinityINTEL]>;
 defm FloatingPointModeALTINTEL : ExecutionModeOperand<5622, [FloatingPointModeINTEL]>;
 defm FloatingPointModeIEEEINTEL : ExecutionModeOperand<5623, [FloatingPointModeINTEL]>;
+defm FPFastMathDefault : ExecutionModeOperand<6028, [FloatControls2]>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define StorageClass enum values and at the same time
@@ -1065,6 +1068,9 @@ defm NotInf : FPFastMathModeOperand<0x2, [Kernel]>;
 defm NSZ : FPFastMathModeOperand<0x4, [Kernel]>;
 defm AllowRecip : FPFastMathModeOperand<0x8, [Kernel]>;
 defm Fast : FPFastMathModeOperand<0x10, [Kernel]>;
+defm AllowContract : FPFastMathModeOperand<0x10000, [FloatControls2]>;
+defm AllowReassoc : FPFastMathModeOperand<0x20000, [FloatControls2]>;
+defm AllowTransform : FPFastMathModeOperand<0x40000, [FloatControls2]>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define FPRoundingMode enum values and at the same time
@@ -1239,7 +1245,7 @@ defm XfbBuffer : DecorationOperand<36, 0, 0, [], [TransformFeedback]>;
 defm XfbStride : DecorationOperand<37, 0, 0, [], [TransformFeedback]>;
 defm FuncParamAttr : DecorationOperand<38, 0, 0, [], [Kernel]>;
 defm FPRoundingMode : DecorationOperand<39, 0, 0, [], []>;
-defm FPFastMathMode : DecorationOperand<40, 0, 0, [], [Kernel]>;
+defm FPFastMathMode : DecorationOperand<40, 0, 0, [], [Kernel, FloatControls2]>;
 defm LinkageAttributes : DecorationOperand<41, 0, 0, [], [Linkage]>;
 defm NoContraction : DecorationOperand<42, 0, 0, [], [Shader]>;
 defm InputAttachmentIndex : DecorationOperand<43, 0, 0, [], [InputAttachment]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 725a7979d3e5b..c8b3cea95e256 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -172,6 +172,9 @@ void buildOpMemberDecorate(Register Reg, MachineInstr &I,
 
 void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
                              const MDNode *GVarMD) {
+  bool NoContractionFound = false;
+  bool HasFPFastMathMode = false;
+  unsigned FPFastMathFlags = SPIRV::FPFastMathMode::None;
   for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
     auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
     if (!OpMD)
@@ -183,6 +186,24 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
     if (!DecorationId)
       report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
                          "element of the decoration");
+
+    // NoContraction decoration is deprecated, and should be replaced with
+    // FPFastMathMode with appropriate flags. However, a instruction can have
+    // both NoContraction and FPFastMathMode decorations, and there is no
+    // guarantee about the order in which we will encounter them, so we store
+    // the information of both and will handle them separately after the loop so
+    // that we can combine them, if needed.
+    if (DecorationId->getZExtValue() ==
+        static_cast<uint32_t>(SPIRV::Decoration::NoContraction)) {
+      NoContractionFound = true;
+      continue; // NoContraction is handled separately.
+    } else if (DecorationId->getZExtValue() ==
+               static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode)) {
+      HasFPFastMathMode = true;
+      FPFastMathFlags = mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(1))
+                            ->getZExtValue();
+      continue; // FPFastMathMode is handled separately.
+    }
     auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
                    .addUse(Reg)
                    .addImm(static_cast<uint32_t>(DecorationId->getZExtValue()));
@@ -196,6 +217,17 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
         report_fatal_error("Unexpected operand of the decoration");
     }
   }
+  // If we have NoContraction decoration, we should set the
+  // FPFastMathMode::NoContraction flag.
+  if (NoContractionFound)
+    FPFastMathFlags &= ~SPIRV::FPFastMathMode::AllowContract;
+
+  if (NoContractionFound || HasFPFastMathMode) {
+    MIRBuilder.buildInstr(SPIRV::OpDecorate)
+        .addUse(Reg)
+        .addImm(static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode))
+        .addImm(FPFastMathFlags);
+  }
 }
 
 MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I) {
@@ -522,6 +554,8 @@ Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx) {
     return Type::getFloatTy(Ctx);
   else if (TypeName.consume_front("double"))
     return Type::getDoubleTy(Ctx);
+  else if (TypeName.consume_front("fp128"))
+    return Type::getFP128Ty(Ctx);
 
   // Unable to recognize SPIRV type name
   return nullptr;

>From 4c325ac612fcaf34e8006159d1f620d0854c8b28 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Mon, 30 Jun 2025 16:19:52 +0200
Subject: [PATCH 02/11] Fix test failures.

---
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     |  12 +-
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 123 +++++++++---------
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h   |   6 +-
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  18 +++
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |   1 +
 .../SPIRV/exec_mode_float_control_khr.ll      |  17 ++-
 .../SPIRV/execution-mode-per-entry-point.ll   |   4 +-
 .../SPIRV/instructions/float-fast-flags.ll    |  33 +++--
 .../SPIRV/llvm-intrinsics/arithmetic-fence.ll |   8 +-
 .../metadata/no_fp_contractions_metadata.ll   |  11 +-
 llvm/test/CodeGen/SPIRV/transcoding/fadd.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll   |  81 +++++++++++-
 llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fmul.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fneg.ll   |  11 +-
 .../fp_contract_reassoc_fast_mode.ll          |   4 +-
 llvm/test/CodeGen/SPIRV/transcoding/frem.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fsub.ll   |   6 +-
 18 files changed, 236 insertions(+), 123 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 9538ce6c8b9b2..22b551e352bd1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -505,7 +505,9 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
               cast<ConstantAsMetadata>((Node->getOperand(i))->getOperand(1))
                   ->getValue())
               ->getZExtValue();
-      if (EM == SPIRV::ExecutionMode::FPFastMathDefault)
+      if (EM == SPIRV::ExecutionMode::FPFastMathDefault ||
+          EM == SPIRV::ExecutionMode::ContractionOff ||
+          EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve)
         continue;
 
       MCInst Inst;
@@ -712,11 +714,9 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
         Inst.addOperand(MCOperand::createReg(TypeReg));
       }
       if (!SPIRVTypeFound) {
-        std::string DiagMsg;
-        raw_string_ostream OS(DiagMsg);
-        TargetTy->print(OS);
-        DiagMsg = "Could not find SPIRV type for target type: " + DiagMsg;
-        report_fatal_error(DiagMsg.c_str(), false);
+        // The module does not contain this FP type, so we don't need to emit
+        // FPFastMathDefault for it.
+        continue;
       }
 
       unsigned Flags = FPFastMathDefaultInfo.FastMathFlags;
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index c23da140e7efb..7c191614136e5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2148,6 +2148,41 @@ static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
   }
 }
 
+static SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &
+getOrCreateFPFastMathDefaultInfoVec(const Module &M,
+                                    SPIRV::ModuleAnalysisInfo &MAI,
+                                    const Function *F) {
+  auto it = MAI.FPFastMathDefaultInfoMap.find(F);
+  if (it != MAI.FPFastMathDefaultInfoMap.end())
+    return it->second;
+
+  // If the map does not contain the entry, create a new one. Initialize it to
+  // contain all 4 elements sorted by bit width of target type: {half, float,
+  // double, fp128}.
+  SmallVector<SPIRV::FPFastMathDefaultInfo, 4> FPFastMathDefaultInfoVec;
+  FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
+                                        SPIRV::FPFastMathMode::None);
+  FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
+                                        SPIRV::FPFastMathMode::None);
+  FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
+                                        SPIRV::FPFastMathMode::None);
+  FPFastMathDefaultInfoVec.emplace_back(Type::getFP128Ty(M.getContext()),
+                                        SPIRV::FPFastMathMode::None);
+  return MAI.FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
+}
+
+static SPIRV::FPFastMathDefaultInfo &getFPFastMathDefaultInfo(
+    SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec,
+    const Type *Ty) {
+  size_t BitWidth = Ty->getScalarSizeInBits();
+  int Index = computeFPFastMathDefaultInfoVecIndex(BitWidth);
+  assert(Index >= 0 && Index < 4 &&
+         "Expected FPFastMathDefaultInfo for half, float, double, or fp128");
+  assert(FPFastMathDefaultInfoVec.size() == 4 &&
+         "Expected FPFastMathDefaultInfoVec to have exactly 4 elements");
+  return FPFastMathDefaultInfoVec[Index];
+}
+
 static void collectFPFastMathDefaults(const Module &M,
                                       SPIRV::ModuleAnalysisInfo &MAI) {
   // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
@@ -2178,73 +2213,37 @@ static void collectFPFastMathDefaults(const Module &M,
                 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
                 ->getZExtValue();
         SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
-            MAI.FPFastMathDefaultInfoMap[F];
-        FPFastMathDefaultInfoVec.emplace_back(T, Flags);
+            getOrCreateFPFastMathDefaultInfoVec(M, MAI, F);
+        getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T).FastMathFlags =
+            Flags;
       } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
-        assert(MDN->getNumOperands() == 4 &&
-               "Expected 2 operands for ContractionOff");
+        assert(MDN->getNumOperands() == 2 &&
+               "Expected no operands for ContractionOff");
 
         // We need to save this info for every possible FP type, i.e. {half,
         // float, double, fp128}.
-        constexpr size_t NumFPTypes = 4;
-        for (size_t i = 0; i < NumFPTypes; ++i) {
-          Type *TargetType = nullptr;
-          switch (i) {
-          case 0:
-            TargetType = Type::getHalfTy(M.getContext());
-            break;
-          case 1:
-            TargetType = Type::getFloatTy(M.getContext());
-            break;
-          case 2:
-            TargetType = Type::getDoubleTy(M.getContext());
-            break;
-          case 3:
-            TargetType = Type::getFP128Ty(M.getContext());
-            break;
-          }
-          assert(TargetType && "Invalid target type for FPFastMathDefault");
-
-          SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
-              &FPFastMathDefaultInfoVec = MAI.FPFastMathDefaultInfoMap[F];
-          FPFastMathDefaultInfoVec.emplace_back(TargetType,
-                                                SPIRV::FPFastMathMode::None);
-          assert(FPFastMathDefaultInfoVec.size() == i + 1 &&
-                 "Expected one FPFastMathDefaultInfo per FP type");
-          MAI.FPFastMathDefaultInfoMap[F][i].ContractionOff = true;
+        SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
+            getOrCreateFPFastMathDefaultInfoVec(M, MAI, F);
+        for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
+          Info.ContractionOff = true;
         }
       } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
-        assert(MDN->getNumOperands() == 4 &&
-               "Expected 2 operands for SignedZeroInfNanPreserve");
-        // We need to save this info for every possible FP type, i.e. {half,
-        // float, double, fp128}.
-        constexpr size_t NumFPTypes = 4;
-        for (size_t i = 0; i < NumFPTypes; ++i) {
-          Type *TargetType = nullptr;
-          switch (i) {
-          case 0:
-            TargetType = Type::getHalfTy(M.getContext());
-            break;
-          case 1:
-            TargetType = Type::getFloatTy(M.getContext());
-            break;
-          case 2:
-            TargetType = Type::getDoubleTy(M.getContext());
-            break;
-          case 3:
-            TargetType = Type::getFP128Ty(M.getContext());
-            break;
-          }
-          assert(TargetType && "Invalid target type for FPFastMathDefault");
-
-          SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
-              &FPFastMathDefaultInfoVec = MAI.FPFastMathDefaultInfoMap[F];
-          FPFastMathDefaultInfoVec.emplace_back(TargetType,
-                                                SPIRV::FPFastMathMode::None);
-          assert(FPFastMathDefaultInfoVec.size() == i + 1 &&
-                 "Expected one FPFastMathDefaultInfo per FP type");
-          MAI.FPFastMathDefaultInfoMap[F][i].ContractionOff = true;
-        }
+        assert(MDN->getNumOperands() == 3 &&
+               "Expected 1 operand for SignedZeroInfNanPreserve");
+        unsigned TargetWidth =
+            cast<ConstantInt>(
+                cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
+                ->getZExtValue();
+        // We need to save this info only for the FP type with TargetWidth.
+        SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
+            getOrCreateFPFastMathDefaultInfoVec(M, MAI, F);
+        int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth);
+        assert(
+            Index >= 0 && Index < 4 &&
+            "Expected FPFastMathDefaultInfo for half, float, double, or fp128");
+        assert(FPFastMathDefaultInfoVec.size() == 4 &&
+               "Expected FPFastMathDefaultInfoVec to have exactly 4 elements");
+        FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
       }
     }
   }
@@ -2271,9 +2270,9 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
   patchPhis(M, GR, *TII, MMI);
 
   addMBBNames(M, *TII, MMI, *ST, MAI);
+  collectFPFastMathDefaults(M, MAI);
   addDecorations(M, *TII, MMI, *ST, MAI, GR);
 
-  collectFPFastMathDefaults(M, MAI);
   collectReqs(M, MAI, MMI, *ST);
 
   // Process type/const/global var/func decl instructions, number their
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 0e972bca07093..2a67c01c37c41 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -182,7 +182,11 @@ struct ModuleAnalysisInfo {
   InstrList MS[NUM_MODULE_SECTIONS];
   // The table maps MBB number to SPIR-V unique ID register.
   DenseMap<std::pair<const MachineFunction *, int>, MCRegister> BBNumToRegMap;
-  // The table maps function pointers to their default FP fast math info.
+  // The table maps function pointers to their default FP fast math info. It can
+  // be assumed that the SmallVector is sorted by the bit width of the type. The
+  // first element is the smallest bit width, and the last element is the
+  // largest bit width, therefore, we will have {half, float, double, fp128} in
+  // the order of their bit widths.
   DenseMap<const Function *, SmallVector<FPFastMathDefaultInfo, 4>>
       FPFastMathDefaultInfoMap;
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index c8b3cea95e256..02839cdcf4c73 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -1019,4 +1019,22 @@ unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
   return foldImm(ResType->getOperand(2), MRI);
 }
 
+size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth) {
+  switch (BitWidth) {
+  case 16: // half
+    return 0;
+  case 32: // float
+    return 1;
+  case 64: // double
+    return 2;
+  case 128: // fp128
+    return 3;
+  default:
+    report_fatal_error("Expected BitWidth to be 16, 32, 64, or 128", false);
+  }
+  assert(false && "Unreachable code");
+  // This return is just to avoid compiler warnings.
+  return 0;
+}
+
 } // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index f14a7d356ea58..e1df1113890b9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -503,5 +503,6 @@ int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
 unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
                                 const MachineInstr *ResType);
 
+size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth);
 } // namespace llvm
 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
diff --git a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
index d3131e5606857..848217b6a9232 100644
--- a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
+++ b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
@@ -11,7 +11,7 @@ entry:
   ret void
 }
 
-define dso_local dllexport spir_kernel void @k_float_controls_2(i32 %ibuf, i32 %obuf) local_unnamed_addr {
+define dso_local dllexport spir_kernel void @k_float_controls_2(half %h, float %f, double %d) local_unnamed_addr {
 entry:
   ret void
 }
@@ -52,12 +52,13 @@ entry:
 ; SPV-DAG: OpExecutionMode %[[#KERNEL1]] DenormFlushToZero 16
 !20 = !{void (i32, i32)* @k_float_controls_1, i32 4460, i32 16}
 
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 64
-!21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 32
+; SignedZeroInfNanPreserve is deprecated in SPV_KHR_float_controls2, and is replaced with FPFastMathDefault.
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP16:]] 7
+!21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP32:]] 7
 !22 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 32}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 16
-!23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP64:]] 7
+!23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
 
 ; SPV-DAG: OpExecutionMode %[[#KERNEL3]] RoundingModeRTE 64
 !24 = !{void (i32, i32)* @k_float_controls_3, i32 4462, i32 64}
@@ -72,3 +73,7 @@ entry:
 !28 = !{void (i32, i32)* @k_float_controls_4, i32 4463, i32 32}
 ; SPV-DAG: OpExecutionMode %[[#KERNEL4]] RoundingModeRTZ 16
 !29 = !{void (i32, i32)* @k_float_controls_4, i32 4463, i32 16}
+
+; SPV-DAG: %[[#FP64]] = OpTypeFloat 64
+; SPV-DAG: %[[#FP32]] = OpTypeFloat 32
+; SPV-DAG: %[[#FP16]] = OpTypeFloat 16
diff --git a/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll b/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
index 6fd1abd2be59a..5f2a7d5d2ca32 100644
--- a/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
+++ b/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
@@ -18,7 +18,7 @@
 ; CHECKN-NOT: OpExecutionMode
 ; CHECKN: OpSource
 
-define spir_kernel void @foo1() {
+define spir_kernel void @foo1(float %f) {
 entry:
   ret void
 }
@@ -33,7 +33,7 @@ entry:
   ret void
 }
 
-define spir_kernel void @foo4() {
+define spir_kernel void @foo4(float %f) {
 entry:
   ret void
 }
diff --git a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
index 43336db4e86fa..bb7c4f379658e 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
@@ -1,4 +1,4 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
 
 ; DISABLED-CHECK-DAG: OpName [[FNEG:%.+]] "scalar_fneg"
 ; CHECK-DAG: OpName [[FADD:%.+]] "test_fadd"
@@ -7,6 +7,11 @@
 ; CHECK-DAG: OpName [[FDIV:%.+]] "test_fdiv"
 ; CHECK-DAG: OpName [[FREM:%.+]] "test_frem"
 ; CHECK-DAG: OpName [[FMA:%.+]] "test_fma"
+; CHECK-DAG: OpDecorate %[[#FAddC:]] FPFastMathMode NotNaN|NotInf
+; CHECK-DAG: OpDecorate %[[#FSubC:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-DAG: OpDecorate %[[#FMulC:]] FPFastMathMode AllowContract
+; CHECK-DAG: OpDecorate %[[#FDivC:]] FPFastMathMode NSZ|AllowRecip
+; CHECK-DAG: OpDecorate %[[#FRemC:]] FPFastMathMode NSZ
 
 ; CHECK-DAG: [[F32Ty:%.+]] = OpTypeFloat 32
 ; CHECK-DAG: [[FNTy:%.+]] = OpTypeFunction [[F32Ty]] [[F32Ty]] [[F32Ty]]
@@ -16,9 +21,8 @@
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[C:%.+]] = OpFAdd [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks
-; CHECK-NEXT: OpReturnValue [[C]]
+; CHECK-NEXT: %[[#FAddC]] = OpFAdd [[F32Ty]] [[A]] [[B]]
+; CHECK-NEXT: OpReturnValue %[[#FAddC]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fadd(float %a, float %b) {
     %c = fadd nnan ninf float %a, %b
@@ -29,9 +33,8 @@ define float @test_fadd(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[C:%.+]] = OpFSub [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks
-; CHECK-NEXT: OpReturnValue [[C]]
+; CHECK-NEXT: %[[#FSubC]] = OpFSub [[F32Ty]] [[A]] [[B]]
+; CHECK-NEXT: OpReturnValue %[[#FSubC]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fsub(float %a, float %b) {
     %c = fsub fast float %a, %b
@@ -42,9 +45,8 @@ define float @test_fsub(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[C:%.+]] = OpFMul [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks]
-; CHECK-NEXT: OpReturnValue [[C]]
+; CHECK-NEXT: %[[#FMulC]] = OpFMul [[F32Ty]] [[A]] [[B]]
+; CHECK-NEXT: OpReturnValue %[[#FMulC]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fmul(float %a, float %b) {
     %c = fmul contract float %a, %b
@@ -55,9 +57,8 @@ define float @test_fmul(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[C:%.+]] = OpFDiv [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks
-; CHECK-NEXT: OpReturnValue [[C]]
+; CHECK-NEXT: %[[#FDivC]] = OpFDiv [[F32Ty]] [[A]] [[B]]
+; CHECK-NEXT: OpReturnValue %[[#FDivC]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fdiv(float %a, float %b) {
     %c = fdiv arcp nsz float %a, %b
@@ -68,9 +69,8 @@ define float @test_fdiv(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: [[C:%.+]] = OpFRem [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks
-; CHECK-NEXT: OpReturnValue [[C]]
+; CHECK-NEXT: %[[#FRemC]] = OpFRem [[F32Ty]] [[A]] [[B]]
+; CHECK-NEXT: OpReturnValue %[[#FRemC]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_frem(float %a, float %b) {
     %c = frem nsz float %a, %b
@@ -86,7 +86,6 @@ declare float @llvm.fma.f32(float, float, float)
 ; CHECK-NEXT: [[C:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
 ; CHECK-NEXT: [[R:%.+]] = OpExtInst [[F32Ty]] {{%.+}} fma [[A]] [[B]] [[C]]
-;; TODO: OpDecorate checks
 ; CHECK-NEXT: OpReturnValue [[R]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fma(float %a, float %b, float %c) {
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
index 5d8f547054dbf..c532ddc22642c 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
@@ -1,8 +1,8 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux %s -o - | FileCheck %s --check-prefixes=CHECK-NOEXT
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefixes=CHECK-NOEXT
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux %s -o - --spirv-ext=+SPV_EXT_arithmetic_fence | FileCheck %s --check-prefixes=CHECK-EXT
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_KHR_float_controls2,+SPV_EXT_arithmetic_fence %s -o - | FileCheck %s --check-prefixes=CHECK-EXT
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-NOEXT-NO: OpCapability ArithmeticFenceEXT
 ; CHECK-NOEXT-NO: OpExtension "SPV_EXT_arithmetic_fence"
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
index 10840125b9f61..41fe089fe8aae 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
@@ -1,8 +1,15 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
 ; CHECK: OpEntryPoint Kernel %[[#ENTRY:]] "foo"
-; CHECK: OpExecutionMode %[[#ENTRY]] ContractionOff
-define spir_kernel void @foo() {
+; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP16:]] 0
+; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP32:]] 0
+; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP64:]] 0
+; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP128:]] 0
+; CHECK: %[[#FP16]] = OpTypeFloat 16
+; CHECK: %[[#FP32]] = OpTypeFloat 32
+; CHECK: %[[#FP64]] = OpTypeFloat 64
+; CHECK: %[[#FP128]] = OpTypeFloat 128
+define spir_kernel void @foo(half %h, float %f, double %d, fp128 %fp) {
 entry:
   ret void
 }
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll b/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
index d84fd492a86a8..c952647d80c52 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -20,7 +20,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV-DAG: %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV-DAG: %[[#double:]] = OpTypeFloat 64
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll b/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
index 46eaba9d5ceb1..9fb653a26ff2d 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV: OpName %[[#r2:]] "r2"
@@ -91,7 +91,82 @@
 ; CHECK-SPIRV: OpName %[[#r88:]] "r88"
 ; CHECK-SPIRV: OpName %[[#r89:]] "r89"
 ; CHECK-SPIRV: OpName %[[#r90:]] "r90"
-; CHECK-SPIRV-NOT: OpDecorate %{{.*}} FPFastMathMode
+; CHECK-SPIRV: OpDecorate %[[#r2]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r3]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r4]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r9]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r10]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r11]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r12]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r13]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r14]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r16]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r17]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r18]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r19]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r20]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r21]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r23]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r24]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r25]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r26]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r27]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r28]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r30]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r31]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r32]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r33]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r34]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r35]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r37]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r38]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r39]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r40]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r41]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r42]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r44]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r45]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r47]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r48]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r49]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r50]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r51]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r52]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r54]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r55]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r56]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r57]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r58]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r59]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r61]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r62]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r63]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r64]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r65]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r66]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r68]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r69]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r70]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r71]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r72]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r73]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r75]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r76]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r77]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r78]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r79]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r80]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r82]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r83]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r84]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r85]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r86]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r87]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV: OpDecorate %[[#r89]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r90]] FPFastMathMode NSZ
 ; CHECK-SPIRV: %[[#bool:]] = OpTypeBool
 ; CHECK-SPIRV: %[[#r1]] = OpFOrdEqual %[[#bool]]
 ; CHECK-SPIRV: %[[#r2]] = OpFOrdEqual %[[#bool]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll b/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
index 79b786814c716..1104d42ac8fb8 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFDiv %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll b/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
index fdab29c9041cb..1918e62ac6943 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFMul %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll b/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
index 60bbfe6b7f393..eb28c523301a5 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV: OpName %[[#r2:]] "r2"
@@ -8,7 +8,12 @@
 ; CHECK-SPIRV: OpName %[[#r5:]] "r5"
 ; CHECK-SPIRV: OpName %[[#r6:]] "r6"
 ; CHECK-SPIRV: OpName %[[#r7:]] "r7"
-; CHECK-SPIRV-NOT: OpDecorate %{{.*}} FPFastMathMode
+; CHECK-SPIRV: OpDecorate %[[#r2]] FPFastMathMode NotNaN
+; CHECK-SPIRV: OpDecorate %[[#r3]] FPFastMathMode NotInf
+; CHECK-SPIRV: OpDecorate %[[#r4]] FPFastMathMode NSZ
+; CHECK-SPIRV: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
+; CHECK-SPIRV: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV: %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV: %[[#r1]] = OpFNegate %[[#float]]
 ; CHECK-SPIRV: %[[#r2]] = OpFNegate %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll b/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
index 974043c11991f..83a93dfcf0963 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV-NOT: OpCapability FPFastMathModeINTEL
 ; CHECK-SPIRV:     OpName %[[#mu:]] "mul"
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/frem.ll b/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
index d36ba7f70e453..07baaf6384374 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFRem %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll b/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
index 3677c00405626..51baf17e2eba0 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFSub %[[#float]]

>From a664820e1a7b5315c9ff3854e438570fe323644f Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 19:42:37 +0200
Subject: [PATCH 03/11] Deprecations only apply when the extension is enabled.

---
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     |  50 ++++--
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp |   2 +-
 llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp      |   8 +-
 llvm/lib/Target/SPIRV/SPIRVInstrInfo.h        |   2 +-
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 154 +++++++++++++-----
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h   |  19 ++-
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |   3 +-
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          |  25 +--
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |   2 +-
 .../SPIRV/exec_mode_float_control_khr.ll      |  11 +-
 .../SPIRV/instructions/float-fast-flags.ll    |  33 ++--
 .../SPIRV/llvm-intrinsics/arithmetic-fence.ll |   8 +-
 llvm/test/CodeGen/SPIRV/transcoding/fadd.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll   |  81 +--------
 llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fmul.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fneg.ll   |  11 +-
 .../fp_contract_reassoc_fast_mode.ll          |   4 +-
 llvm/test/CodeGen/SPIRV/transcoding/frem.ll   |   6 +-
 llvm/test/CodeGen/SPIRV/transcoding/fsub.ll   |   6 +-
 20 files changed, 231 insertions(+), 212 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 22b551e352bd1..9bb204959d6fe 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -498,17 +498,20 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
   NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
   if (Node) {
     for (unsigned i = 0; i < Node->getNumOperands(); i++) {
-      // If FPFastMathDefault, ContractionOff or SignedZeroInfNanPreserve
-      // execution modes, skip it, it'll be done somewhere else.
-      const auto EM =
-          cast<ConstantInt>(
-              cast<ConstantAsMetadata>((Node->getOperand(i))->getOperand(1))
-                  ->getValue())
-              ->getZExtValue();
-      if (EM == SPIRV::ExecutionMode::FPFastMathDefault ||
-          EM == SPIRV::ExecutionMode::ContractionOff ||
-          EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve)
-        continue;
+      // If SPV_KHR_float_controls2 is enabled and we find any of
+      // FPFastMathDefault, ContractionOff or SignedZeroInfNanPreserve execution
+      // modes, skip it, it'll be done somewhere else.
+      if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
+        const auto EM =
+            cast<ConstantInt>(
+                cast<ConstantAsMetadata>((Node->getOperand(i))->getOperand(1))
+                    ->getValue())
+                ->getZExtValue();
+        if (EM == SPIRV::ExecutionMode::FPFastMathDefault ||
+            EM == SPIRV::ExecutionMode::ContractionOff ||
+            EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve)
+          continue;
+      }
 
       MCInst Inst;
       Inst.setOpcode(SPIRV::OpExecutionMode);
@@ -720,12 +723,31 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
       }
 
       unsigned Flags = FPFastMathDefaultInfo.FastMathFlags;
-      if (FPFastMathDefaultInfo.ContractionOff)
-        Flags &= ~SPIRV::FPFastMathMode::AllowContract;
-      if (FPFastMathDefaultInfo.SignedZeroInfNanPreserve)
+      if (FPFastMathDefaultInfo.ContractionOff &&
+          (Flags & SPIRV::FPFastMathMode::AllowContract) &&
+          FPFastMathDefaultInfo.FPFastMathMode)
+        report_fatal_error(
+            "Conflicting FPFastMathFlags: ContractionOff and AllowContract");
+
+      if (FPFastMathDefaultInfo.SignedZeroInfNanPreserve &&
+          !(Flags &
+            (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
+             SPIRV::FPFastMathMode::NSZ))) {
+        if (FPFastMathDefaultInfo.FPFastMathMode)
+          report_fatal_error("Conflicting FPFastMathFlags: "
+                             "SignedZeroInfNanPreserve but at least one of "
+                             "NotNaN/NotInf/NSZ is disabled.");
+
         Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
                  SPIRV::FPFastMathMode::NSZ;
+      }
 
+      // Don't emit if none of the execution modes was used.
+      if (Flags == SPIRV::FPFastMathMode::None &&
+          !FPFastMathDefaultInfo.ContractionOff &&
+          !FPFastMathDefaultInfo.SignedZeroInfNanPreserve &&
+          !FPFastMathDefaultInfo.FPFastMathMode)
+        continue;
       Inst.addOperand(MCOperand::createImm(Flags));
       outputMCInst(Inst);
     }
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index c5e8269efd25a..81b6c194116a7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -794,7 +794,7 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
   // arguments.
   MDNode *GVarMD = nullptr;
   if (GVar && (GVarMD = GVar->getMetadata("spirv.Decorations")) != nullptr)
-    buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD);
+    buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD, ST);
 
   return Reg;
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
index 411669aba6d44..357aab2f580c9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
@@ -130,7 +130,8 @@ bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
   }
 }
 
-bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
+bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI,
+                                         bool KHRFloatControls2) const {
   switch (MI.getOpcode()) {
   case SPIRV::OpFAddS:
   case SPIRV::OpFSubS:
@@ -142,9 +143,10 @@ bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
   case SPIRV::OpFMulV:
   case SPIRV::OpFDivV:
   case SPIRV::OpFRemV:
+  case SPIRV::OpFMod:
+    return true;
   case SPIRV::OpFNegateV:
   case SPIRV::OpFNegate:
-  case SPIRV::OpFMod:
   case SPIRV::OpOrdered:
   case SPIRV::OpUnordered:
   case SPIRV::OpFOrdEqual:
@@ -160,7 +162,7 @@ bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
   case SPIRV::OpFUnordGreaterThan:
   case SPIRV::OpFUnordGreaterThanEqual:
   case SPIRV::OpExtInst:
-    return true;
+    return KHRFloatControls2 ? true : false;
   default:
     return false;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
index d58dddcd8da2b..fda3142111bf0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
@@ -35,7 +35,7 @@ class SPIRVInstrInfo : public SPIRVGenInstrInfo {
   bool isTypeDeclInstr(const MachineInstr &MI) const;
   bool isDecorationInstr(const MachineInstr &MI) const;
   bool isAliasingInstr(const MachineInstr &MI) const;
-  bool canUseFastMathFlags(const MachineInstr &MI) const;
+  bool canUseFastMathFlags(const MachineInstr &MI, bool KHRFloatControls2) const;
   bool canUseNSW(const MachineInstr &MI) const;
   bool canUseNUW(const MachineInstr &MI) const;
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 7c191614136e5..592d3ddae2f11 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -240,6 +240,22 @@ static InstrSignature instrToSignature(const MachineInstr &MI,
   Register DefReg;
   InstrSignature Signature{MI.getOpcode()};
   for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
+    // The only decorations that can be applied more than once to a given <id>
+    // or structure member are UserSemantic(5635), CacheControlLoadINTEL (6442),
+    // and CacheControlStoreINTEL (6443). For all the rest of decorations, we
+    // will only add to the signature the Opcode, the id to which it applies,
+    // and the decoration id, disregarding any decoration flags. This will
+    // ensure that any subsequent decoration with the same id will be deemed as
+    // a duplicate. Then, at the call site, we will be able to handle duplicates
+    // in the best way.
+    unsigned Opcode = MI.getOpcode();
+    if ((Opcode == SPIRV::OpDecorate) && i >= 2) {
+      unsigned DecorationID = MI.getOperand(1).getImm();
+      if (DecorationID != SPIRV::Decoration::UserSemantic &&
+          DecorationID != SPIRV::Decoration::CacheControlLoadINTEL &&
+          DecorationID != SPIRV::Decoration::CacheControlStoreINTEL)
+        continue;
+    }
     const MachineOperand &MO = MI.getOperand(i);
     size_t h;
     if (MO.isReg()) {
@@ -551,8 +567,54 @@ static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
   MAI.setSkipEmission(&MI);
   InstrSignature MISign = instrToSignature(MI, MAI, true);
   auto FoundMI = IS.insert(MISign);
-  if (!FoundMI.second)
+  if (!FoundMI.second) {
+    if (MI.getOpcode() == SPIRV::OpDecorate) {
+      assert(MI.getNumOperands() >= 2 &&
+             "Decoration instructions must have at least 2 operands");
+      assert(MSType == SPIRV::MB_Annotations &&
+             "Only OpDecorate instructions can be duplicates");
+      // For FPFastMathMode decoration, we need to merge the flags of the
+      // duplicate decoration with the original one, so we need to find the
+      // original instruction that has the same signature. For the rest of
+      // instructions, we will simply skip the duplicate.
+      if (MI.getOperand(1).getImm() != SPIRV::Decoration::FPFastMathMode)
+        return; // Skip duplicates of other decorations.
+
+      const SPIRV::InstrList &Decorations = MAI.MS[MSType];
+      for (const MachineInstr *OrigMI : Decorations) {
+        if (instrToSignature(*OrigMI, MAI, true) == MISign) {
+          assert(OrigMI->getNumOperands() == MI.getNumOperands() &&
+                 "Original instruction must have the same number of operands");
+          assert(
+              OrigMI->getNumOperands() == 3 &&
+              "FPFastMathMode decoration must have 3 operands for OpDecorate");
+          unsigned OrigFlags = OrigMI->getOperand(2).getImm();
+          unsigned NewFlags = MI.getOperand(2).getImm();
+          if (OrigFlags == NewFlags)
+            return; // No need to merge, the flags are the same.
+
+          // Emit warning about possible conflict between flags.
+          unsigned FinalFlags = OrigFlags | NewFlags;
+          llvm::errs()
+              << "Warning: Conflicting FPFastMathMode decoration flags "
+                 "in instruction: "
+              << *OrigMI << "Original flags: " << OrigFlags
+              << ", new flags: " << NewFlags
+              << ". They will be merged on a best effort basis, but not "
+                 "validated. Final flags: "
+              << FinalFlags << "\n";
+          MachineInstr *OrigMINonConst = const_cast<MachineInstr *>(OrigMI);
+          MachineOperand &OrigFlagsOp = OrigMINonConst->getOperand(2);
+          OrigFlagsOp =
+              MachineOperand::CreateImm(static_cast<unsigned>(FinalFlags));
+          return; // Merge done, so we found a duplicate; don't add it to MAI.MS
+        }
+      }
+      assert(false && "No original instruction found for the duplicate "
+                      "OpDecorate, but we found one in IS.");
+    }
     return; // insert failed, so we found a duplicate; don't add it to MAI.MS
+  }
   // No duplicates, so add it.
   if (Append)
     MAI.MS[MSType].push_back(&MI);
@@ -921,8 +983,10 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
     Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
     Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
   } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
-    Reqs.addRequirements(SPIRV::Capability::FloatControls2);
-    Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
+    if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
+      Reqs.addRequirements(SPIRV::Capability::FloatControls2);
+      Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
+    }
   }
 }
 
@@ -1917,8 +1981,6 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
           // ContractionOff and SignedZeroInfNanPreserve are deprecated.
           // FPFastMathDefault with the appropriate flags should be used
           // instead.
-          case SPIRV::ExecutionMode::ContractionOff:
-          case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
           case SPIRV::ExecutionMode::FPFastMathDefault: {
             if (HasKHRFloatControls2) {
               RequireKHRFloatControls2 = true;
@@ -1980,7 +2042,8 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
   }
 }
 
-static unsigned getFastMathFlags(const MachineInstr &I) {
+static unsigned getFastMathFlags(const MachineInstr &I,
+                                 const SPIRVSubtarget &ST) {
   unsigned Flags = SPIRV::FPFastMathMode::None;
   if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
     Flags |= SPIRV::FPFastMathMode::NotNaN;
@@ -1992,33 +2055,40 @@ static unsigned getFastMathFlags(const MachineInstr &I) {
     Flags |= SPIRV::FPFastMathMode::AllowRecip;
   if (I.getFlag(MachineInstr::MIFlag::FmContract))
     Flags |= SPIRV::FPFastMathMode::AllowContract;
-  if (I.getFlag(MachineInstr::MIFlag::FmReassoc))
-    // LLVM reassoc maps to SPIRV transform, see
-    // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
-    // Because we are enabling AllowTransform, we must enable AllowReassoc and
-    // AllowContract too, as required by SPIRV spec. Also, we used to map
-    // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
-    // replaced by turning all the other bits instead. Therefore, we're enabling
-    // every bit here except None and Fast.
-    Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
-             SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
-             SPIRV::FPFastMathMode::AllowTransform |
-             SPIRV::FPFastMathMode::AllowReassoc |
-             SPIRV::FPFastMathMode::AllowContract;
-
-  // Error out if SPIRV::FPFastMathMode::Fast is enabled.
-  if (Flags & SPIRV::FPFastMathMode::Fast)
-    report_fatal_error("FPFastMathMode::Fast flag is deprecated and it is not "
-                       "valid to use anymore.");
-
-  // Error out if AllowTransform is enabled without AllowReassoc and
-  // AllowContract.
-  if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
-      !(Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
-      !(Flags & SPIRV::FPFastMathMode::AllowContract))
-    report_fatal_error(
-        "FPFastMathMode::AllowTransform flag requires AllowReassoc and "
-        "AllowContract flags to be enabled as well.");
+  if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
+    if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
+      // LLVM reassoc maps to SPIRV transform, see
+      // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
+      // Because we are enabling AllowTransform, we must enable AllowReassoc and
+      // AllowContract too, as required by SPIRV spec. Also, we used to map
+      // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
+      // replaced by turning all the other bits instead. Therefore, we're
+      // enabling every bit here except None and Fast.
+      Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
+               SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
+               SPIRV::FPFastMathMode::AllowTransform |
+               SPIRV::FPFastMathMode::AllowReassoc |
+               SPIRV::FPFastMathMode::AllowContract;
+    else
+      Flags |= SPIRV::FPFastMathMode::Fast;
+  }
+
+  if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
+    // Error out if SPIRV::FPFastMathMode::Fast is enabled.
+    if (Flags & SPIRV::FPFastMathMode::Fast)
+      report_fatal_error(
+          "FPFastMathMode::Fast flag is deprecated and it is not "
+          "valid to use anymore.");
+
+    // Error out if AllowTransform is enabled without AllowReassoc and
+    // AllowContract.
+    if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
+        !(Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
+        !(Flags & SPIRV::FPFastMathMode::AllowContract))
+      report_fatal_error(
+          "FPFastMathMode::AllowTransform flag requires AllowReassoc and "
+          "AllowContract flags to be enabled as well.");
+  }
 
   return Flags;
 }
@@ -2026,7 +2096,7 @@ static unsigned getFastMathFlags(const MachineInstr &I) {
 static void handleMIFlagDecoration(
     MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
     SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR,
-    const SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
+    SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
         &FPFastMathDefaultInfoVec) {
   if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
       getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
@@ -2043,10 +2113,11 @@ static void handleMIFlagDecoration(
     buildOpDecorate(I.getOperand(0).getReg(), I, TII,
                     SPIRV::Decoration::NoUnsignedWrap, {});
   }
-  if (!TII.canUseFastMathFlags(I))
+  if (!TII.canUseFastMathFlags(
+          I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)))
     return;
 
-  unsigned FMFlags = getFastMathFlags(I);
+  unsigned FMFlags = getFastMathFlags(I, ST);
   if (FMFlags == SPIRV::FPFastMathMode::None) {
     // We also need to check if any FPFastMathDefault info was set for the types
     // used in this instruction.
@@ -2075,9 +2146,10 @@ static void handleMIFlagDecoration(
     const Type *Ty = GR->getTypeForSPIRVType(ResType);
 
     // Match instruction type with the FPFastMathDefaultInfoVec.
-    for (const auto &Elem : FPFastMathDefaultInfoVec) {
+    for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
       if (Ty == Elem.Ty) {
         FMFlags = Elem.FastMathFlags;
+        Elem.FPFastMathMode = true;
         break;
       }
     }
@@ -2184,7 +2256,11 @@ static SPIRV::FPFastMathDefaultInfo &getFPFastMathDefaultInfo(
 }
 
 static void collectFPFastMathDefaults(const Module &M,
-                                      SPIRV::ModuleAnalysisInfo &MAI) {
+                                      SPIRV::ModuleAnalysisInfo &MAI,
+                                      const SPIRVSubtarget &ST) {
+  if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
+    return;
+
   // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
   // We need the entry point (function) as the key, and the target
   // type and flags as the value.
@@ -2270,7 +2346,7 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
   patchPhis(M, GR, *TII, MMI);
 
   addMBBNames(M, *TII, MMI, *ST, MAI);
-  collectFPFastMathDefaults(M, MAI);
+  collectFPFastMathDefaults(M, MAI, *ST);
   addDecorations(M, *TII, MMI, *ST, MAI, GR);
 
   collectReqs(M, MAI, MMI, *ST);
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 2a67c01c37c41..8e0de616337c7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -134,17 +134,18 @@ using RegisterAliasMapTy =
 struct FPFastMathDefaultInfo {
   const Type *Ty = nullptr;
   unsigned FastMathFlags = 0;
-  // These can be represented with FastMathFlags, but since both ContractionOff
-  // and SignedZeroInfNanPreserve execution modes are deprecated, we will need
-  // to replace them with FPFastMath appropriate flags. However, we have no
-  // guarantee about the order in which we will process execution modes.
-  // Therefore it could happen that we first process ContractionOff, setting
-  // AllowContraction bit to 0, and then we process FPFastMathDefault enabling
-  // AllowContraction bit, effectively invalidating ContractionOff. Because of
-  // that, it's best to keep separate bits for the two deprecated options, and
-  // we will combine them later when we emit OpExecutionMode instructions.
+  // When SPV_KHR_float_controls2 ContractionOff and SignzeroInfNanPreserve are
+  // deprecated, and we replace them with FPFastMathDefault appropriate flags
+  // instead. However, we have no guarantee about the order in which we will
+  // process execution modes. Therefore it could happen that we first process
+  // ContractionOff, setting AllowContraction bit to 0, and then we process
+  // FPFastMathDefault enabling AllowContraction bit, effectively invalidating
+  // ContractionOff. Because of that, it's best to keep separate bits for the
+  // different execution modes, and we will try and combine them later when we
+  // emit OpExecutionMode instructions.
   bool ContractionOff = false;
   bool SignedZeroInfNanPreserve = false;
+  bool FPFastMathMode = false;
 
   FPFastMathDefaultInfo() = default;
   FPFastMathDefaultInfo(const Type *Ty, unsigned FastMathFlags)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index f4b4846f70d7d..9fa2992766d03 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -841,6 +841,7 @@ static uint32_t convertFloatToSPIRVWord(float F) {
 
 static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR,
                                    MachineIRBuilder MIB) {
+  const SPIRVSubtarget &ST = cast<SPIRVSubtarget>(MIB.getMF().getSubtarget());
   SmallVector<MachineInstr *, 10> ToErase;
   for (MachineBasicBlock &MBB : MF) {
     for (MachineInstr &MI : MBB) {
@@ -851,7 +852,7 @@ static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR,
       MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
       if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
         buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
-                                MI.getOperand(2).getMetadata());
+                                MI.getOperand(2).getMetadata(), ST);
       } else if (isSpvIntrinsic(MI,
                                 Intrinsic::spv_assign_fpmaxerror_decoration)) {
         ConstantFP *OpV = mdconst::dyn_extract<ConstantFP>(
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 02839cdcf4c73..657d69f04d779 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -171,7 +171,7 @@ void buildOpMemberDecorate(Register Reg, MachineInstr &I,
 }
 
 void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
-                             const MDNode *GVarMD) {
+                             const MDNode *GVarMD, const SPIRVSubtarget &ST) {
   bool NoContractionFound = false;
   bool HasFPFastMathMode = false;
   unsigned FPFastMathFlags = SPIRV::FPFastMathMode::None;
@@ -187,14 +187,15 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
       report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
                          "element of the decoration");
 
-    // NoContraction decoration is deprecated, and should be replaced with
-    // FPFastMathMode with appropriate flags. However, a instruction can have
-    // both NoContraction and FPFastMathMode decorations, and there is no
-    // guarantee about the order in which we will encounter them, so we store
-    // the information of both and will handle them separately after the loop so
-    // that we can combine them, if needed.
-    if (DecorationId->getZExtValue() ==
-        static_cast<uint32_t>(SPIRV::Decoration::NoContraction)) {
+    // NoContraction decoration is deprecated by SPV_KHR_float_controls2, and
+    // should be replaced with FPFastMathMode with appropriate flags. However, a
+    // instruction can have both NoContraction and FPFastMathMode decorations,
+    // and there is no guarantee about the order in which we will encounter
+    // them, so we store the information of both and will handle them separately
+    // after the loop so that we can combine them, if needed.
+    if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2) &&
+        DecorationId->getZExtValue() ==
+            static_cast<uint32_t>(SPIRV::Decoration::NoContraction)) {
       NoContractionFound = true;
       continue; // NoContraction is handled separately.
     } else if (DecorationId->getZExtValue() ==
@@ -219,8 +220,10 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
   }
   // If we have NoContraction decoration, we should set the
   // FPFastMathMode::NoContraction flag.
-  if (NoContractionFound)
-    FPFastMathFlags &= ~SPIRV::FPFastMathMode::AllowContract;
+  if (NoContractionFound &&
+      (FPFastMathFlags & SPIRV::FPFastMathMode::AllowContract))
+    report_fatal_error(
+        "Conflicting FPFastMathFlags: NoContraction and AllowContract");
 
   if (NoContractionFound || HasFPFastMathMode) {
     MIRBuilder.buildInstr(SPIRV::OpDecorate)
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index e1df1113890b9..fc1f404158d8d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -157,7 +157,7 @@ void buildOpMemberDecorate(Register Reg, MachineInstr &I,
 
 // Add an OpDecorate instruction by "spirv.Decorations" metadata node.
 void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
-                             const MDNode *GVarMD);
+                             const MDNode *GVarMD, const SPIRVSubtarget &ST);
 
 // Return a valid position for the OpVariable instruction inside a function,
 // i.e., at the beginning of the first block of the function.
diff --git a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
index 848217b6a9232..058337c8a79f2 100644
--- a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
+++ b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
@@ -52,12 +52,11 @@ entry:
 ; SPV-DAG: OpExecutionMode %[[#KERNEL1]] DenormFlushToZero 16
 !20 = !{void (i32, i32)* @k_float_controls_1, i32 4460, i32 16}
 
-; SignedZeroInfNanPreserve is deprecated in SPV_KHR_float_controls2, and is replaced with FPFastMathDefault.
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP16:]] 7
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 64 
 !21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP32:]] 7
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 32 
 !22 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 32}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] FPFastMathDefault %[[#FP64:]] 7
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 16 
 !23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
 
 ; SPV-DAG: OpExecutionMode %[[#KERNEL3]] RoundingModeRTE 64
@@ -73,7 +72,3 @@ entry:
 !28 = !{void (i32, i32)* @k_float_controls_4, i32 4463, i32 32}
 ; SPV-DAG: OpExecutionMode %[[#KERNEL4]] RoundingModeRTZ 16
 !29 = !{void (i32, i32)* @k_float_controls_4, i32 4463, i32 16}
-
-; SPV-DAG: %[[#FP64]] = OpTypeFloat 64
-; SPV-DAG: %[[#FP32]] = OpTypeFloat 32
-; SPV-DAG: %[[#FP16]] = OpTypeFloat 16
diff --git a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
index bb7c4f379658e..6f820bee43f11 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
@@ -1,4 +1,4 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
 
 ; DISABLED-CHECK-DAG: OpName [[FNEG:%.+]] "scalar_fneg"
 ; CHECK-DAG: OpName [[FADD:%.+]] "test_fadd"
@@ -7,22 +7,17 @@
 ; CHECK-DAG: OpName [[FDIV:%.+]] "test_fdiv"
 ; CHECK-DAG: OpName [[FREM:%.+]] "test_frem"
 ; CHECK-DAG: OpName [[FMA:%.+]] "test_fma"
-; CHECK-DAG: OpDecorate %[[#FAddC:]] FPFastMathMode NotNaN|NotInf
-; CHECK-DAG: OpDecorate %[[#FSubC:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-DAG: OpDecorate %[[#FMulC:]] FPFastMathMode AllowContract
-; CHECK-DAG: OpDecorate %[[#FDivC:]] FPFastMathMode NSZ|AllowRecip
-; CHECK-DAG: OpDecorate %[[#FRemC:]] FPFastMathMode NSZ
 
 ; CHECK-DAG: [[F32Ty:%.+]] = OpTypeFloat 32
 ; CHECK-DAG: [[FNTy:%.+]] = OpTypeFunction [[F32Ty]] [[F32Ty]] [[F32Ty]]
 
-
 ; CHECK:      [[FADD]] = OpFunction [[F32Ty]] None [[FNTy]]
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: %[[#FAddC]] = OpFAdd [[F32Ty]] [[A]] [[B]]
-; CHECK-NEXT: OpReturnValue %[[#FAddC]]
+; CHECK-NEXT: [[C:%.+]] = OpFAdd [[F32Ty]] [[A]] [[B]]
+;; TODO: OpDecorate checks
+; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fadd(float %a, float %b) {
     %c = fadd nnan ninf float %a, %b
@@ -33,8 +28,9 @@ define float @test_fadd(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: %[[#FSubC]] = OpFSub [[F32Ty]] [[A]] [[B]]
-; CHECK-NEXT: OpReturnValue %[[#FSubC]]
+; CHECK-NEXT: [[C:%.+]] = OpFSub [[F32Ty]] [[A]] [[B]]
+;; TODO: OpDecorate checks
+; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fsub(float %a, float %b) {
     %c = fsub fast float %a, %b
@@ -45,8 +41,9 @@ define float @test_fsub(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: %[[#FMulC]] = OpFMul [[F32Ty]] [[A]] [[B]]
-; CHECK-NEXT: OpReturnValue %[[#FMulC]]
+; CHECK-NEXT: [[C:%.+]] = OpFMul [[F32Ty]] [[A]] [[B]]
+;; TODO: OpDecorate checks
+; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fmul(float %a, float %b) {
     %c = fmul contract float %a, %b
@@ -57,8 +54,9 @@ define float @test_fmul(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: %[[#FDivC]] = OpFDiv [[F32Ty]] [[A]] [[B]]
-; CHECK-NEXT: OpReturnValue %[[#FDivC]]
+; CHECK-NEXT: [[C:%.+]] = OpFDiv [[F32Ty]] [[A]] [[B]]
+;; TODO: OpDecorate checks
+; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fdiv(float %a, float %b) {
     %c = fdiv arcp nsz float %a, %b
@@ -69,8 +67,9 @@ define float @test_fdiv(float %a, float %b) {
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
-; CHECK-NEXT: %[[#FRemC]] = OpFRem [[F32Ty]] [[A]] [[B]]
-; CHECK-NEXT: OpReturnValue %[[#FRemC]]
+; CHECK-NEXT: [[C:%.+]] = OpFRem [[F32Ty]] [[A]] [[B]]
+;; TODO: OpDecorate checks
+; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_frem(float %a, float %b) {
     %c = frem nsz float %a, %b
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
index c532ddc22642c..42d94a556e4c3 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
@@ -1,8 +1,8 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefixes=CHECK-NOEXT
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux %s -o - | FileCheck %s --check-prefixes=CHECK-NOEXT
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_KHR_float_controls2,+SPV_EXT_arithmetic_fence %s -o - | FileCheck %s --check-prefixes=CHECK-EXT
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_EXT_arithmetic_fence %s -o - | FileCheck %s --check-prefixes=CHECK-EXT
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-NOEXT-NO: OpCapability ArithmeticFenceEXT
 ; CHECK-NOEXT-NO: OpExtension "SPV_EXT_arithmetic_fence"
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll b/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
index c952647d80c52..d84fd492a86a8 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fadd.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -20,7 +20,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV-DAG: %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV-DAG: %[[#double:]] = OpTypeFloat 64
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll b/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
index 9fb653a26ff2d..46eaba9d5ceb1 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fcmp.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV: OpName %[[#r2:]] "r2"
@@ -91,82 +91,7 @@
 ; CHECK-SPIRV: OpName %[[#r88:]] "r88"
 ; CHECK-SPIRV: OpName %[[#r89:]] "r89"
 ; CHECK-SPIRV: OpName %[[#r90:]] "r90"
-; CHECK-SPIRV: OpDecorate %[[#r2]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r3]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r4]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r9]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r10]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r11]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r12]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r13]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r14]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r16]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r17]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r18]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r19]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r20]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r21]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r23]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r24]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r25]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r26]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r27]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r28]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r30]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r31]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r32]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r33]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r34]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r35]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r37]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r38]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r39]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r40]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r41]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r42]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r44]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r45]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r47]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r48]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r49]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r50]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r51]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r52]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r54]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r55]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r56]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r57]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r58]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r59]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r61]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r62]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r63]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r64]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r65]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r66]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r68]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r69]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r70]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r71]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r72]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r73]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r75]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r76]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r77]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r78]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r79]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r80]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r82]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r83]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r84]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r85]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r86]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r87]] FPFastMathMode NotNaN|NotInf
-; CHECK-SPIRV: OpDecorate %[[#r89]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r90]] FPFastMathMode NSZ
+; CHECK-SPIRV-NOT: OpDecorate %{{.*}} FPFastMathMode
 ; CHECK-SPIRV: %[[#bool:]] = OpTypeBool
 ; CHECK-SPIRV: %[[#r1]] = OpFOrdEqual %[[#bool]]
 ; CHECK-SPIRV: %[[#r2]] = OpFOrdEqual %[[#bool]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll b/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
index 1104d42ac8fb8..79b786814c716 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fdiv.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFDiv %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll b/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
index 1918e62ac6943..fdab29c9041cb 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fmul.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFMul %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll b/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
index eb28c523301a5..60bbfe6b7f393 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fneg.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV: OpName %[[#r2:]] "r2"
@@ -8,12 +8,7 @@
 ; CHECK-SPIRV: OpName %[[#r5:]] "r5"
 ; CHECK-SPIRV: OpName %[[#r6:]] "r6"
 ; CHECK-SPIRV: OpName %[[#r7:]] "r7"
-; CHECK-SPIRV: OpDecorate %[[#r2]] FPFastMathMode NotNaN
-; CHECK-SPIRV: OpDecorate %[[#r3]] FPFastMathMode NotInf
-; CHECK-SPIRV: OpDecorate %[[#r4]] FPFastMathMode NSZ
-; CHECK-SPIRV: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
-; CHECK-SPIRV: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
+; CHECK-SPIRV-NOT: OpDecorate %{{.*}} FPFastMathMode
 ; CHECK-SPIRV: %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV: %[[#r1]] = OpFNegate %[[#float]]
 ; CHECK-SPIRV: %[[#r2]] = OpFNegate %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll b/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
index 83a93dfcf0963..974043c11991f 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fp_contract_reassoc_fast_mode.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV-NOT: OpCapability FPFastMathModeINTEL
 ; CHECK-SPIRV:     OpName %[[#mu:]] "mul"
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/frem.ll b/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
index 07baaf6384374..d36ba7f70e453 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/frem.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFRem %[[#float]]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll b/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
index 51baf17e2eba0..3677c00405626 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/fsub.ll
@@ -1,5 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV:     OpName %[[#r1:]] "r1"
 ; CHECK-SPIRV:     OpName %[[#r2:]] "r2"
@@ -13,7 +13,7 @@
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r3]] FPFastMathMode NotInf
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r4]] FPFastMathMode NSZ
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r5]] FPFastMathMode AllowRecip
-; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK-SPIRV-DAG: OpDecorate %[[#r6]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
 ; CHECK-SPIRV-DAG: OpDecorate %[[#r7]] FPFastMathMode NotNaN|NotInf
 ; CHECK-SPIRV:     %[[#float:]] = OpTypeFloat 32
 ; CHECK-SPIRV:     %[[#r1]] = OpFSub %[[#float]]

>From 0648840abacc09abe2d37a6e8d5a0f80fd7452db Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 19:43:01 +0200
Subject: [PATCH 04/11] Add extension specific tests.

---
 .../SPV_KHR_float_controls2/decoration.ll     | 98 +++++++++++++++++++
 .../SPV_KHR_float_controls2/exec_mode.ll      | 95 ++++++++++++++++++
 .../SPV_KHR_float_controls2/exec_mode2.ll     | 58 +++++++++++
 3 files changed, 251 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode2.ll

diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll
new file mode 100644
index 0000000000000..91dc5e8772a09
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll
@@ -0,0 +1,98 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability FloatControls2 
+; CHECK: Extension "SPV_KHR_float_controls2"
+
+; CHECK: OpName %[[#addRes:]] "addRes"
+; CHECK: OpName %[[#subRes:]] "subRes"
+; CHECK: OpName %[[#mulRes:]] "mulRes"
+; CHECK: OpName %[[#divRes:]] "divRes"
+; CHECK: OpName %[[#remRes:]] "remRes"
+; CHECK: OpName %[[#negRes:]] "negRes"
+; CHECK: OpName %[[#oeqRes:]] "oeqRes"
+; CHECK: OpName %[[#oneRes:]] "oneRes"
+; CHECK: OpName %[[#oltRes:]] "oltRes"
+; CHECK: OpName %[[#ogtRes:]] "ogtRes"
+; CHECK: OpName %[[#oleRes:]] "oleRes"
+; CHECK: OpName %[[#ogeRes:]] "ogeRes"
+; CHECK: OpName %[[#ordRes:]] "ordRes"
+; CHECK: OpName %[[#ueqRes:]] "ueqRes"
+; CHECK: OpName %[[#uneRes:]] "uneRes"
+; CHECK: OpName %[[#ultRes:]] "ultRes"
+; CHECK: OpName %[[#ugtRes:]] "ugtRes"
+; CHECK: OpName %[[#uleRes:]] "uleRes"
+; CHECK: OpName %[[#ugeRes:]] "ugeRes"
+; CHECK: OpName %[[#unoRes:]] "unoRes"
+; CHECK: OpName %[[#modRes:]] "modRes"
+; CHECK: OpName %[[#maxRes:]] "maxRes"
+; CHECK: OpName %[[#maxCommonRes:]] "maxCommonRes"
+; CHECK: OpDecorate %[[#subRes]] FPFastMathMode NotNaN
+; CHECK: OpDecorate %[[#mulRes]] FPFastMathMode NotInf
+; CHECK: OpDecorate %[[#divRes]] FPFastMathMode NSZ
+; CHECK: OpDecorate %[[#remRes]] FPFastMathMode AllowRecip
+; CHECK: OpDecorate %[[#negRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oeqRes]] FPFastMathMode NotNaN|NotInf
+; CHECK: OpDecorate %[[#oneRes]] FPFastMathMode AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oltRes]] FPFastMathMode NotNaN|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ogtRes]] FPFastMathMode NotInf|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oleRes]] FPFastMathMode NSZ|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ogeRes]] FPFastMathMode AllowRecip|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ordRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ueqRes]] FPFastMathMode NotNaN|NotInf|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#uneRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ultRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ugtRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#uleRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ugeRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#unoRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK-NOT: OpDecorate %[[#modRes]] FPFastMathMode
+; CHECK: OpDecorate %[[#maxRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#maxCommonRes:]] FPFastMathMode NotNaN|NotInf 
+
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
+target triple = "spir"
+
+; Function Attrs: convergent mustprogress nofree nounwind willreturn memory(none)
+declare spir_func float @_Z4fmodff(float, float)
+declare dso_local spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fmaxff(float noundef nofpclass(nan inf), float noundef nofpclass(nan inf)) local_unnamed_addr #1
+declare dso_local spir_func noundef nofpclass(nan inf) float @_Z23__spirv_ocl_fmax_commonff(float noundef nofpclass(nan inf), float noundef nofpclass(nan inf)) local_unnamed_addr #1
+
+; Function Attrs: convergent mustprogress norecurse nounwind
+define weak_odr dso_local spir_kernel void @foo(float %1, float %2) {
+entry:
+  %addRes = fadd float %1,  %2
+  %subRes = fsub nnan float %1,  %2
+  %mulRes = fmul ninf float %1,  %2
+  %divRes = fdiv nsz float %1,  %2
+  %remRes = frem arcp float %1,  %2
+  %negRes = fneg fast float %1
+  %oeqRes = fcmp nnan ninf oeq float %1,  %2
+  %oneRes = fcmp one float %1,  %2, !spirv.Decorations !3
+  %oltRes = fcmp nnan olt float %1,  %2, !spirv.Decorations !3
+  %ogtRes = fcmp ninf ogt float %1,  %2, !spirv.Decorations !3
+  %oleRes = fcmp nsz ole float %1,  %2, !spirv.Decorations !3
+  %ogeRes = fcmp arcp oge float %1,  %2, !spirv.Decorations !3
+  %ordRes = fcmp fast ord float %1,  %2, !spirv.Decorations !3
+  %ueqRes = fcmp nnan ninf ueq float %1,  %2, !spirv.Decorations !3
+  %uneRes = fcmp une float %1,  %2, !spirv.Decorations !3
+  %ultRes = fcmp ult float %1,  %2, !spirv.Decorations !3
+  %ugtRes = fcmp ugt float %1,  %2, !spirv.Decorations !3
+  %uleRes = fcmp ule float %1,  %2, !spirv.Decorations !3
+  %ugeRes = fcmp uge float %1,  %2, !spirv.Decorations !3
+  %unoRes = fcmp uno float %1,  %2, !spirv.Decorations !3
+  %modRes = call spir_func float @_Z4fmodff(float %1, float %2)
+  %maxRes = tail call fast spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fmaxff(float noundef nofpclass(nan inf) %1, float noundef nofpclass(nan inf) %2)
+   %maxCommonRes = tail call spir_func noundef float @_Z23__spirv_ocl_fmax_commonff(float noundef nofpclass(nan inf) %1, float noundef nofpclass(nan inf) %2)
+  ret void
+}
+
+!llvm.module.flags = !{!12}
+!llvm.ident = !{!13}
+!spirv.EntryPoint = !{}
+
+!3 = !{!5, !4}
+!4 = !{i32 42} ; 42 is NoContraction decoration
+!5 = !{i32 40, i32 393216} ; 40 is FPFastMathMode
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 8.0.1"}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll
new file mode 100644
index 0000000000000..aeee4e9ebbca9
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll
@@ -0,0 +1,95 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability FloatControls2 
+; CHECK: Extension "SPV_KHR_float_controls2"
+
+define dso_local dllexport spir_kernel void @k_float_controls_half(half %h) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_bfloat(bfloat %b) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_float(float %f) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_double(double %d) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_fp128(fp128 %fp) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d, fp128 %fp) {
+entry:
+  ret void
+}
+
+!llvm.module.flags = !{!12}
+!llvm.ident = !{!13}
+!spirv.EntryPoint = !{}
+!spirv.ExecutionMode = !{!17, !18, !19, !20, !21, !22, !23, !24, !25, !26}
+
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_HALF:]] "k_float_controls_half"
+!0 = !{ptr @k_float_controls_half, !"k_float_controls_half", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_BFLOAT:]] "k_float_controls_bfloat"
+!1 = !{ptr @k_float_controls_bfloat, !"k_float_controls_bfloat", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_FLOAT:]] "k_float_controls_float"
+!2 = !{ptr @k_float_controls_float, !"k_float_controls_float", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_DOUBLE:]] "k_float_controls_double"
+!3 = !{ptr @k_float_controls_double, !"k_float_controls_double", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_FP128:]] "k_float_controls_fp128"
+!4 = !{ptr @k_float_controls_fp128, !"k_float_controls_fp128", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL:]] "k_float_controls_all"
+!5 = !{ptr @k_float_controls_all, !"k_float_controls_all", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+!6 = !{i32 2, i32 2}
+!7 = !{i32 32, i32 36}
+!8 = !{i32 0, i32 0}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 8.0.1"}
+!14 = !{i32 1, i32 0}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_HALF]] FPFastMathDefault %[[#HALF_TYPE:]] 1 
+!17 = !{ptr @k_float_controls_half, i32 6028, half undef, i32 1}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] 2 
+!18 = !{ptr @k_float_controls_bfloat, i32 6028, bfloat undef, i32 2}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 4 
+!19 = !{ptr @k_float_controls_float, i32 6028, float undef, i32 4}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 
+!20 = !{ptr @k_float_controls_double, i32 6028, double undef, i32 7}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_FP128]] FPFastMathDefault %[[#FP128_TYPE:]] 65536
+!21 = !{ptr @k_float_controls_fp128, i32 6028, fp128 undef, i32 65536}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE]] 131072 
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE]] 262144 
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE]] 458752 
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FP128_TYPE]] 65543 
+!22 = !{ptr @k_float_controls_all, i32 6028, half undef, i32 131072}
+!23 = !{ptr @k_float_controls_all, i32 6028, bfloat undef, i32 131072}
+!24 = !{ptr @k_float_controls_all, i32 6028, float undef, i32 262144}
+!25 = !{ptr @k_float_controls_all, i32 6028, double undef, i32 458752}
+!26 = !{ptr @k_float_controls_all, i32 6028, fp128 undef, i32 65543}
+
+; CHECK: %[[#HALF_TYPE]] = OpTypeFloat 16
+; CHECK: %[[#FLOAT_TYPE]] = OpTypeFloat 32
+; CHECK: %[[#DOUBLE_TYPE]] = OpTypeFloat 64
+; CHECK: %[[#FP128_TYPE]] = OpTypeFloat 128
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode2.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode2.ll
new file mode 100644
index 0000000000000..f9f72748809cf
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode2.ll
@@ -0,0 +1,58 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability FloatControls2 
+; CHECK: Extension "SPV_KHR_float_controls2"
+
+define dso_local dllexport spir_kernel void @k_float_controls_float(float %f) {
+entry:
+  ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d, fp128 %fp) {
+entry:
+  ret void
+}
+
+
+!llvm.module.flags = !{!12}
+!llvm.ident = !{!13}
+!spirv.EntryPoint = !{}
+!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26, !27}
+
+
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_FLOAT:]] "k_float_controls_float"
+!2 = !{ptr @k_float_controls_float, !"k_float_controls_float", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL:]] "k_float_controls_all"
+!3 = !{ptr @k_float_controls_all, !"k_float_controls_all", !6, i32 0, !6, !7, !8, i32 0, i32 0}
+
+!6 = !{i32 2, i32 2}
+!7 = !{i32 32, i32 36}
+!8 = !{i32 0, i32 0}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 8.0.1"}
+!14 = !{i32 1, i32 0}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 
+!19 = !{ptr @k_float_controls_float, i32 6028, float undef, i32 131079}
+; We expect 130179 for float type.
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 
+; We expect 7 for the rest of types because it's NotInf | NotNaN | NSZ set by SignedZeroInfNanPreserve.
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] 7 
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 
+; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FP128_TYPE:]] 7 
+!20 = !{ptr @k_float_controls_all, i32 6028, float undef, i32 131079}
+; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false.
+!21 = !{ptr @k_float_controls_float, i32 31}
+!22 = !{ptr @k_float_controls_all, i32 31}
+; SignedZeroInfNanPreserve is now replaced with FPFastMathDefault with flags NotInf, NotNaN and NSZ. 
+!23 = !{ptr @k_float_controls_float, i32 4461, i32 32}
+!24 = !{ptr @k_float_controls_all, i32 4461, i32 16}
+!25 = !{ptr @k_float_controls_all, i32 4461, i32 32}
+!26 = !{ptr @k_float_controls_all, i32 4461, i32 64}
+!27 = !{ptr @k_float_controls_all, i32 4461, i32 128}
+
+; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16
+; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32
+; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64
+; CHECK-DAG: %[[#FP128_TYPE]] = OpTypeFloat 128

>From 34c0628d71b6ed1f87bb4ff0b701301f4c0f78cd Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 19:58:20 +0200
Subject: [PATCH 05/11] Further work to apply deprecations only when extension
 is enabled.

---
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     | 131 ++++++++++--------
 llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp       |   7 +-
 .../metadata/no_fp_contractions_metadata.ll   |   9 +-
 3 files changed, 78 insertions(+), 69 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 9bb204959d6fe..06d67eb086cf2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -568,70 +568,83 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
     }
     if (ST->isKernel() && !M.getNamedMetadata("spirv.ExecutionMode") &&
         !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
-      // ContractionOff is now deprecated. We need to use FPFastMathDefault with
-      // the appropriate flags instead. Since FPFastMathDefault takes a target
-      // type, we need to emit it for each floating-point type to match the
-      // effect of ContractionOff. As of now, there are 4 FP types: fp16, fp32,
-      // fp64 and fp128.
-      constexpr size_t NumFPTypes = 4;
-      for (size_t i = 0; i < NumFPTypes; ++i) {
+      if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
+        // When SPV_KHR_float_controls2 is enabled, ContractionOff is
+        // deprecated. We need to use FPFastMathDefault with the appropriate
+        // flags instead. Since FPFastMathDefault takes a target type, we need
+        // to emit it for each floating-point type to match the effect of
+        // ContractionOff. As of now, there are 4 FP types: fp16, fp32, fp64 and
+        // fp128.
+        constexpr size_t NumFPTypes = 4;
+        for (size_t i = 0; i < NumFPTypes; ++i) {
+          MCInst Inst;
+          Inst.setOpcode(SPIRV::OpExecutionMode);
+          Inst.addOperand(MCOperand::createReg(FReg));
+          unsigned EM =
+              static_cast<unsigned>(SPIRV::ExecutionMode::FPFastMathDefault);
+          Inst.addOperand(MCOperand::createImm(EM));
+
+          Type *TargetType = nullptr;
+          switch (i) {
+          case 0:
+            TargetType = Type::getHalfTy(M.getContext());
+            break;
+          case 1:
+            TargetType = Type::getFloatTy(M.getContext());
+            break;
+          case 2:
+            TargetType = Type::getDoubleTy(M.getContext());
+            break;
+          case 3:
+            TargetType = Type::getFP128Ty(M.getContext());
+            break;
+          }
+          assert(TargetType && "Invalid target type for FPFastMathDefault");
+
+          // Find the SPIRV type matching the target type. We'll go over all the
+          // TypeConstVars instructions in the SPIRV module and find the one
+          // that matches the target type. We know the target type is a
+          // floating-point type, so we can skip anything different than
+          // OpTypeFloat. Then, we need to check the bitwidth.
+          bool SPIRVTypeFound = false;
+          for (const MachineInstr *MI :
+               MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
+            // Skip if the instruction is not OpTypeFloat.
+            if (MI->getOpcode() != SPIRV::OpTypeFloat)
+              continue;
+
+            // Skip if TargetTy bitwidth doesn't match MI->getOperand(1), which
+            // is the SPIRV type bit width.
+            if (TargetType->getScalarSizeInBits() != MI->getOperand(1).getImm())
+              continue;
+
+            SPIRVTypeFound = true;
+            const MachineFunction *MF = MI->getMF();
+            MCRegister TypeReg =
+                MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
+            Inst.addOperand(MCOperand::createReg(TypeReg));
+          }
+
+          if (!SPIRVTypeFound) {
+            // The module does not contain this FP type, so we don't need to
+            // emit FPFastMathDefault for it.
+            continue;
+          }
+          // We only end up here because there is no "spirv.ExecutionMode"
+          // metadata, so that means no FPFastMathDefault. Therefore, we only
+          // need to make sure AllowContract is set to 0, as the rest of flags.
+          // We still need to emit the OpExecutionMode instruction, otherwise
+          // it's up to the client API to define the flags.
+          Inst.addOperand(MCOperand::createImm(SPIRV::FPFastMathMode::None));
+          outputMCInst(Inst);
+        }
+      } else {
         MCInst Inst;
         Inst.setOpcode(SPIRV::OpExecutionMode);
         Inst.addOperand(MCOperand::createReg(FReg));
         unsigned EM =
-            static_cast<unsigned>(SPIRV::ExecutionMode::FPFastMathDefault);
+            static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff);
         Inst.addOperand(MCOperand::createImm(EM));
-
-        Type *TargetType = nullptr;
-        switch (i) {
-        case 0:
-          TargetType = Type::getHalfTy(M.getContext());
-          break;
-        case 1:
-          TargetType = Type::getFloatTy(M.getContext());
-          break;
-        case 2:
-          TargetType = Type::getDoubleTy(M.getContext());
-          break;
-        case 3:
-          TargetType = Type::getFP128Ty(M.getContext());
-          break;
-        }
-        assert(TargetType && "Invalid target type for FPFastMathDefault");
-
-        // Find the SPIRV type matching the target type. We'll go over all the
-        // TypeConstVars instructions in the SPIRV module and find the one that
-        // matches the target type. We know the target type is a floating-point
-        // type, so we can skip anything different than OpTypeFloat. Then, we
-        // need to check the bitwidth.
-        bool SPIRVTypeFound = false;
-        for (const MachineInstr *MI :
-             MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
-          // Skip if the instruction is not OpTypeFloat.
-          if (MI->getOpcode() != SPIRV::OpTypeFloat)
-            continue;
-
-          // Skip if TargetTy bitwidth doesn't match MI->getOperand(1), which is
-          // the SPIRV type bit width.
-          if (TargetType->getScalarSizeInBits() != MI->getOperand(1).getImm())
-            continue;
-
-          SPIRVTypeFound = true;
-          const MachineFunction *MF = MI->getMF();
-          MCRegister TypeReg =
-              MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
-          Inst.addOperand(MCOperand::createReg(TypeReg));
-        }
-
-        if (!SPIRVTypeFound) {
-          // The module does not contain this FP type, so we don't need to emit
-          // FPFastMathDefault for it.
-          continue;
-        }
-        // We only end up here because there is no "spirv.ExecutionMode"
-        // metadata, so that means no FPFastMathDefault. Therefore, we only need
-        // to make sure AllowContract is set to 0, as the rest of flags.
-        Inst.addOperand(MCOperand::createImm(SPIRV::FPFastMathMode::None));
         outputMCInst(Inst);
       }
     }
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 22217811e75f4..350937f1f0b22 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1135,8 +1135,11 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call,
   // fmax with NotInf and NotNaN flags instead. Keep original number to add
   // later the NoNans and NoInfs flags.
   uint32_t OrigNumber = Number;
-  if (Number == SPIRV::OpenCLExtInst::fmin_common ||
-      Number == SPIRV::OpenCLExtInst::fmax_common) {
+  const SPIRVSubtarget &ST =
+      cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
+  if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2) &&
+      (Number == SPIRV::OpenCLExtInst::fmin_common ||
+       Number == SPIRV::OpenCLExtInst::fmax_common)) {
     Number = (Number == SPIRV::OpenCLExtInst::fmin_common)
                  ? SPIRV::OpenCLExtInst::fmin
                  : SPIRV::OpenCLExtInst::fmax;
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
index 41fe089fe8aae..a1ce51b10b465 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
@@ -1,14 +1,7 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
 ; CHECK: OpEntryPoint Kernel %[[#ENTRY:]] "foo"
-; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP16:]] 0
-; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP32:]] 0
-; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP64:]] 0
-; CHECK: OpExecutionMode %[[#ENTRY]] FPFastMathDefault %[[#FP128:]] 0
-; CHECK: %[[#FP16]] = OpTypeFloat 16
-; CHECK: %[[#FP32]] = OpTypeFloat 32
-; CHECK: %[[#FP64]] = OpTypeFloat 64
-; CHECK: %[[#FP128]] = OpTypeFloat 128
+; CHECK: OpExecutionMode %[[#ENTRY]] ContractionOff 
 define spir_kernel void @foo(half %h, float %f, double %d, fp128 %fp) {
 entry:
   ret void

>From 1d87705f37f7f326c4573b68813be62823a3b8e7 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 20:04:53 +0200
Subject: [PATCH 06/11] Remove leftover comment.

---
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 592d3ddae2f11..999214381b634 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1978,9 +1978,6 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
                   SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
             }
             break;
-          // ContractionOff and SignedZeroInfNanPreserve are deprecated.
-          // FPFastMathDefault with the appropriate flags should be used
-          // instead.
           case SPIRV::ExecutionMode::FPFastMathDefault: {
             if (HasKHRFloatControls2) {
               RequireKHRFloatControls2 = true;
@@ -2096,8 +2093,7 @@ static unsigned getFastMathFlags(const MachineInstr &I,
 static void handleMIFlagDecoration(
     MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
     SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR,
-    SmallVector<SPIRV::FPFastMathDefaultInfo, 4>
-        &FPFastMathDefaultInfoVec) {
+    SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec) {
   if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
       getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
                                      SPIRV::Decoration::NoSignedWrap, ST, Reqs)

>From de07e832964c6968eebf718d2aad0336e95bfc94 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 20:15:27 +0200
Subject: [PATCH 07/11] Yet more work to apply deprecations only when extension
 is enabled.

---
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 33 ++++++++++---------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 999214381b634..4dcec19692eb7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2042,6 +2042,8 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
 static unsigned getFastMathFlags(const MachineInstr &I,
                                  const SPIRVSubtarget &ST) {
   unsigned Flags = SPIRV::FPFastMathMode::None;
+  bool CanUseKHRFloatControls2 =
+      ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
   if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
     Flags |= SPIRV::FPFastMathMode::NotNaN;
   if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
@@ -2050,10 +2052,10 @@ static unsigned getFastMathFlags(const MachineInstr &I,
     Flags |= SPIRV::FPFastMathMode::NSZ;
   if (I.getFlag(MachineInstr::MIFlag::FmArcp))
     Flags |= SPIRV::FPFastMathMode::AllowRecip;
-  if (I.getFlag(MachineInstr::MIFlag::FmContract))
+  if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
     Flags |= SPIRV::FPFastMathMode::AllowContract;
   if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
-    if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
+    if (CanUseKHRFloatControls2)
       // LLVM reassoc maps to SPIRV transform, see
       // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
       // Because we are enabling AllowTransform, we must enable AllowReassoc and
@@ -2070,7 +2072,7 @@ static unsigned getFastMathFlags(const MachineInstr &I,
       Flags |= SPIRV::FPFastMathMode::Fast;
   }
 
-  if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
+  if (CanUseKHRFloatControls2) {
     // Error out if SPIRV::FPFastMathMode::Fast is enabled.
     if (Flags & SPIRV::FPFastMathMode::Fast)
       report_fatal_error(
@@ -2115,8 +2117,8 @@ static void handleMIFlagDecoration(
 
   unsigned FMFlags = getFastMathFlags(I, ST);
   if (FMFlags == SPIRV::FPFastMathMode::None) {
-    // We also need to check if any FPFastMathDefault info was set for the types
-    // used in this instruction.
+    // We also need to check if any FPFastMathDefault info was set for the
+    // types used in this instruction.
     if (FPFastMathDefaultInfoVec.empty())
       return;
 
@@ -2126,14 +2128,13 @@ static void handleMIFlagDecoration(
     // 3. Extended instructions (ExtInst)
     // For arithmetic instructions, the floating point type can be in the
     // result type or in the operands, but they all must be the same.
-    // For the relational and logical instructions, the floating point type can
-    // only be in the operands 1 and 2, not the result type. Also, the operands
-    // must have the same type.
-    // For the extended instructions, the floating point type can be in the
-    // result type or in the operands. It's unclear if the operands
-    // and the result type must be the same. Let's assume they must be.
-    // Therefore, for 1. and 2., we can check the first operand type,
-    // and for 3. we can check the result type.
+    // For the relational and logical instructions, the floating point type
+    // can only be in the operands 1 and 2, not the result type. Also, the
+    // operands must have the same type. For the extended instructions, the
+    // floating point type can be in the result type or in the operands. It's
+    // unclear if the operands and the result type must be the same. Let's
+    // assume they must be. Therefore, for 1. and 2., we can check the first
+    // operand type, and for 3. we can check the result type.
     assert(I.getNumOperands() >= 3 && "Expected at least 3 operands");
     Register ResReg = I.getOpcode() == SPIRV::OpExtInst
                           ? I.getOperand(1).getReg()
@@ -2310,9 +2311,9 @@ static void collectFPFastMathDefaults(const Module &M,
         SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
             getOrCreateFPFastMathDefaultInfoVec(M, MAI, F);
         int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth);
-        assert(
-            Index >= 0 && Index < 4 &&
-            "Expected FPFastMathDefaultInfo for half, float, double, or fp128");
+        assert(Index >= 0 && Index < 4 &&
+               "Expected FPFastMathDefaultInfo for half, float, double, or "
+               "fp128");
         assert(FPFastMathDefaultInfoVec.size() == 4 &&
                "Expected FPFastMathDefaultInfoVec to have exactly 4 elements");
         FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;

>From 3edf82a9e08332c82e6d2285f8899a2e4bb4ddc3 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 20:47:12 +0200
Subject: [PATCH 08/11] Renamings and bugfixes.

---
 llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp     |  6 +++---
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 15 +++++++++------
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h   |  2 +-
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 06d67eb086cf2..38ffdf1af2fcb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -738,7 +738,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
       unsigned Flags = FPFastMathDefaultInfo.FastMathFlags;
       if (FPFastMathDefaultInfo.ContractionOff &&
           (Flags & SPIRV::FPFastMathMode::AllowContract) &&
-          FPFastMathDefaultInfo.FPFastMathMode)
+          FPFastMathDefaultInfo.FPFastMathDefault)
         report_fatal_error(
             "Conflicting FPFastMathFlags: ContractionOff and AllowContract");
 
@@ -746,7 +746,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
           !(Flags &
             (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
              SPIRV::FPFastMathMode::NSZ))) {
-        if (FPFastMathDefaultInfo.FPFastMathMode)
+        if (FPFastMathDefaultInfo.FPFastMathDefault)
           report_fatal_error("Conflicting FPFastMathFlags: "
                              "SignedZeroInfNanPreserve but at least one of "
                              "NotNaN/NotInf/NSZ is disabled.");
@@ -759,7 +759,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
       if (Flags == SPIRV::FPFastMathMode::None &&
           !FPFastMathDefaultInfo.ContractionOff &&
           !FPFastMathDefaultInfo.SignedZeroInfNanPreserve &&
-          !FPFastMathDefaultInfo.FPFastMathMode)
+          !FPFastMathDefaultInfo.FPFastMathDefault)
         continue;
       Inst.addOperand(MCOperand::createImm(Flags));
       outputMCInst(Inst);
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 4dcec19692eb7..c7707e1db61fe 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2082,8 +2082,8 @@ static unsigned getFastMathFlags(const MachineInstr &I,
     // Error out if AllowTransform is enabled without AllowReassoc and
     // AllowContract.
     if ((Flags & SPIRV::FPFastMathMode::AllowTransform) &&
-        !(Flags & SPIRV::FPFastMathMode::AllowReassoc) &&
-        !(Flags & SPIRV::FPFastMathMode::AllowContract))
+        (!(Flags & SPIRV::FPFastMathMode::AllowReassoc) ||
+         !(Flags & SPIRV::FPFastMathMode::AllowContract)))
       report_fatal_error(
           "FPFastMathMode::AllowTransform flag requires AllowReassoc and "
           "AllowContract flags to be enabled as well.");
@@ -2143,15 +2143,16 @@ static void handleMIFlagDecoration(
     const Type *Ty = GR->getTypeForSPIRVType(ResType);
 
     // Match instruction type with the FPFastMathDefaultInfoVec.
+    bool Emit = false;
     for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
       if (Ty == Elem.Ty) {
         FMFlags = Elem.FastMathFlags;
-        Elem.FPFastMathMode = true;
+        Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve || Elem.FPFastMathDefault;
         break;
       }
     }
 
-    if (FMFlags == SPIRV::FPFastMathMode::None)
+    if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
       return;
   }
   Register DstReg = I.getOperand(0).getReg();
@@ -2287,8 +2288,10 @@ static void collectFPFastMathDefaults(const Module &M,
                 ->getZExtValue();
         SmallVector<SPIRV::FPFastMathDefaultInfo, 4> &FPFastMathDefaultInfoVec =
             getOrCreateFPFastMathDefaultInfoVec(M, MAI, F);
-        getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T).FastMathFlags =
-            Flags;
+        SPIRV::FPFastMathDefaultInfo &Info =
+            getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
+        Info.FastMathFlags = Flags;
+        Info.FPFastMathDefault = true;
       } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
         assert(MDN->getNumOperands() == 2 &&
                "Expected no operands for ContractionOff");
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 8e0de616337c7..31f52736cd603 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -145,7 +145,7 @@ struct FPFastMathDefaultInfo {
   // emit OpExecutionMode instructions.
   bool ContractionOff = false;
   bool SignedZeroInfNanPreserve = false;
-  bool FPFastMathMode = false;
+  bool FPFastMathDefault = false;
 
   FPFastMathDefaultInfo() = default;
   FPFastMathDefaultInfo(const Type *Ty, unsigned FastMathFlags)

>From c0ef106fd8bd4750f7976eb6fd08fc387e46427e Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 21:09:44 +0200
Subject: [PATCH 09/11] Renamings, bugfixes and undo undesired changes.

---
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp            | 1 -
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h              | 5 ++++-
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp                     | 9 +++++----
 llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll   | 6 +++---
 .../test/CodeGen/SPIRV/execution-mode-per-entry-point.ll | 4 ++--
 llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll | 4 +++-
 .../CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll    | 2 +-
 .../SPIRV/opencl/metadata/no_fp_contractions_metadata.ll | 2 +-
 8 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index c7707e1db61fe..54f1fa49682a3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -2268,7 +2268,6 @@ static void collectFPFastMathDefaults(const Module &M,
   auto Node = M.getNamedMetadata("spirv.ExecutionMode");
   if (Node) {
     for (unsigned i = 0; i < Node->getNumOperands(); i++) {
-
       MDNode *MDN = cast<MDNode>(Node->getOperand(i));
       assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
       const Function *F = cast<Function>(
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index 31f52736cd603..152179cba7687 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -151,7 +151,10 @@ struct FPFastMathDefaultInfo {
   FPFastMathDefaultInfo(const Type *Ty, unsigned FastMathFlags)
       : Ty(Ty), FastMathFlags(FastMathFlags) {}
   bool operator==(const FPFastMathDefaultInfo &Other) const {
-    return Ty == Other.Ty && FastMathFlags == Other.FastMathFlags;
+    return Ty == Other.Ty && FastMathFlags == Other.FastMathFlags &&
+           ContractionOff == Other.ContractionOff &&
+           SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve &&
+           FPFastMathDefault == Other.FPFastMathDefault;
   }
 };
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 657d69f04d779..e39cdb91c2db3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -173,7 +173,7 @@ void buildOpMemberDecorate(Register Reg, MachineInstr &I,
 void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
                              const MDNode *GVarMD, const SPIRVSubtarget &ST) {
   bool NoContractionFound = false;
-  bool HasFPFastMathMode = false;
+  bool FPFastMathModeFound = false;
   unsigned FPFastMathFlags = SPIRV::FPFastMathMode::None;
   for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
     auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
@@ -200,7 +200,7 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
       continue; // NoContraction is handled separately.
     } else if (DecorationId->getZExtValue() ==
                static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode)) {
-      HasFPFastMathMode = true;
+      FPFastMathModeFound = true;
       FPFastMathFlags = mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(1))
                             ->getZExtValue();
       continue; // FPFastMathMode is handled separately.
@@ -219,13 +219,14 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
     }
   }
   // If we have NoContraction decoration, we should set the
-  // FPFastMathMode::NoContraction flag.
+  // FPFastMathMode::AllowContract bit to 0. If it has been set to 1 by
+  // FPFastMathMode decoration, we should report an error.
   if (NoContractionFound &&
       (FPFastMathFlags & SPIRV::FPFastMathMode::AllowContract))
     report_fatal_error(
         "Conflicting FPFastMathFlags: NoContraction and AllowContract");
 
-  if (NoContractionFound || HasFPFastMathMode) {
+  if (NoContractionFound || FPFastMathModeFound) {
     MIRBuilder.buildInstr(SPIRV::OpDecorate)
         .addUse(Reg)
         .addImm(static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode))
diff --git a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
index 058337c8a79f2..cae156fc8136e 100644
--- a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
+++ b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
@@ -11,7 +11,7 @@ entry:
   ret void
 }
 
-define dso_local dllexport spir_kernel void @k_float_controls_2(half %h, float %f, double %d) local_unnamed_addr {
+define dso_local dllexport spir_kernel void @k_float_controls_2(i32 %ibuf, i32 %obuf) local_unnamed_addr {
 entry:
   ret void
 }
@@ -53,11 +53,11 @@ entry:
 !20 = !{void (i32, i32)* @k_float_controls_1, i32 4460, i32 16}
 
 ; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 64 
-!21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
+!21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
 ; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 32 
 !22 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 32}
 ; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 16 
-!23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
+!23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
 
 ; SPV-DAG: OpExecutionMode %[[#KERNEL3]] RoundingModeRTE 64
 !24 = !{void (i32, i32)* @k_float_controls_3, i32 4462, i32 64}
diff --git a/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll b/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
index 5f2a7d5d2ca32..6fd1abd2be59a 100644
--- a/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
+++ b/llvm/test/CodeGen/SPIRV/execution-mode-per-entry-point.ll
@@ -18,7 +18,7 @@
 ; CHECKN-NOT: OpExecutionMode
 ; CHECKN: OpSource
 
-define spir_kernel void @foo1(float %f) {
+define spir_kernel void @foo1() {
 entry:
   ret void
 }
@@ -33,7 +33,7 @@ entry:
   ret void
 }
 
-define spir_kernel void @foo4(float %f) {
+define spir_kernel void @foo4() {
 entry:
   ret void
 }
diff --git a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
index 6f820bee43f11..43336db4e86fa 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/float-fast-flags.ll
@@ -11,6 +11,7 @@
 ; CHECK-DAG: [[F32Ty:%.+]] = OpTypeFloat 32
 ; CHECK-DAG: [[FNTy:%.+]] = OpTypeFunction [[F32Ty]] [[F32Ty]] [[F32Ty]]
 
+
 ; CHECK:      [[FADD]] = OpFunction [[F32Ty]] None [[FNTy]]
 ; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
@@ -42,7 +43,7 @@ define float @test_fsub(float %a, float %b) {
 ; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
 ; CHECK-NEXT: [[C:%.+]] = OpFMul [[F32Ty]] [[A]] [[B]]
-;; TODO: OpDecorate checks
+;; TODO: OpDecorate checks]
 ; CHECK-NEXT: OpReturnValue [[C]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fmul(float %a, float %b) {
@@ -85,6 +86,7 @@ declare float @llvm.fma.f32(float, float, float)
 ; CHECK-NEXT: [[C:%.+]] = OpFunctionParameter [[F32Ty]]
 ; CHECK-NEXT: OpLabel
 ; CHECK-NEXT: [[R:%.+]] = OpExtInst [[F32Ty]] {{%.+}} fma [[A]] [[B]] [[C]]
+;; TODO: OpDecorate checks
 ; CHECK-NEXT: OpReturnValue [[R]]
 ; CHECK-NEXT: OpFunctionEnd
 define float @test_fma(float %a, float %b, float %c) {
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
index 42d94a556e4c3..5d8f547054dbf 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/arithmetic-fence.ll
@@ -1,7 +1,7 @@
 ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux %s -o - | FileCheck %s --check-prefixes=CHECK-NOEXT
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux --spirv-ext=+SPV_EXT_arithmetic_fence %s -o - | FileCheck %s --check-prefixes=CHECK-EXT
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-linux %s -o - --spirv-ext=+SPV_EXT_arithmetic_fence | FileCheck %s --check-prefixes=CHECK-EXT
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK-NOEXT-NO: OpCapability ArithmeticFenceEXT
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
index a1ce51b10b465..2bf0a7dbcc2c0 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
@@ -2,7 +2,7 @@
 
 ; CHECK: OpEntryPoint Kernel %[[#ENTRY:]] "foo"
 ; CHECK: OpExecutionMode %[[#ENTRY]] ContractionOff 
-define spir_kernel void @foo(half %h, float %f, double %d, fp128 %fp) {
+define spir_kernel void @foo() {
 entry:
   ret void
 }

>From 97720d5d84cfc8eda01521e3535f2d85f60011ff Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 3 Jul 2025 21:11:14 +0200
Subject: [PATCH 10/11] Undo undesired changes.

---
 llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll      | 6 +++---
 .../SPIRV/opencl/metadata/no_fp_contractions_metadata.ll    | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
index cae156fc8136e..d3131e5606857 100644
--- a/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
+++ b/llvm/test/CodeGen/SPIRV/exec_mode_float_control_khr.ll
@@ -52,11 +52,11 @@ entry:
 ; SPV-DAG: OpExecutionMode %[[#KERNEL1]] DenormFlushToZero 16
 !20 = !{void (i32, i32)* @k_float_controls_1, i32 4460, i32 16}
 
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 64 
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 64
 !21 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 64}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 32 
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 32
 !22 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 32}
-; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 16 
+; SPV-DAG: OpExecutionMode %[[#KERNEL2]] SignedZeroInfNanPreserve 16
 !23 = !{void (i32, i32)* @k_float_controls_2, i32 4461, i32 16}
 
 ; SPV-DAG: OpExecutionMode %[[#KERNEL3]] RoundingModeRTE 64
diff --git a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
index 2bf0a7dbcc2c0..10840125b9f61 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/metadata/no_fp_contractions_metadata.ll
@@ -1,7 +1,7 @@
 ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
 ; CHECK: OpEntryPoint Kernel %[[#ENTRY:]] "foo"
-; CHECK: OpExecutionMode %[[#ENTRY]] ContractionOff 
+; CHECK: OpExecutionMode %[[#ENTRY]] ContractionOff
 define spir_kernel void @foo() {
 entry:
   ret void

>From eccd27a45ed038e220da7e3f1a8c3ea04346da58 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Fri, 4 Jul 2025 12:38:03 +0200
Subject: [PATCH 11/11] Fix after-merge bugs.

---
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp     | 15 ++++++++++++++-
 llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td    |  1 -
 .../CodeGen/SPIRV/capability-FloatControl2.ll     |  2 +-
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index ff040e0ebbe72..288bb154a1a84 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1994,6 +1994,18 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
             }
             break;
           }
+          case SPIRV::ExecutionMode::ContractionOff:
+          case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
+            if (HasKHRFloatControls2) {
+              RequireKHRFloatControls2 = true;
+              MAI.Reqs.getAndAddRequirements(
+                  SPIRV::OperandCategory::ExecutionModeOperand,
+                  SPIRV::ExecutionMode::FPFastMathDefault, ST);
+            } else {
+              MAI.Reqs.getAndAddRequirements(
+                  SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
+            }
+            break;
           default:
             MAI.Reqs.getAndAddRequirements(
                 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
@@ -2163,7 +2175,8 @@ static void handleMIFlagDecoration(
     for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
       if (Ty == Elem.Ty) {
         FMFlags = Elem.FastMathFlags;
-        Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve || Elem.FPFastMathDefault;
+        Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
+               Elem.FPFastMathDefault;
         break;
       }
     }
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 555a61dff49b4..3c384e1dbd993 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -529,7 +529,6 @@ defm Subgroup2DBlockTransformINTEL : CapabilityOperand<6229, 0, 0, [SPV_INTEL_2d
 defm Subgroup2DBlockTransposeINTEL : CapabilityOperand<6230, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>;
 defm Int4TypeINTEL : CapabilityOperand<5112, 0, 0, [SPV_INTEL_int4], []>;
 defm Int4CooperativeMatrixINTEL : CapabilityOperand<5114, 0, 0, [SPV_INTEL_int4], [Int4TypeINTEL, CooperativeMatrixKHR]>;
-defm FloatControls2 : CapabilityOperand<6029, 0, 0, [SPV_KHR_float_controls2], []>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define SourceLanguage enum values and at the same time
diff --git a/llvm/test/CodeGen/SPIRV/capability-FloatControl2.ll b/llvm/test/CodeGen/SPIRV/capability-FloatControl2.ll
index aa60e13232b46..b4e283e746125 100644
--- a/llvm/test/CodeGen/SPIRV/capability-FloatControl2.ll
+++ b/llvm/test/CodeGen/SPIRV/capability-FloatControl2.ll
@@ -8,7 +8,7 @@
 
 ; CHECK-EXT: OpCapability FloatControls2
 ; CHECK-EXT: OpExtension "SPV_KHR_float_controls2"
-; CHECK-EXT: OpDecorate {{%[0-9]+}} FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast
+; CHECK-EXT: OpDecorate {{%[0-9]+}} FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
 
 define hidden spir_func float @foo(float  %0) local_unnamed_addr {
   %2 = fmul reassoc nnan ninf nsz arcp afn float %0, 2.000000e+00



More information about the llvm-commits mailing list