[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