From cbe7a07417b24e059843a1882bdb765adef5fd4b Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Wed, 25 Jun 2025 20:32:33 +0200 Subject: [PATCH 01/31] 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(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( + cast((Node->getOperand(i))->getOperand(1)) + ->getValue()) + ->getZExtValue(); + if (EM == SPIRV::ExecutionMode::FPFastMathDefault) + continue; + MCInst Inst; Inst.setOpcode(SPIRV::OpExecutionMode); addOpsFromMDNode(cast(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(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(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 lowerBuiltin(const StringRef DemangledCall, MachineIRBuilder &MIRBuilder, const Register OrigRet, const Type *OrigRetTy, const SmallVectorImpl &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 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 lowerBuiltin(const StringRef DemangledCall, MachineIRBuilder &MIRBuilder, const Register OrigRet, const Type *OrigRetTy, const SmallVectorImpl &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> 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(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(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 + &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(Node->getOperand(i)); + assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands"); + const Function *F = cast( + cast(MDN->getOperand(0))->getValue()); + const auto EM = + cast( + cast(MDN->getOperand(1))->getValue()) + ->getZExtValue(); + if (EM == SPIRV::ExecutionMode::FPFastMathDefault) { + assert(MDN->getNumOperands() == 4 && + "Expected 4 operands for FPFastMathDefault"); + + const Type *T = cast(MDN->getOperand(2))->getType(); + unsigned Flags = + cast( + cast(MDN->getOperand(3))->getValue()) + ->getZExtValue(); + SmallVector &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 + &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 + &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; using RegisterAliasMapTy = std::map; +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, MCRegister> BBNumToRegMap; + // The table maps function pointers to their default FP fast math info. + DenseMap> + 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(GVarMD->getOperand(I)); if (!OpMD) @@ -183,6 +186,24 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, if (!DecorationId) report_fatal_error("Expect SPIR-V 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(SPIRV::Decoration::NoContraction)) { + NoContractionFound = true; + continue; // NoContraction is handled separately. + } else if (DecorationId->getZExtValue() == + static_cast(SPIRV::Decoration::FPFastMathMode)) { + HasFPFastMathMode = true; + FPFastMathFlags = mdconst::dyn_extract(OpMD->getOperand(1)) + ->getZExtValue(); + continue; // FPFastMathMode is handled separately. + } auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) .addUse(Reg) .addImm(static_cast(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(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 Date: Mon, 30 Jun 2025 16:19:52 +0200 Subject: [PATCH 02/31] 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((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 & +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 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 &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(MDN->getOperand(3))->getValue()) ->getZExtValue(); SmallVector &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 - &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 &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 - &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( + cast(MDN->getOperand(2))->getValue()) + ->getZExtValue(); + // We need to save this info only for the FP type with TargetWidth. + SmallVector &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, 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> 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 Date: Thu, 3 Jul 2025 19:42:37 +0200 Subject: [PATCH 03/31] 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( - cast((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( + cast((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 + // 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(OrigMI); + MachineOperand &OrigFlagsOp = OrigMINonConst->getOperand(2); + OrigFlagsOp = + MachineOperand::CreateImm(static_cast(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 + SmallVector &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(MIB.getMF().getSubtarget()); SmallVector 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( 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 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(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(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 Date: Thu, 3 Jul 2025 19:43:01 +0200 Subject: [PATCH 04/31] 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 Date: Thu, 3 Jul 2025 19:58:20 +0200 Subject: [PATCH 05/31] 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(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(SPIRV::ExecutionMode::FPFastMathDefault); + static_cast(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(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 Date: Thu, 3 Jul 2025 20:04:53 +0200 Subject: [PATCH 06/31] 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 - &FPFastMathDefaultInfoVec) { + SmallVector &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 Date: Thu, 3 Jul 2025 20:15:27 +0200 Subject: [PATCH 07/31] 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 &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 Date: Thu, 3 Jul 2025 20:47:12 +0200 Subject: [PATCH 08/31] 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 &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 Date: Thu, 3 Jul 2025 21:09:44 +0200 Subject: [PATCH 09/31] 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(Node->getOperand(i)); assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands"); const Function *F = cast( 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(GVarMD->getOperand(I)); @@ -200,7 +200,7 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, continue; // NoContraction is handled separately. } else if (DecorationId->getZExtValue() == static_cast(SPIRV::Decoration::FPFastMathMode)) { - HasFPFastMathMode = true; + FPFastMathModeFound = true; FPFastMathFlags = mdconst::dyn_extract(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(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 Date: Thu, 3 Jul 2025 21:11:14 +0200 Subject: [PATCH 10/31] 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 Date: Fri, 4 Jul 2025 12:38:03 +0200 Subject: [PATCH 11/31] 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 From 868c6a45c02cb071e0268830de8f458782700d4b Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Fri, 4 Jul 2025 13:01:24 +0200 Subject: [PATCH 12/31] Fix clang-format issues. --- llvm/lib/Target/SPIRV/SPIRVInstrInfo.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h index fda3142111bf0..925c8c70ed5f4 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h @@ -35,7 +35,8 @@ 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, bool KHRFloatControls2) const; + bool canUseFastMathFlags(const MachineInstr &MI, + bool KHRFloatControls2) const; bool canUseNSW(const MachineInstr &MI) const; bool canUseNUW(const MachineInstr &MI) const; From 21c17d11753b52703ccd1dcd78a621a929b690b2 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Fri, 4 Jul 2025 13:04:52 +0200 Subject: [PATCH 13/31] Replace undef with poison for placeholders. --- .../SPV_KHR_float_controls2/exec_mode.ll | 20 +++++++++---------- .../SPV_KHR_float_controls2/exec_mode2.ll | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) 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 index aeee4e9ebbca9..ebee66c9c62a9 100644 --- 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 @@ -65,29 +65,29 @@ entry: !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} +!17 = !{ptr @k_float_controls_half, i32 6028, half poison, i32 1} ; CHECK-DAG: OpExecutionMode %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] 2 -!18 = !{ptr @k_float_controls_bfloat, i32 6028, bfloat undef, i32 2} +!18 = !{ptr @k_float_controls_bfloat, i32 6028, bfloat poison, i32 2} ; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 4 -!19 = !{ptr @k_float_controls_float, i32 6028, float undef, i32 4} +!19 = !{ptr @k_float_controls_float, i32 6028, float poison, i32 4} ; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 -!20 = !{ptr @k_float_controls_double, i32 6028, double undef, i32 7} +!20 = !{ptr @k_float_controls_double, i32 6028, double poison, i32 7} ; CHECK-DAG: OpExecutionMode %[[#KERNEL_FP128]] FPFastMathDefault %[[#FP128_TYPE:]] 65536 -!21 = !{ptr @k_float_controls_fp128, i32 6028, fp128 undef, i32 65536} +!21 = !{ptr @k_float_controls_fp128, i32 6028, fp128 poison, 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} +!22 = !{ptr @k_float_controls_all, i32 6028, half poison, i32 131072} +!23 = !{ptr @k_float_controls_all, i32 6028, bfloat poison, i32 131072} +!24 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 262144} +!25 = !{ptr @k_float_controls_all, i32 6028, double poison, i32 458752} +!26 = !{ptr @k_float_controls_all, i32 6028, fp128 poison, i32 65543} ; CHECK: %[[#HALF_TYPE]] = OpTypeFloat 16 ; CHECK: %[[#FLOAT_TYPE]] = OpTypeFloat 32 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 index f9f72748809cf..28015790bf0a0 100644 --- 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 @@ -34,14 +34,14 @@ entry: !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} +!19 = !{ptr @k_float_controls_float, i32 6028, float poison, 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} +!20 = !{ptr @k_float_controls_all, i32 6028, float poison, 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} From cfdc210d8630aa07d74b1b787acd3774c18f48ff Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Mon, 7 Jul 2025 15:54:28 +0200 Subject: [PATCH 14/31] Add SPIR-V Instructions Mapped to LLVM Metadata section. --- llvm/docs/SPIRVUsage.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 3bb40ed313bc4..3f6fa241da8ac 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -585,3 +585,31 @@ Group and Subgroup Operations For workgroup and subgroup operations, LLVM uses function calls to represent SPIR-V's group-based instructions. These builtins facilitate group synchronization, data sharing, and collective operations essential for efficient parallel computation. + +SPIR-V Instructions Mapped to LLVM Metadata +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Some SPIR-V instructions don't have a direct equivalent in the LLVM IR language. To +address this, the SPIR-V Target uses different specific LLVM named metadata to convey +the necessary information. The SPIR-V specification allows multiple module-scope +instructions, where as LLVM named metadata must be unique. Therefore, the encoding of +such instructions has the following format: + +.. code-block:: llvm + + !spirv. = !{!, !, ..} + ! = !{, , ..} + ! = !{, , ..} + +Below, you will find the mappings between SPIR-V instruction and their corresponding +LLVM IR representations. + ++--------------------+---------------------------------------------------------+ +| SPIR-V instruction | LLVM IR | ++====================+=========================================================+ +| OpExecutionMode | .. code-block:: llvm | +| | | +| | !spirv.ExecutionMode = !{!0} | +| | !0 = !{void @worker, i32 30, i32 262149} | +| | ; Set execution mode with id 30 (VecTypeHint) and | +| | ; literal `262149` operand. | ++--------------------+---------------------------------------------------------+ From 9b8b43d64dd1563034547b483f75715a6a10a16d Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Mon, 7 Jul 2025 15:55:09 +0200 Subject: [PATCH 15/31] Address code review. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 1 - .../extensions/SPV_KHR_float_controls2/decoration.ll | 6 ------ .../SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll | 7 ------- .../extensions/SPV_KHR_float_controls2/exec_mode2.ll | 8 -------- 4 files changed, 22 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index 3626d94e505b9..24e4e390f98f0 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -459,7 +459,6 @@ 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(EM))); addOpsFromMDNode(Node, Inst, MAI); 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 index 91dc5e8772a09..cb8e6d9e3b427 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll @@ -87,12 +87,6 @@ entry: 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 index ebee66c9c62a9..3430dd731fee9 100644 --- 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 @@ -34,12 +34,8 @@ 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} @@ -60,9 +56,6 @@ entry: !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 poison, i32 1} 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 index 28015790bf0a0..79b9c9b160988 100644 --- 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 @@ -14,13 +14,8 @@ 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" @@ -29,9 +24,6 @@ entry: !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 poison, i32 131079} From a3532950729bf1ae17b7e49fad7fe75b5a8297bb Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Wed, 16 Jul 2025 20:28:12 +0200 Subject: [PATCH 16/31] Address code review feedback. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 132 +++++++----------- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 60 ++++---- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h | 4 +- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 6 +- .../SPV_KHR_float_controls2/decoration.ll | 3 - .../SPV_KHR_float_controls2/exec_mode.ll | 18 +-- .../SPV_KHR_float_controls2/exec_mode2.ll | 7 +- 7 files changed, 83 insertions(+), 147 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index 24e4e390f98f0..e97ba48f219d9 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -572,64 +572,32 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) { // 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) { + // to emit it for each floating-point type that exists in the module + // to match the effect of ContractionOff. As of now, there are 4 FP + // types: fp16, fp32 and fp64. + for (const MachineInstr *MI : + MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) { + // Skip if the instruction is not OpTypeFloat. + if (MI->getOpcode() != SPIRV::OpTypeFloat) + continue; + + // Skip if the target type is not fp16, fp32, fp64. + const unsigned OpTypeFloatSize = MI->getOperand(1).getImm(); + if (OpTypeFloatSize != 16 && OpTypeFloatSize != 32 && + OpTypeFloatSize != 64) { + continue; + } + MCInst Inst; Inst.setOpcode(SPIRV::OpExecutionMode); Inst.addOperand(MCOperand::createReg(FReg)); unsigned EM = static_cast(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; - } + const MachineFunction *MF = MI->getMF(); + MCRegister TypeReg = + MAI->getRegisterAlias(MF, MI->getOperand(0).getReg()); + Inst.addOperand(MCOperand::createReg(TypeReg)); // 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. @@ -694,9 +662,33 @@ void SPIRVAsmPrinter::outputAnnotations(const Module &M) { } void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { + // Collect the SPIRVTypes that are OpTypeFloat. + std::vector SPIRVFloatTypes; + for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) { + // Skip if the instruction is not OpTypeFloat. + if (MI->getOpcode() != SPIRV::OpTypeFloat) + continue; + + // Collect the SPIRV type. + SPIRVFloatTypes.push_back(MI); + } + for (const auto &[Func, FPFastMathDefaultInfoVec] : MAI->FPFastMathDefaultInfoMap) { - for (const auto &FPFastMathDefaultInfo : FPFastMathDefaultInfoVec) { + if (FPFastMathDefaultInfoVec.empty()) + continue; + + for (const MachineInstr *MI : SPIRVFloatTypes) { + unsigned OpTypeFloatSize = MI->getOperand(1).getImm(); + unsigned Index = computeFPFastMathDefaultInfoVecIndex(OpTypeFloatSize); + assert(Index < FPFastMathDefaultInfoVec.size() && + "Index out of bounds for FPFastMathDefaultInfoVec"); + const auto &FPFastMathDefaultInfo = FPFastMathDefaultInfoVec[Index]; + assert(FPFastMathDefaultInfo.Ty && + "Expected target type for FPFastMathDefaultInfo"); + assert(FPFastMathDefaultInfo.Ty->getScalarSizeInBits() == + OpTypeFloatSize && + "Mismatched float type size"); MCInst Inst; Inst.setOpcode(SPIRV::OpExecutionMode); MCRegister FuncReg = MAI->getFuncReg(Func); @@ -704,37 +696,9 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { 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) { - // The module does not contain this FP type, so we don't need to emit - // FPFastMathDefault for it. - continue; - } - + MCRegister TypeReg = + MAI->getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg()); + Inst.addOperand(MCOperand::createReg(TypeReg)); unsigned Flags = FPFastMathDefaultInfo.FastMathFlags; if (FPFastMathDefaultInfo.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract) && diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 288bb154a1a84..7c1b4bce0a4e6 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -2094,25 +2094,24 @@ static unsigned getFastMathFlags(const MachineInstr &I, if (CanUseKHRFloatControls2) { // 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."); + assert(!(Flags & SPIRV::FPFastMathMode::Fast) && + "SPIRV::FPFastMathMode::Fast is deprecated and should not be used " + "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."); + assert( + !(Flags & SPIRV::FPFastMathMode::AllowTransform) || + ((Flags & SPIRV::FPFastMathMode::AllowReassoc && + Flags & SPIRV::FPFastMathMode::AllowContract)) && + "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and " + "AllowContract flags to be enabled as well."); } return Flags; } -static bool isFastMathMathModeAvailable(const SPIRVSubtarget &ST) { +static bool isFastMathModeAvailable(const SPIRVSubtarget &ST) { if (ST.isKernel()) return true; if (ST.getSPIRVVersion() < VersionTuple(1, 2)) @@ -2123,7 +2122,7 @@ static bool isFastMathMathModeAvailable(const SPIRVSubtarget &ST) { static void handleMIFlagDecoration( MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII, SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR, - SmallVector &FPFastMathDefaultInfoVec) { + SmallVector &FPFastMathDefaultInfoVec) { if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) && getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, SPIRV::Decoration::NoSignedWrap, ST, Reqs) @@ -2184,7 +2183,7 @@ static void handleMIFlagDecoration( if (FMFlags == SPIRV::FPFastMathMode::None && !Emit) return; } - if (isFastMathMathModeAvailable(ST)) { + if (isFastMathModeAvailable(ST)) { Register DstReg = I.getOperand(0).getReg(); buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags}); @@ -2250,7 +2249,7 @@ static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR, } } -static SmallVector & +static SmallVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, const Function *F) { @@ -2259,29 +2258,27 @@ getOrCreateFPFastMathDefaultInfoVec(const Module &M, 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 FPFastMathDefaultInfoVec; + // contain all 3 elements sorted by bit width of target type: {half, float, + // double}. + SmallVector 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 &FPFastMathDefaultInfoVec, + SmallVector &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"); + assert(Index >= 0 && Index < 3 && + "Expected FPFastMathDefaultInfo for half, float, or double"); + assert(FPFastMathDefaultInfoVec.size() == 3 && + "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); return FPFastMathDefaultInfoVec[Index]; } @@ -2317,7 +2314,7 @@ static void collectFPFastMathDefaults(const Module &M, cast( cast(MDN->getOperand(3))->getValue()) ->getZExtValue(); - SmallVector &FPFastMathDefaultInfoVec = + SmallVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); SPIRV::FPFastMathDefaultInfo &Info = getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T); @@ -2329,7 +2326,7 @@ static void collectFPFastMathDefaults(const Module &M, // We need to save this info for every possible FP type, i.e. {half, // float, double, fp128}. - SmallVector &FPFastMathDefaultInfoVec = + SmallVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { Info.ContractionOff = true; @@ -2342,14 +2339,13 @@ static void collectFPFastMathDefaults(const Module &M, cast(MDN->getOperand(2))->getValue()) ->getZExtValue(); // We need to save this info only for the FP type with TargetWidth. - SmallVector &FPFastMathDefaultInfoVec = + SmallVector &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"); + assert(Index >= 0 && Index < 3 && + "Expected FPFastMathDefaultInfo for half, float, or double"); + assert(FPFastMathDefaultInfoVec.size() == 3 && + "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true; } } diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h index 152179cba7687..2ce5b2d8f4d69 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h @@ -189,9 +189,9 @@ struct ModuleAnalysisInfo { // 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 + // largest bit width, therefore, we will have {half, float, double} in // the order of their bit widths. - DenseMap> + DenseMap> FPFastMathDefaultInfoMap; MCRegister getFuncReg(const Function *F) { diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index afaf19501db09..ca3cb720d7a4d 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -568,8 +568,6 @@ 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; @@ -1041,10 +1039,8 @@ size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth) { 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); + report_fatal_error("Expected BitWidth to be 16, 32, 64", false); } assert(false && "Unreachable code"); // This return is just to avoid compiler warnings. 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 index cb8e6d9e3b427..8a80a8369a1e8 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll @@ -50,9 +50,6 @@ ; 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 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 index 3430dd731fee9..a02459cac6a06 100644 --- 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 @@ -24,17 +24,12 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_fp128(fp128 %fp) { +define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d) { 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 -} - -!spirv.ExecutionMode = !{!17, !18, !19, !20, !21, !22, !23, !24, !25, !26} +!spirv.ExecutionMode = !{!17, !18, !19, !20, !22, !23, !24, !25} ; 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} @@ -48,9 +43,6 @@ entry: ; 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} @@ -69,20 +61,14 @@ entry: ; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 !20 = !{ptr @k_float_controls_double, i32 6028, double poison, i32 7} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FP128]] FPFastMathDefault %[[#FP128_TYPE:]] 65536 -!21 = !{ptr @k_float_controls_fp128, i32 6028, fp128 poison, 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 poison, i32 131072} !23 = !{ptr @k_float_controls_all, i32 6028, bfloat poison, i32 131072} !24 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 262144} !25 = !{ptr @k_float_controls_all, i32 6028, double poison, i32 458752} -!26 = !{ptr @k_float_controls_all, i32 6028, fp128 poison, 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 index 79b9c9b160988..b65c18db56208 100644 --- 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 @@ -9,12 +9,12 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d, fp128 %fp) { +define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d) { entry: ret void } -!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26, !27} +!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26} ; 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} @@ -32,7 +32,6 @@ entry: ; 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 poison, i32 131079} ; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false. !21 = !{ptr @k_float_controls_float, i32 31} @@ -42,9 +41,7 @@ entry: !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 f1403d65c32877d9eaa06f1f50cf2c2c0d5b130c Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Thu, 17 Jul 2025 11:30:20 +0200 Subject: [PATCH 17/31] Fix documentation build. --- llvm/docs/SPIRVUsage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 3f6fa241da8ac..d5b6df818d29c 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -587,7 +587,7 @@ group-based instructions. These builtins facilitate group synchronization, data and collective operations essential for efficient parallel computation. SPIR-V Instructions Mapped to LLVM Metadata -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some SPIR-V instructions don't have a direct equivalent in the LLVM IR language. To address this, the SPIR-V Target uses different specific LLVM named metadata to convey the necessary information. The SPIR-V specification allows multiple module-scope From 37a3abeb1d648b98232cab7e5263abb69f77b69c Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Thu, 17 Jul 2025 11:37:38 +0200 Subject: [PATCH 18/31] Fix another error in documentation build. --- llvm/docs/SPIRVUsage.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index d5b6df818d29c..9567c65f0c4ad 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -602,14 +602,13 @@ such instructions has the following format: Below, you will find the mappings between SPIR-V instruction and their corresponding LLVM IR representations. - +--------------------+---------------------------------------------------------+ | SPIR-V instruction | LLVM IR | +====================+=========================================================+ | OpExecutionMode | .. code-block:: llvm | | | | | | !spirv.ExecutionMode = !{!0} | -| | !0 = !{void @worker, i32 30, i32 262149} | +| | !0 = !{void @worker, i32 30, i32 262149} | | | ; Set execution mode with id 30 (VecTypeHint) and | | | ; literal `262149` operand. | +--------------------+---------------------------------------------------------+ From d76db3e2e31e0f1c975d888d595483f0a0a8d640 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Fri, 1 Aug 2025 14:48:07 +0200 Subject: [PATCH 19/31] Ignore spirv.Decorations metadata related to FP flags. --- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 41 +++++-------------- .../SPV_KHR_float_controls2/decoration.ll | 26 ++++-------- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index ca3cb720d7a4d..3fbcd63a1a40f 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -197,23 +197,18 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, report_fatal_error("Expect SPIR-V operand to be the first " "element of the decoration"); - // 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) && + // The goal of `spirv.Decorations` metadata is to provide a way to + // represent SPIR-V entities that do not map to LLVM in an obvious way. + // FP flags do have obvious matches between LLVM IR and SPIR-V. + // Additionally, we have no guarantee at this point that the flags passed + // through the decoration are not violated already in the optimizer passes. + // Therefore, we simply ignore FP flags, including NoContraction, and + // FPFastMathMode. + if (DecorationId->getZExtValue() == + static_cast(SPIRV::Decoration::NoContraction) || DecorationId->getZExtValue() == - static_cast(SPIRV::Decoration::NoContraction)) { - NoContractionFound = true; - continue; // NoContraction is handled separately. - } else if (DecorationId->getZExtValue() == - static_cast(SPIRV::Decoration::FPFastMathMode)) { - FPFastMathModeFound = true; - FPFastMathFlags = mdconst::dyn_extract(OpMD->getOperand(1)) - ->getZExtValue(); - continue; // FPFastMathMode is handled separately. + static_cast(SPIRV::Decoration::FPFastMathMode)) { + continue; // Ignored. } auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) .addUse(Reg) @@ -228,20 +223,6 @@ void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, report_fatal_error("Unexpected operand of the decoration"); } } - // If we have NoContraction decoration, we should set the - // 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 || FPFastMathModeFound) { - MIRBuilder.buildInstr(SPIRV::OpDecorate) - .addUse(Reg) - .addImm(static_cast(SPIRV::Decoration::FPFastMathMode)) - .addImm(FPFastMathFlags); - } } MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I) { 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 index 8a80a8369a1e8..2cd3664d522ee 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll @@ -1,7 +1,7 @@ ; 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-DAG: Capability FloatControls2 ; CHECK: Extension "SPV_KHR_float_controls2" ; CHECK: OpName %[[#addRes:]] "addRes" @@ -33,22 +33,14 @@ ; 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 +; CHECK: OpDecorate %[[#oltRes]] FPFastMathMode NotNaN +; CHECK: OpDecorate %[[#ogtRes]] FPFastMathMode NotInf +; CHECK: OpDecorate %[[#oleRes]] FPFastMathMode NSZ +; CHECK: OpDecorate %[[#ogeRes]] FPFastMathMode AllowRecip +; CHECK: OpDecorate %[[#ordRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#ueqRes]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#maxRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#maxCommonRes:]] FPFastMathMode NotNaN|NotInf ; Function Attrs: convergent mustprogress nofree nounwind willreturn memory(none) declare spir_func float @_Z4fmodff(float, float) From f2aefbf502e6a48a5f8b251bdfbeb7ed8d412041 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Fri, 8 Aug 2025 13:12:59 +0200 Subject: [PATCH 20/31] Address code review feedback. --- llvm/docs/SPIRVUsage.rst | 1 + llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 5 +- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 113 +++++++++--------- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 8 +- .../SPV_KHR_float_controls2/decoration.ll | 66 +++++++++- .../SPV_KHR_float_controls2/exec_mode.ll | 16 +-- .../SPV_KHR_float_controls2/exec_mode2.ll | 53 +++++--- .../SPV_KHR_float_controls2/exec_mode3.ll | 100 ++++++++++++++++ 8 files changed, 272 insertions(+), 90 deletions(-) create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 7baceff1626c9..b6cd4b4feb46b 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -606,6 +606,7 @@ such instructions has the following format: Below, you will find the mappings between SPIR-V instruction and their corresponding LLVM IR representations. + +--------------------+---------------------------------------------------------+ | SPIR-V instruction | LLVM IR | +====================+=========================================================+ diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index e97ba48f219d9..74d99c6314366 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -713,10 +713,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { if (FPFastMathDefaultInfo.FPFastMathDefault) 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; + "NotNaN/NotInf/NSZ is enabled."); } // Don't emit if none of the execution modes was used. diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 7c1b4bce0a4e6..a390c5cbeb9e7 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -2100,12 +2100,11 @@ static unsigned getFastMathFlags(const MachineInstr &I, // Error out if AllowTransform is enabled without AllowReassoc and // AllowContract. - assert( - !(Flags & SPIRV::FPFastMathMode::AllowTransform) || - ((Flags & SPIRV::FPFastMathMode::AllowReassoc && - Flags & SPIRV::FPFastMathMode::AllowContract)) && - "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and " - "AllowContract flags to be enabled as well."); + assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) || + ((Flags & SPIRV::FPFastMathMode::AllowReassoc && + Flags & SPIRV::FPFastMathMode::AllowContract))) && + "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and " + "AllowContract flags to be enabled as well."); } return Flags; @@ -2168,6 +2167,7 @@ static void handleMIFlagDecoration( : I.getOperand(2).getReg(); SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResReg, I.getMF()); const Type *Ty = GR->getTypeForSPIRVType(ResType); + Ty = Ty->isVectorTy() ? cast(Ty)->getElementType() : Ty; // Match instruction type with the FPFastMathDefaultInfoVec. bool Emit = false; @@ -2295,59 +2295,60 @@ static void collectFPFastMathDefaults(const Module &M, // 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(Node->getOperand(i)); - assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands"); - const Function *F = cast( - cast(MDN->getOperand(0))->getValue()); - const auto EM = + if (!Node) + return; + + for (unsigned i = 0; i < Node->getNumOperands(); i++) { + MDNode *MDN = cast(Node->getOperand(i)); + assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands"); + const Function *F = cast( + cast(MDN->getOperand(0))->getValue()); + const auto EM = + cast( + cast(MDN->getOperand(1))->getValue()) + ->getZExtValue(); + if (EM == SPIRV::ExecutionMode::FPFastMathDefault) { + assert(MDN->getNumOperands() == 4 && + "Expected 4 operands for FPFastMathDefault"); + + const Type *T = cast(MDN->getOperand(2))->getType(); + unsigned Flags = cast( - cast(MDN->getOperand(1))->getValue()) + cast(MDN->getOperand(3))->getValue()) ->getZExtValue(); - if (EM == SPIRV::ExecutionMode::FPFastMathDefault) { - assert(MDN->getNumOperands() == 4 && - "Expected 4 operands for FPFastMathDefault"); - - const Type *T = cast(MDN->getOperand(2))->getType(); - unsigned Flags = - cast( - cast(MDN->getOperand(3))->getValue()) - ->getZExtValue(); - SmallVector &FPFastMathDefaultInfoVec = - getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); - 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"); - - // We need to save this info for every possible FP type, i.e. {half, - // float, double, fp128}. - SmallVector &FPFastMathDefaultInfoVec = - getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); - for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { - Info.ContractionOff = true; - } - } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) { - assert(MDN->getNumOperands() == 3 && - "Expected 1 operand for SignedZeroInfNanPreserve"); - unsigned TargetWidth = - cast( - cast(MDN->getOperand(2))->getValue()) - ->getZExtValue(); - // We need to save this info only for the FP type with TargetWidth. - SmallVector &FPFastMathDefaultInfoVec = - getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); - int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth); - assert(Index >= 0 && Index < 3 && - "Expected FPFastMathDefaultInfo for half, float, or double"); - assert(FPFastMathDefaultInfoVec.size() == 3 && - "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); - FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true; + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); + 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"); + + // We need to save this info for every possible FP type, i.e. {half, + // float, double, fp128}. + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); + for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { + Info.ContractionOff = true; } + } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) { + assert(MDN->getNumOperands() == 3 && + "Expected 1 operand for SignedZeroInfNanPreserve"); + unsigned TargetWidth = + cast( + cast(MDN->getOperand(2))->getValue()) + ->getZExtValue(); + // We need to save this info only for the FP type with TargetWidth. + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); + int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth); + assert(Index >= 0 && Index < 3 && + "Expected FPFastMathDefaultInfo for half, float, or double"); + assert(FPFastMathDefaultInfoVec.size() == 3 && + "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); + FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true; } } } diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index 0a965e2ff0631..e85cef3925689 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -182,9 +182,6 @@ void buildOpMemberDecorate(Register Reg, MachineInstr &I, void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD, const SPIRVSubtarget &ST) { - bool NoContractionFound = false; - bool FPFastMathModeFound = false; - unsigned FPFastMathFlags = SPIRV::FPFastMathMode::None; for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) { auto *OpMD = dyn_cast(GVarMD->getOperand(I)); if (!OpMD) @@ -1023,9 +1020,7 @@ size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth) { default: report_fatal_error("Expected BitWidth to be 16, 32, 64", false); } - assert(false && "Unreachable code"); - // This return is just to avoid compiler warnings. - return 0; + llvm_unreachable("Unreachable code in computeFPFastMathDefaultInfoVecIndex"); } MachineBasicBlock::iterator @@ -1052,3 +1047,4 @@ getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) { } } // namespace llvm + 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 index 2cd3664d522ee..ddade804f8f78 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll @@ -27,6 +27,29 @@ ; CHECK: OpName %[[#modRes:]] "modRes" ; CHECK: OpName %[[#maxRes:]] "maxRes" ; CHECK: OpName %[[#maxCommonRes:]] "maxCommonRes" +; CHECK: OpName %[[#addResV:]] "addResV" +; CHECK: OpName %[[#subResV:]] "subResV" +; CHECK: OpName %[[#mulResV:]] "mulResV" +; CHECK: OpName %[[#divResV:]] "divResV" +; CHECK: OpName %[[#remResV:]] "remResV" +; CHECK: OpName %[[#negResV:]] "negResV" +; CHECK: OpName %[[#oeqResV:]] "oeqResV" +; CHECK: OpName %[[#oneResV:]] "oneResV" +; CHECK: OpName %[[#oltResV:]] "oltResV" +; CHECK: OpName %[[#ogtResV:]] "ogtResV" +; CHECK: OpName %[[#oleResV:]] "oleResV" +; CHECK: OpName %[[#ogeResV:]] "ogeResV" +; CHECK: OpName %[[#ordResV:]] "ordResV" +; CHECK: OpName %[[#ueqResV:]] "ueqResV" +; CHECK: OpName %[[#uneResV:]] "uneResV" +; CHECK: OpName %[[#ultResV:]] "ultResV" +; CHECK: OpName %[[#ugtResV:]] "ugtResV" +; CHECK: OpName %[[#uleResV:]] "uleResV" +; CHECK: OpName %[[#ugeResV:]] "ugeResV" +; CHECK: OpName %[[#unoResV:]] "unoResV" +; CHECK: OpName %[[#modResV:]] "modResV" +; CHECK: OpName %[[#maxResV:]] "maxResV" +; CHECK: OpName %[[#maxCommonResV:]] "maxCommonResV" ; CHECK: OpDecorate %[[#subRes]] FPFastMathMode NotNaN ; CHECK: OpDecorate %[[#mulRes]] FPFastMathMode NotInf ; CHECK: OpDecorate %[[#divRes]] FPFastMathMode NSZ @@ -40,7 +63,21 @@ ; CHECK: OpDecorate %[[#ordRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform ; CHECK: OpDecorate %[[#ueqRes]] FPFastMathMode NotNaN|NotInf ; CHECK: OpDecorate %[[#maxRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform -; CHECK: OpDecorate %[[#maxCommonRes:]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#maxCommonRes]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#subResV]] FPFastMathMode NotNaN +; CHECK: OpDecorate %[[#mulResV]] FPFastMathMode NotInf +; CHECK: OpDecorate %[[#divResV]] FPFastMathMode NSZ +; CHECK: OpDecorate %[[#remResV]] FPFastMathMode AllowRecip +; CHECK: OpDecorate %[[#negResV]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#oeqResV]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#oltResV]] FPFastMathMode NotNaN +; CHECK: OpDecorate %[[#ogtResV]] FPFastMathMode NotInf +; CHECK: OpDecorate %[[#oleResV]] FPFastMathMode NSZ +; CHECK: OpDecorate %[[#ogeResV]] FPFastMathMode AllowRecip +; CHECK: OpDecorate %[[#ordResV]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#ueqResV]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#maxResV]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#maxCommonResV]] FPFastMathMode NotNaN|NotInf ; Function Attrs: convergent mustprogress nofree nounwind willreturn memory(none) declare spir_func float @_Z4fmodff(float, float) @@ -76,6 +113,33 @@ entry: ret void } +define weak_odr dso_local spir_kernel void @fooV(<2 x float> %v1, <2 x float> %v2) { + %addResV = fadd <2 x float> %v1, %v2 + %subResV = fsub nnan <2 x float> %v1, %v2 + %mulResV = fmul ninf <2 x float> %v1, %v2 + %divResV = fdiv nsz <2 x float> %v1, %v2 + %remResV = frem arcp <2 x float> %v1, %v2 + %negResV = fneg fast <2 x float> %v1 + %oeqResV = fcmp nnan ninf oeq <2 x float> %v1, %v2 + %oneResV = fcmp one <2 x float> %v1, %v2, !spirv.Decorations !3 + %oltResV = fcmp nnan olt <2 x float> %v1, %v2, !spirv.Decorations !3 + %ogtResV = fcmp ninf ogt <2 x float> %v1, %v2, !spirv.Decorations !3 + %oleResV = fcmp nsz ole <2 x float> %v1, %v2, !spirv.Decorations !3 + %ogeResV = fcmp arcp oge <2 x float> %v1, %v2, !spirv.Decorations !3 + %ordResV = fcmp fast ord <2 x float> %v1, %v2, !spirv.Decorations !3 + %ueqResV = fcmp nnan ninf ueq <2 x float> %v1, %v2, !spirv.Decorations !3 + %uneResV = fcmp une <2 x float> %v1, %v2, !spirv.Decorations !3 + %ultResV = fcmp ult <2 x float> %v1, %v2, !spirv.Decorations !3 + %ugtResV = fcmp ugt <2 x float> %v1, %v2, !spirv.Decorations !3 + %uleResV = fcmp ule <2 x float> %v1, %v2, !spirv.Decorations !3 + %ugeResV = fcmp uge <2 x float> %v1, %v2, !spirv.Decorations !3 + %unoResV = fcmp uno <2 x float> %v1, %v2, !spirv.Decorations !3 + %modResV = call spir_func <2 x float> @_Z4fmodff(<2 x float> %v1, <2 x float> %v2) + %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + ret void +} + !3 = !{!5, !4} !4 = !{i32 42} ; 42 is NoContraction decoration !5 = !{i32 40, i32 393216} ; 40 is FPFastMathMode 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 index a02459cac6a06..d4f975d83e607 100644 --- 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 @@ -1,7 +1,7 @@ ; 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-DAG: Capability FloatControls2 ; CHECK: Extension "SPV_KHR_float_controls2" define dso_local dllexport spir_kernel void @k_float_controls_half(half %h) { @@ -49,21 +49,21 @@ entry: !7 = !{i32 32, i32 36} !8 = !{i32 0, i32 0} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_HALF]] FPFastMathDefault %[[#HALF_TYPE:]] 1 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_HALF]] FPFastMathDefault %[[#HALF_TYPE:]] 1 !17 = !{ptr @k_float_controls_half, i32 6028, half poison, i32 1} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] 2 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] 2 !18 = !{ptr @k_float_controls_bfloat, i32 6028, bfloat poison, i32 2} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 4 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 4 !19 = !{ptr @k_float_controls_float, i32 6028, float poison, i32 4} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 !20 = !{ptr @k_float_controls_double, i32 6028, double poison, i32 7} -; 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 %[[#HALF_TYPE]] 131072 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE]] 262144 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE]] 458752 !22 = !{ptr @k_float_controls_all, i32 6028, half poison, i32 131072} !23 = !{ptr @k_float_controls_all, i32 6028, bfloat poison, i32 131072} !24 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 262144} 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 index b65c18db56208..3014bafc8019f 100644 --- 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 @@ -1,9 +1,14 @@ ; 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-DAG: Capability FloatControls2 ; CHECK: Extension "SPV_KHR_float_controls2" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_FLOAT:]] "k_float_controls_float" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL:]] "k_float_controls_all" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_FLOAT_V:]] "k_float_controls_float_v" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL_V:]] "k_float_controls_all_v" + define dso_local dllexport spir_kernel void @k_float_controls_float(float %f) { entry: ret void @@ -14,34 +19,52 @@ entry: ret void } -!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26} +define dso_local dllexport spir_kernel void @k_float_controls_float_v(<2 x float> %f) { +entry: + ret void +} -; 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} +define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x bfloat> %b, <2 x float> %f, <2 x double> %d) { +entry: + ret void +} -!6 = !{i32 2, i32 2} -!7 = !{i32 32, i32 36} -!8 = !{i32 0, i32 0} +!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 !19 = !{ptr @k_float_controls_float, i32 6028, float poison, 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 %[[#FLOAT_TYPE:]] 131079 +; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] 0 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 !20 = !{ptr @k_float_controls_all, i32 6028, float poison, 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. +; SignedZeroInfNanPreserve is now replaced with FPFastMathDefault with flags 0. !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} +; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +!27 = !{ptr @k_float_controls_float_v, i32 6028, float poison, i32 131079} +; We expect 130179 for float type. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] 0 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 +!28 = !{ptr @k_float_controls_all_v, i32 6028, float poison, i32 131079} +; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false. +!29 = !{ptr @k_float_controls_float_v, i32 31} +!30 = !{ptr @k_float_controls_all_v, i32 31} +; SignedZeroInfNanPreserve is now replaced with FPFastMathDefault with flags 0. +!31 = !{ptr @k_float_controls_float_v, i32 4461, i32 32} +!32 = !{ptr @k_float_controls_all_v, i32 4461, i32 16} +!33 = !{ptr @k_float_controls_all_v, i32 4461, i32 32} +!34 = !{ptr @k_float_controls_all_v, i32 4461, i32 64} + ; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16 ; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32 ; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll new file mode 100644 index 0000000000000..3b4a443bace77 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll @@ -0,0 +1,100 @@ +; 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: OpEntryPoint Kernel %[[#KERNEL_FLOAT:]] "k_float_controls_float" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL:]] "k_float_controls_all" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_FLOAT_V:]] "k_float_controls_float_v" +; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL_V:]] "k_float_controls_all_v" + +; We expect 130179 for float type. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] 0 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 + +; We expect 130179 for float type. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] 0 +; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 + +; CHECK-DAG: OpDecorate %[[#addRes:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc +; CHECK-DAG: OpDecorate %[[#addResH:]] FPFastMathMode None +; CHECK-DAG: OpDecorate %[[#addResF:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc +; CHECK-DAG: OpDecorate %[[#addResD:]] FPFastMathMode None +; CHECK-DAG: OpDecorate %[[#addRes_V:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc +; CHECK-DAG: OpDecorate %[[#addResH_V:]] FPFastMathMode None +; CHECK-DAG: OpDecorate %[[#addResF_V:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc +; CHECK-DAG: OpDecorate %[[#addResD_V:]] FPFastMathMode None + +; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16 +; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32 +; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 + +; CHECK-DAG: %[[#HALF_V_TYPE:]] = OpTypeVector %[[#HALF_TYPE]] +; CHECK-DAG: %[[#FLOAT_V_TYPE:]] = OpTypeVector %[[#FLOAT_TYPE]] +; CHECK-DAG: %[[#DOUBLE_V_TYPE:]] = OpTypeVector %[[#DOUBLE_TYPE]] + +define dso_local dllexport spir_kernel void @k_float_controls_float(float %f) { +entry: +; CHECK-DAG: %[[#addRes]] = OpFAdd %[[#FLOAT_TYPE]] + %addRes = fadd float %f, %f + ret void +} + +define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d) { +entry: +; CHECK-DAG: %[[#addResH]] = OpFAdd %[[#HALF_TYPE]] +; CHECK-DAG: %[[#addResF]] = OpFAdd %[[#FLOAT_TYPE]] +; CHECK-DAG: %[[#addResD]] = OpFAdd %[[#DOUBLE_TYPE]] + %addResH = fadd half %h, %h + %addResF = fadd float %f, %f + %addResD = fadd double %d, %d + ret void +} + +define dso_local dllexport spir_kernel void @k_float_controls_float_v(<2 x float> %f) { +entry: +; CHECK-DAG: %[[#addRes_V]] = OpFAdd %[[#FLOAT_V_TYPE]] + %addRes = fadd <2 x float> %f, %f + ret void +} + +define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x bfloat> %b, <2 x float> %f, <2 x double> %d) { +entry: +; CHECK-DAG: %[[#addResH_V]] = OpFAdd %[[#HALF_V_TYPE]] +; CHECK-DAG: %[[#addResF_V]] = OpFAdd %[[#FLOAT_V_TYPE]] +; CHECK-DAG: %[[#addResD_V]] = OpFAdd %[[#DOUBLE_V_TYPE]] + %addResH = fadd <2 x half> %h, %h + %addResF = fadd <2 x float> %f, %f + %addResD = fadd <2 x double> %d, %d + ret void +} + +!spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34} + +!19 = !{ptr @k_float_controls_float, i32 6028, float poison, i32 131079} +!20 = !{ptr @k_float_controls_all, i32 6028, float poison, 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 0. +!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_float_v, i32 6028, float poison, i32 131079} +!28 = !{ptr @k_float_controls_all_v, i32 6028, float poison, i32 131079} +; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false. +!29 = !{ptr @k_float_controls_float_v, i32 31} +!30 = !{ptr @k_float_controls_all_v, i32 31} +; SignedZeroInfNanPreserve is now replaced with FPFastMathDefault with flags 0. +!31 = !{ptr @k_float_controls_float_v, i32 4461, i32 32} +!32 = !{ptr @k_float_controls_all_v, i32 4461, i32 16} +!33 = !{ptr @k_float_controls_all_v, i32 4461, i32 32} +!34 = !{ptr @k_float_controls_all_v, i32 4461, i32 64} From 848611acb1917b292c890990c7ca44b172aec8be Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Fri, 8 Aug 2025 14:21:06 +0200 Subject: [PATCH 21/31] Fix clang-format. --- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index 8579fcc563e6f..e0dc9440bbe59 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -1049,4 +1049,3 @@ getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) { } } // namespace llvm - From bde02921aa06c33898858d22e0574229033c3d5b Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 26 Aug 2025 11:53:59 +0200 Subject: [PATCH 22/31] Address reviewer feedback. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 3 +- .../SPV_KHR_float_controls2/replacements.ll | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index 901d9aa999269..ea278a4df87e6 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -704,8 +704,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { Inst.addOperand(MCOperand::createReg(TypeReg)); unsigned Flags = FPFastMathDefaultInfo.FastMathFlags; if (FPFastMathDefaultInfo.ContractionOff && - (Flags & SPIRV::FPFastMathMode::AllowContract) && - FPFastMathDefaultInfo.FPFastMathDefault) + (Flags & SPIRV::FPFastMathMode::AllowContract)) report_fatal_error( "Conflicting FPFastMathFlags: ContractionOff and AllowContract"); diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll new file mode 100644 index 0000000000000..3ed79e05f5573 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll @@ -0,0 +1,57 @@ +; 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 %} + +;; This test checks that the OpenCL.std instructions fmin_common, fmax_common are replaced with fmin, fmax with NInf and NNaN instead. + +; CHECK-DAG: Capability FloatControls2 +; CHECK: Extension "SPV_KHR_float_controls2" + +; CHECK: OpName %[[#maxRes:]] "maxRes" +; CHECK: OpName %[[#maxCommonRes:]] "maxCommonRes" +; CHECK: OpName %[[#minRes:]] "minRes" +; CHECK: OpName %[[#minCommonRes:]] "minCommonRes" +; CHECK: OpName %[[#maxResV:]] "maxResV" +; CHECK: OpName %[[#maxCommonResV:]] "maxCommonResV" +; CHECK: OpName %[[#minResV:]] "minResV" +; CHECK: OpName %[[#minCommonResV:]] "minCommonResV" +; CHECK: OpDecorate %[[#maxRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#maxCommonRes]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#minRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#minCommonRes]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#maxResV]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#maxCommonResV]] FPFastMathMode NotNaN|NotInf +; CHECK: OpDecorate %[[#minResV]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform +; CHECK: OpDecorate %[[#minCommonResV]] FPFastMathMode NotNaN|NotInf +; CHECK: %[[#maxRes]] = OpExtInst {{.*}} fmax +; CHECK: %[[#maxCommonRes]] = OpExtInst {{.*}} fmax +; CHECK: %[[#minRes]] = OpExtInst {{.*}} fmin +; CHECK: %[[#minCommonRes]] = OpExtInst {{.*}} fmin +; CHECK: %[[#maxResV]] = OpExtInst {{.*}} fmax +; CHECK: %[[#maxCommonResV]] = OpExtInst {{.*}} fmax +; CHECK: %[[#minResV]] = OpExtInst {{.*}} fmin +; CHECK: %[[#minCommonResV]] = OpExtInst {{.*}} fmin + +; 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 +declare dso_local spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fminff(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_fmin_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: + %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) + %minRes = tail call fast spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fminff(float noundef nofpclass(nan inf) %1, float noundef nofpclass(nan inf) %2) + %minCommonRes = tail call spir_func noundef float @_Z23__spirv_ocl_fmin_commonff(float noundef nofpclass(nan inf) %1, float noundef nofpclass(nan inf) %2) + ret void +} + +define weak_odr dso_local spir_kernel void @fooV(<2 x float> %v1, <2 x float> %v2) { + %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %minResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fminff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %minCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmin_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + ret void +} From 6420f435ace41d18f06b562338a519efcda68d73 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 15:54:37 +0200 Subject: [PATCH 23/31] Use constant instruction for flags. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 103 ++++++-- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 239 +++++++++++++++++- 2 files changed, 311 insertions(+), 31 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index ea278a4df87e6..d1727d938e0d8 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -574,23 +574,56 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) { // 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 that exists in the module - // to match the effect of ContractionOff. As of now, there are 4 FP + // to match the effect of ContractionOff. As of now, there are 3 FP // types: fp16, fp32 and fp64. + + // 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. Therefore, we need + // to find the constant with 0 value. + + // Collect the SPIRVTypes for fp16, fp32, and fp64 and the constant of + // type int32 with 0 value to represent the FP Fast Math Mode. + std::vector SPIRVFloatTypes; + const MachineInstr *ConstZero = nullptr; for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) { - // Skip if the instruction is not OpTypeFloat. - if (MI->getOpcode() != SPIRV::OpTypeFloat) + // Skip if the instruction is not OpTypeFloat or OpConstant. + unsigned OpCode = MI->getOpcode(); + if (OpCode != SPIRV::OpTypeFloat && OpCode != SPIRV::OpConstantNull) continue; - // Skip if the target type is not fp16, fp32, fp64. - const unsigned OpTypeFloatSize = MI->getOperand(1).getImm(); - if (OpTypeFloatSize != 16 && OpTypeFloatSize != 32 && - OpTypeFloatSize != 64) { - continue; + // Collect the SPIRV type if it's a float. + if (OpCode == SPIRV::OpTypeFloat) { + // Skip if the target type is not fp16, fp32, fp64. + const unsigned OpTypeFloatSize = MI->getOperand(1).getImm(); + if (OpTypeFloatSize != 16 && OpTypeFloatSize != 32 && + OpTypeFloatSize != 64) { + continue; + } + SPIRVFloatTypes.push_back(MI); + } else { + // Check if the constant is int32, if not skip it. + const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); + MachineInstr *TypeMI = MRI.getVRegDef(MI->getOperand(1).getReg()); + if (!TypeMI || TypeMI->getOperand(1).getImm() != 32) + continue; + + ConstZero = MI; } + } + // 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 that exists in the module + // to match the effect of ContractionOff. As of now, there are 3 FP + // types: fp16, fp32 and fp64. + for (const MachineInstr *MI : SPIRVFloatTypes) { MCInst Inst; - Inst.setOpcode(SPIRV::OpExecutionMode); + Inst.setOpcode(SPIRV::OpExecutionModeId); Inst.addOperand(MCOperand::createReg(FReg)); unsigned EM = static_cast(SPIRV::ExecutionMode::FPFastMathDefault); @@ -599,12 +632,10 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) { MCRegister TypeReg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg()); Inst.addOperand(MCOperand::createReg(TypeReg)); - // 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)); + assert(ConstZero && "There should be a constant zero."); + MCRegister ConstReg = MAI->getRegisterAlias( + ConstZero->getMF(), ConstZero->getOperand(0).getReg()); + Inst.addOperand(MCOperand::createReg(ConstReg)); outputMCInst(Inst); } } else { @@ -665,15 +696,34 @@ void SPIRVAsmPrinter::outputAnnotations(const Module &M) { } void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { - // Collect the SPIRVTypes that are OpTypeFloat. + SPIRVGlobalRegistry *GR = ST->getSPIRVGlobalRegistry(); + // Collect the SPIRVTypes that are OpTypeFloat and the constants of type + // int32, that might be used as FP Fast Math Mode. std::vector SPIRVFloatTypes; + // Hashtable to associate immediate values with the constant holding them. + std::unordered_map ConstMap; for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) { - // Skip if the instruction is not OpTypeFloat. - if (MI->getOpcode() != SPIRV::OpTypeFloat) + // Skip if the instruction is not OpTypeFloat or OpConstant. + unsigned OpCode = MI->getOpcode(); + if (OpCode != SPIRV::OpTypeFloat && OpCode != SPIRV::OpConstantI && + OpCode != SPIRV::OpConstantNull) continue; - // Collect the SPIRV type. - SPIRVFloatTypes.push_back(MI); + // Collect the SPIRV type if it's a float. + if (OpCode == SPIRV::OpTypeFloat) { + SPIRVFloatTypes.push_back(MI); + } else { + // Check if the constant is int32, if not skip it. + const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); + MachineInstr *TypeMI = MRI.getVRegDef(MI->getOperand(1).getReg()); + if (!TypeMI || TypeMI->getOperand(1).getImm() != 32) + continue; + + if (OpCode == SPIRV::OpConstantI) + ConstMap[MI->getOperand(2).getImm()] = MI; + else + ConstMap[0] = MI; + } } for (const auto &[Func, FPFastMathDefaultInfoVec] : @@ -693,7 +743,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { OpTypeFloatSize && "Mismatched float type size"); MCInst Inst; - Inst.setOpcode(SPIRV::OpExecutionMode); + Inst.setOpcode(SPIRV::OpExecutionModeId); MCRegister FuncReg = MAI->getFuncReg(Func); assert(FuncReg.isValid()); Inst.addOperand(MCOperand::createReg(FuncReg)); @@ -724,7 +774,16 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { !FPFastMathDefaultInfo.SignedZeroInfNanPreserve && !FPFastMathDefaultInfo.FPFastMathDefault) continue; - Inst.addOperand(MCOperand::createImm(Flags)); + + // Retrieve the constant instruction for the immediate value. + auto It = ConstMap.find(Flags); + if (It == ConstMap.end()) + report_fatal_error("Expected constant instruction for FP Fast Math " + "Mode operand of FPFastMathDefault execution mode."); + const MachineInstr *ConstMI = It->second; + MCRegister ConstReg = + MAI->getRegisterAlias(ConstMI->getMF(), ConstMI->getOperand(0).getReg()); + Inst.addOperand(MCOperand::createReg(ConstReg)); outputMCInst(Inst); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index f5a49e2b47363..86ba03c89183c 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/TypedPointerType.h" #include "llvm/Transforms/Utils/Local.h" +#include #include #include @@ -152,6 +153,7 @@ class SPIRVEmitIntrinsics void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B); bool shouldTryToAddMemAliasingDecoration(Instruction *Inst); void insertSpirvDecorations(Instruction *I, IRBuilder<> &B); + void insertFPFastMathDefault(Module &M); void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B); void processParamTypes(Function *F, IRBuilder<> &B); void processParamTypesByFunHeader(Function *F, IRBuilder<> &B); @@ -262,6 +264,33 @@ class SPIRVEmitIntrinsics } }; +struct FPFastMathDefaultInfo { + const Type *Ty = nullptr; + unsigned FastMathFlags = 0; + // 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 FPFastMathDefault = 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 && + ContractionOff == Other.ContractionOff && + SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve && + FPFastMathDefault == Other.FPFastMathDefault; + } +}; + bool isConvergenceIntrinsic(const Instruction *I) { const auto *II = dyn_cast(I); if (!II) @@ -2248,6 +2277,196 @@ void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I, } } +static SmallVector & +getOrCreateFPFastMathDefaultInfoVec( + const Module &M, + DenseMap> + &FPFastMathDefaultInfoMap, + Function *F) { + auto it = FPFastMathDefaultInfoMap.find(F); + if (it != FPFastMathDefaultInfoMap.end()) + return it->second; + + // If the map does not contain the entry, create a new one. Initialize it to + // contain all 3 elements sorted by bit width of target type: {half, float, + // double}. + SmallVector 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); + return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec); +} + +static FPFastMathDefaultInfo &getFPFastMathDefaultInfo( + SmallVector &FPFastMathDefaultInfoVec, + const Type *Ty) { + size_t BitWidth = Ty->getScalarSizeInBits(); + int Index = computeFPFastMathDefaultInfoVecIndex(BitWidth); + assert(Index >= 0 && Index < 3 && + "Expected FPFastMathDefaultInfo for half, float, or double"); + assert(FPFastMathDefaultInfoVec.size() == 3 && + "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); + return FPFastMathDefaultInfoVec[Index]; +} + +void SPIRVEmitIntrinsics::insertFPFastMathDefault(Module &M) { + const SPIRVSubtarget *ST = TM->getSubtargetImpl(); + 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. + // 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) { + if (!M.getNamedMetadata("opencl.enable.FP_CONTRACT")) { + // This requires emitting ContractionOff. However, because + // ContractionOff is now deprecated, we need to replace it with + // FPFastMathDefaultInfo with FP Fast Math Mode bitmask set to all 0. + // We need to create the constant for that. + + // Create constant instruction with the bitmask flags. + Constant *InitValue = + ConstantInt::get(Type::getInt32Ty(M.getContext()), 0); + // TODO: Reuse constant if there is one already with the required + // value. + [[maybe_unused]] GlobalVariable *GV = + new GlobalVariable(M, // Module + Type::getInt32Ty(M.getContext()), // Type + true, // isConstant + GlobalValue::InternalLinkage, // Linkage + InitValue // Initializer + ); + } + return; + } + + // 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} + // in the order of their bit widths. + DenseMap> + FPFastMathDefaultInfoMap; + + for (unsigned i = 0; i < Node->getNumOperands(); i++) { + MDNode *MDN = cast(Node->getOperand(i)); + assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands"); + Function *F = cast( + cast(MDN->getOperand(0))->getValue()); + const auto EM = + cast( + cast(MDN->getOperand(1))->getValue()) + ->getZExtValue(); + if (EM == SPIRV::ExecutionMode::FPFastMathDefault) { + assert(MDN->getNumOperands() == 4 && + "Expected 4 operands for FPFastMathDefault"); + const Type *T = cast(MDN->getOperand(2))->getType(); + unsigned Flags = + cast( + cast(MDN->getOperand(3))->getValue()) + ->getZExtValue(); + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); + 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"); + + // We need to save this info for every possible FP type, i.e. {half, + // float, double, fp128}. + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); + for (FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { + Info.ContractionOff = true; + } + } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) { + assert(MDN->getNumOperands() == 3 && + "Expected 1 operand for SignedZeroInfNanPreserve"); + unsigned TargetWidth = + cast( + cast(MDN->getOperand(2))->getValue()) + ->getZExtValue(); + // We need to save this info only for the FP type with TargetWidth. + SmallVector &FPFastMathDefaultInfoVec = + getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); + int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth); + assert(Index >= 0 && Index < 3 && + "Expected FPFastMathDefaultInfo for half, float, or double"); + assert(FPFastMathDefaultInfoVec.size() == 3 && + "Expected FPFastMathDefaultInfoVec to have exactly 3 elements"); + FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true; + } + } + + std::unordered_map GlobalVars; + for (auto &[Func, FPFastMathDefaultInfoVec] : FPFastMathDefaultInfoMap) { + if (FPFastMathDefaultInfoVec.empty()) + continue; + + for (const FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { + assert(Info.Ty && "Expected target type for FPFastMathDefaultInfo"); + // Skip if none of the execution modes was used. + unsigned Flags = Info.FastMathFlags; + if (Flags == SPIRV::FPFastMathMode::None && !Info.ContractionOff && + !Info.SignedZeroInfNanPreserve && !Info.FPFastMathDefault) + continue; + + // Check if flags are compatible. + if (Info.ContractionOff && (Flags & SPIRV::FPFastMathMode::AllowContract)) + report_fatal_error("Conflicting FPFastMathFlags: ContractionOff " + "and AllowContract"); + + if (Info.SignedZeroInfNanPreserve && + !(Flags & + (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf | + SPIRV::FPFastMathMode::NSZ))) { + if (Info.FPFastMathDefault) + report_fatal_error("Conflicting FPFastMathFlags: " + "SignedZeroInfNanPreserve but at least one of " + "NotNaN/NotInf/NSZ is enabled."); + } + + if ((Flags & SPIRV::FPFastMathMode::AllowTransform) && + !((Flags & SPIRV::FPFastMathMode::AllowReassoc) && + (Flags & SPIRV::FPFastMathMode::AllowContract))) { + report_fatal_error("Conflicting FPFastMathFlags: " + "AllowTransform requires AllowReassoc and " + "AllowContract to be set."); + } + + auto it = GlobalVars.find(Flags); + GlobalVariable *GV = nullptr; + if (it != GlobalVars.end()) { + // Reuse existing global variable. + GV = it->second; + } else { + // Create constant instruction with the bitmask flags. + Constant *InitValue = + ConstantInt::get(Type::getInt32Ty(M.getContext()), Flags); + // TODO: Reuse constant if there is one already with the required + // value. + GV = new GlobalVariable(M, // Module + Type::getInt32Ty(M.getContext()), // Type + true, // isConstant + GlobalValue::InternalLinkage, // Linkage + InitValue // Initializer + ); + GlobalVars[Flags] = GV; + } + } + } +} + void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I, IRBuilder<> &B) { auto *II = dyn_cast(I); @@ -2568,9 +2787,9 @@ GetElementPtrInst * SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) { // getelementptr [0 x T], P, 0 (zero), I -> getelementptr T, P, I. // If type is 0-length array and first index is 0 (zero), drop both the - // 0-length array type and the first index. This is a common pattern in the - // IR, e.g. when using a zero-length array as a placeholder for a flexible - // array such as unbound arrays. + // 0-length array type and the first index. This is a common pattern in + // the IR, e.g. when using a zero-length array as a placeholder for a + // flexible array such as unbound arrays. assert(GEP && "GEP is null"); Type *SrcTy = GEP->getSourceElementType(); SmallVector Indices(GEP->indices()); @@ -2632,8 +2851,9 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { processParamTypesByFunHeader(CurrF, B); - // StoreInst's operand type can be changed during the next transformations, - // so we need to store it in the set. Also store already transformed types. + // StoreInst's operand type can be changed during the next + // transformations, so we need to store it in the set. Also store already + // transformed types. for (auto &I : instructions(Func)) { StoreInst *SI = dyn_cast(&I); if (!SI) @@ -2680,8 +2900,8 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { for (auto &I : llvm::reverse(instructions(Func))) deduceOperandElementType(&I, &IncompleteRets); - // Pass forward for PHIs only, their operands are not preceed the instruction - // in meaning of `instructions(Func)`. + // Pass forward for PHIs only, their operands are not preceed the + // instruction in meaning of `instructions(Func)`. for (BasicBlock &BB : Func) for (PHINode &Phi : BB.phis()) if (isPointerTy(Phi.getType())) @@ -2691,8 +2911,8 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { TrackConstants = true; if (!I->getType()->isVoidTy() || isa(I)) setInsertPointAfterDef(B, I); - // Visitors return either the original/newly created instruction for further - // processing, nullptr otherwise. + // Visitors return either the original/newly created instruction for + // further processing, nullptr otherwise. I = visit(*I); if (!I) continue; @@ -2815,6 +3035,7 @@ bool SPIRVEmitIntrinsics::runOnModule(Module &M) { bool Changed = false; parseFunDeclarations(M); + insertFPFastMathDefault(M); TodoType.clear(); for (auto &F : M) From 0bf9ca6db0f17a21d2b2c408f264b35187bb1106 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 15:57:04 +0200 Subject: [PATCH 24/31] Enable spirv-val and update tests accordingly. --- .../SPV_KHR_float_controls2/decoration.ll | 11 ++++--- .../SPV_KHR_float_controls2/exec_mode.ll | 31 ++++++++++++------- .../SPV_KHR_float_controls2/exec_mode2.ll | 21 +++++++------ .../SPV_KHR_float_controls2/exec_mode3.ll | 21 +++++++------ .../SPV_KHR_float_controls2/replacements.ll | 14 ++++++--- 5 files changed, 59 insertions(+), 39 deletions(-) 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 index ddade804f8f78..d3fe9e43450cd 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/decoration.ll @@ -1,5 +1,5 @@ ; 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 %} +; RUN: %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" @@ -83,6 +83,9 @@ 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 +declare spir_func <2 x float> @_Z4fmodDv2_fDv2_f(<2 x float>, <2 x float>) +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x float> noundef nofpclass(nan inf)) local_unnamed_addr #1 +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z23__spirv_ocl_fmax_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x 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) { @@ -134,9 +137,9 @@ define weak_odr dso_local spir_kernel void @fooV(<2 x float> %v1, <2 x float> %v %uleResV = fcmp ule <2 x float> %v1, %v2, !spirv.Decorations !3 %ugeResV = fcmp uge <2 x float> %v1, %v2, !spirv.Decorations !3 %unoResV = fcmp uno <2 x float> %v1, %v2, !spirv.Decorations !3 - %modResV = call spir_func <2 x float> @_Z4fmodff(<2 x float> %v1, <2 x float> %v2) - %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) - %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %modResV = call spir_func <2 x float> @_Z4fmodDv2_fDv2_f(<2 x float> %v1, <2 x float> %v2) + %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) ret void } 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 index d4f975d83e607..303aef1873cac 100644 --- 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 @@ -1,5 +1,5 @@ ; 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 %} +; RUN: %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" @@ -49,26 +49,33 @@ entry: !7 = !{i32 32, i32 36} !8 = !{i32 0, i32 0} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_HALF]] FPFastMathDefault %[[#HALF_TYPE:]] 1 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_HALF]] FPFastMathDefault %[[#HALF_TYPE:]] %[[#CONST1:]] !17 = !{ptr @k_float_controls_half, i32 6028, half poison, i32 1} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] 2 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_BFLOAT]] FPFastMathDefault %[[#BFLOAT_TYPE:]] %[[#CONST2:]] !18 = !{ptr @k_float_controls_bfloat, i32 6028, bfloat poison, i32 2} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 4 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST4:]] !19 = !{ptr @k_float_controls_float, i32 6028, float poison, i32 4} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 7 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_DOUBLE]] FPFastMathDefault %[[#DOUBLE_TYPE:]] %[[#CONST7:]] !20 = !{ptr @k_float_controls_double, i32 6028, double poison, i32 7} -; 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: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE]] %[[#CONST131072:]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE]] %[[#CONST458752:]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE]] %[[#CONST458752:]] !22 = !{ptr @k_float_controls_all, i32 6028, half poison, i32 131072} !23 = !{ptr @k_float_controls_all, i32 6028, bfloat poison, i32 131072} -!24 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 262144} +!24 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 458752} !25 = !{ptr @k_float_controls_all, i32 6028, double poison, i32 458752} -; CHECK: %[[#HALF_TYPE]] = OpTypeFloat 16 -; CHECK: %[[#FLOAT_TYPE]] = OpTypeFloat 32 -; CHECK: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 +; CHECK-DAG: %[[#INT32_TYPE:]] = OpTypeInt 32 0 +; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16 +; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32 +; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 +; CHECK-DAG: %[[#CONST1]] = OpConstant %[[#INT32_TYPE]] 1 +; CHECK-DAG: %[[#CONST2]] = OpConstant %[[#INT32_TYPE]] 2 +; CHECK-DAG: %[[#CONST4]] = OpConstant %[[#INT32_TYPE]] 4 +; CHECK-DAG: %[[#CONST7]] = OpConstant %[[#INT32_TYPE]] 7 +; CHECK-DAG: %[[#CONST131072]] = OpConstant %[[#INT32_TYPE]] 131072 +; CHECK-DAG: %[[#CONST458752]] = OpConstant %[[#INT32_TYPE]] 458752 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 index 3014bafc8019f..4bed484609393 100644 --- 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 @@ -1,5 +1,5 @@ ; 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 %} +; RUN: %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" @@ -31,13 +31,13 @@ entry: !spirv.ExecutionMode = !{!19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079:]] !19 = !{ptr @k_float_controls_float, i32 6028, float poison, i32 131079} ; We expect 130179 for float type. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] ; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] 0 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] %[[#CONST0:]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] %[[#CONST0]] !20 = !{ptr @k_float_controls_all, i32 6028, float poison, i32 131079} ; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false. !21 = !{ptr @k_float_controls_float, i32 31} @@ -48,13 +48,13 @@ entry: !25 = !{ptr @k_float_controls_all, i32 4461, i32 32} !26 = !{ptr @k_float_controls_all, i32 4461, i32 64} -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] !27 = !{ptr @k_float_controls_float_v, i32 6028, float poison, i32 131079} ; We expect 130179 for float type. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] ; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] 0 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] %[[#CONST0]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] %[[#CONST0]] !28 = !{ptr @k_float_controls_all_v, i32 6028, float poison, i32 131079} ; ContractionOff is now replaced with FPFastMathDefault with AllowContract bit set to false. !29 = !{ptr @k_float_controls_float_v, i32 31} @@ -65,6 +65,9 @@ entry: !33 = !{ptr @k_float_controls_all_v, i32 4461, i32 32} !34 = !{ptr @k_float_controls_all_v, i32 4461, i32 64} +; CHECK-DAG: %[[#INT32_TYPE:]] = OpTypeInt 32 0 ; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16 ; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32 ; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 +; CHECK-DAG: %[[#CONST0]] = OpConstantNull %[[#INT32_TYPE]] +; CHECK-DAG: %[[#CONST131079]] = OpConstant %[[#INT32_TYPE]] 131079 diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll index 3b4a443bace77..d635383729b1f 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll @@ -1,5 +1,5 @@ ; 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 %} +; RUN: %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" @@ -9,18 +9,18 @@ ; CHECK: OpEntryPoint Kernel %[[#KERNEL_ALL_V:]] "k_float_controls_all_v" ; We expect 130179 for float type. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_FLOAT]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079:]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] ; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] 0 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#HALF_TYPE:]] %[[#CONST0:]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL]] FPFastMathDefault %[[#DOUBLE_TYPE:]] %[[#CONST0]] ; We expect 130179 for float type. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] 131079 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_FLOAT_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#FLOAT_TYPE:]] %[[#CONST131079]] ; We expect 0 for the rest of types because it's SignedZeroInfNanPreserve. -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] 0 -; CHECK-DAG: OpExecutionMode %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] 0 +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#HALF_TYPE:]] %[[#CONST0]] +; CHECK-DAG: OpExecutionModeId %[[#KERNEL_ALL_V]] FPFastMathDefault %[[#DOUBLE_TYPE:]] %[[#CONST0]] ; CHECK-DAG: OpDecorate %[[#addRes:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc ; CHECK-DAG: OpDecorate %[[#addResH:]] FPFastMathMode None @@ -31,9 +31,12 @@ ; CHECK-DAG: OpDecorate %[[#addResF_V:]] FPFastMathMode NotNaN|NotInf|NSZ|AllowReassoc ; CHECK-DAG: OpDecorate %[[#addResD_V:]] FPFastMathMode None +; CHECK-DAG: %[[#INT32_TYPE:]] = OpTypeInt 32 0 ; CHECK-DAG: %[[#HALF_TYPE]] = OpTypeFloat 16 ; CHECK-DAG: %[[#FLOAT_TYPE]] = OpTypeFloat 32 ; CHECK-DAG: %[[#DOUBLE_TYPE]] = OpTypeFloat 64 +; CHECK-DAG: %[[#CONST0]] = OpConstantNull %[[#INT32_TYPE]] +; CHECK-DAG: %[[#CONST131079]] = OpConstant %[[#INT32_TYPE]] 131079 ; CHECK-DAG: %[[#HALF_V_TYPE:]] = OpTypeVector %[[#HALF_TYPE]] ; CHECK-DAG: %[[#FLOAT_V_TYPE:]] = OpTypeVector %[[#FLOAT_TYPE]] diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll index 3ed79e05f5573..bba1c93a7e78d 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/replacements.ll @@ -1,5 +1,5 @@ ; 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 %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %} ;; This test checks that the OpenCL.std instructions fmin_common, fmax_common are replaced with fmin, fmax with NInf and NNaN instead. @@ -37,6 +37,10 @@ declare dso_local spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fm 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 declare dso_local spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fminff(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_fmin_commonff(float noundef nofpclass(nan inf), float noundef nofpclass(nan inf)) local_unnamed_addr #1 +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x float> noundef nofpclass(nan inf)) local_unnamed_addr #1 +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z23__spirv_ocl_fmax_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x float> noundef nofpclass(nan inf)) local_unnamed_addr #1 +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fminDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x float> noundef nofpclass(nan inf)) local_unnamed_addr #1 +declare dso_local spir_func noundef nofpclass(nan inf) <2 x float> @_Z23__spirv_ocl_fmin_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf), <2 x 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) { @@ -49,9 +53,9 @@ entry: } define weak_odr dso_local spir_kernel void @fooV(<2 x float> %v1, <2 x float> %v2) { - %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) - %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) - %minResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fminff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) - %minCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmin_commonff(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %maxResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fmaxDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %maxCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmax_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %minResV = tail call fast spir_func noundef nofpclass(nan inf) <2 x float> @_Z16__spirv_ocl_fminDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) + %minCommonResV = tail call spir_func noundef <2 x float> @_Z23__spirv_ocl_fmin_commonDv2_fDv2_f(<2 x float> noundef nofpclass(nan inf) %v1, <2 x float> noundef nofpclass(nan inf) %v2) ret void } From cb1065eaf6ac94cd61ac9f9ab81c35f0289d65f2 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 16:14:45 +0200 Subject: [PATCH 25/31] Rename new function to better represent what it does. --- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 86ba03c89183c..de5b0952f5399 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -153,7 +153,7 @@ class SPIRVEmitIntrinsics void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B); bool shouldTryToAddMemAliasingDecoration(Instruction *Inst); void insertSpirvDecorations(Instruction *I, IRBuilder<> &B); - void insertFPFastMathDefault(Module &M); + void insertConstantsForFPFastMathDefault(Module &M); void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B); void processParamTypes(Function *F, IRBuilder<> &B); void processParamTypesByFunHeader(Function *F, IRBuilder<> &B); @@ -2312,7 +2312,7 @@ static FPFastMathDefaultInfo &getFPFastMathDefaultInfo( return FPFastMathDefaultInfoVec[Index]; } -void SPIRVEmitIntrinsics::insertFPFastMathDefault(Module &M) { +void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { const SPIRVSubtarget *ST = TM->getSubtargetImpl(); if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) return; From c19d29698c632e7982c7947e24f7ccd1dc7ee9fb Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 16:22:23 +0200 Subject: [PATCH 26/31] Fix clang-format issues. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 4 ++-- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index d1727d938e0d8..bb48f8b47fd3f 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -781,8 +781,8 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { report_fatal_error("Expected constant instruction for FP Fast Math " "Mode operand of FPFastMathDefault execution mode."); const MachineInstr *ConstMI = It->second; - MCRegister ConstReg = - MAI->getRegisterAlias(ConstMI->getMF(), ConstMI->getOperand(0).getReg()); + MCRegister ConstReg = MAI->getRegisterAlias( + ConstMI->getMF(), ConstMI->getOperand(0).getReg()); Inst.addOperand(MCOperand::createReg(ConstReg)); outputMCInst(Inst); } diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index de5b0952f5399..0bf389f0677db 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -2439,9 +2439,9 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { if ((Flags & SPIRV::FPFastMathMode::AllowTransform) && !((Flags & SPIRV::FPFastMathMode::AllowReassoc) && (Flags & SPIRV::FPFastMathMode::AllowContract))) { - report_fatal_error("Conflicting FPFastMathFlags: " - "AllowTransform requires AllowReassoc and " - "AllowContract to be set."); + report_fatal_error("Conflicting FPFastMathFlags: " + "AllowTransform requires AllowReassoc and " + "AllowContract to be set."); } auto it = GlobalVars.find(Flags); @@ -3035,7 +3035,7 @@ bool SPIRVEmitIntrinsics::runOnModule(Module &M) { bool Changed = false; parseFunDeclarations(M); - insertFPFastMathDefault(M); + insertConstantsForFPFastMathDefault(M); TodoType.clear(); for (auto &F : M) From b5ce97adb39874be2c84efbbe2a403d68a8245cd Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 16:34:27 +0200 Subject: [PATCH 27/31] Remove unused variable. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index bb48f8b47fd3f..efa77f70c3a54 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -696,7 +696,6 @@ void SPIRVAsmPrinter::outputAnnotations(const Module &M) { } void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { - SPIRVGlobalRegistry *GR = ST->getSPIRVGlobalRegistry(); // Collect the SPIRVTypes that are OpTypeFloat and the constants of type // int32, that might be used as FP Fast Math Mode. std::vector SPIRVFloatTypes; From c973c1a5961303823c8800bbe044ada029b7948c Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 2 Sep 2025 20:18:02 +0200 Subject: [PATCH 28/31] Fix test failure. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index efa77f70c3a54..79ba15904750a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -715,7 +715,8 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { // Check if the constant is int32, if not skip it. const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); MachineInstr *TypeMI = MRI.getVRegDef(MI->getOperand(1).getReg()); - if (!TypeMI || TypeMI->getOperand(1).getImm() != 32) + if (!TypeMI || TypeMI->getOpcode() != SPIRV::OpTypeInt || + TypeMI->getOperand(1).getImm() != 32) continue; if (OpCode == SPIRV::OpConstantI) From f684280d7354beec90bd84c5344911113a25140a Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Thu, 11 Sep 2025 11:19:29 +0200 Subject: [PATCH 29/31] Apply code review suggestions. --- llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp | 5 +- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 59 ++++++------------- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 25 ++++---- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h | 28 +-------- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 14 ----- llvm/lib/Target/SPIRV/SPIRVUtils.h | 50 +++++++++++++++- 6 files changed, 82 insertions(+), 99 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp index 79ba15904750a..b765fecbc8de3 100644 --- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -700,7 +700,7 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { // int32, that might be used as FP Fast Math Mode. std::vector SPIRVFloatTypes; // Hashtable to associate immediate values with the constant holding them. - std::unordered_map ConstMap; + std::unordered_map ConstMap; for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) { // Skip if the instruction is not OpTypeFloat or OpConstant. unsigned OpCode = MI->getOpcode(); @@ -733,7 +733,8 @@ void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() { for (const MachineInstr *MI : SPIRVFloatTypes) { unsigned OpTypeFloatSize = MI->getOperand(1).getImm(); - unsigned Index = computeFPFastMathDefaultInfoVecIndex(OpTypeFloatSize); + unsigned Index = SPIRV::FPFastMathDefaultInfoVector:: + computeFPFastMathDefaultInfoVecIndex(OpTypeFloatSize); assert(Index < FPFastMathDefaultInfoVec.size() && "Index out of bounds for FPFastMathDefaultInfoVec"); const auto &FPFastMathDefaultInfo = FPFastMathDefaultInfoVec[Index]; diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 0bf389f0677db..ddd50b39a849c 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -264,33 +264,6 @@ class SPIRVEmitIntrinsics } }; -struct FPFastMathDefaultInfo { - const Type *Ty = nullptr; - unsigned FastMathFlags = 0; - // 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 FPFastMathDefault = 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 && - ContractionOff == Other.ContractionOff && - SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve && - FPFastMathDefault == Other.FPFastMathDefault; - } -}; - bool isConvergenceIntrinsic(const Instruction *I) { const auto *II = dyn_cast(I); if (!II) @@ -2277,10 +2250,9 @@ void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I, } } -static SmallVector & -getOrCreateFPFastMathDefaultInfoVec( +static SPIRV::FPFastMathDefaultInfoVector &getOrCreateFPFastMathDefaultInfoVec( const Module &M, - DenseMap> + DenseMap &FPFastMathDefaultInfoMap, Function *F) { auto it = FPFastMathDefaultInfoMap.find(F); @@ -2290,7 +2262,7 @@ getOrCreateFPFastMathDefaultInfoVec( // If the map does not contain the entry, create a new one. Initialize it to // contain all 3 elements sorted by bit width of target type: {half, float, // double}. - SmallVector FPFastMathDefaultInfoVec; + SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec; FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()), SPIRV::FPFastMathMode::None); FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()), @@ -2300,11 +2272,13 @@ getOrCreateFPFastMathDefaultInfoVec( return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec); } -static FPFastMathDefaultInfo &getFPFastMathDefaultInfo( - SmallVector &FPFastMathDefaultInfoVec, +static SPIRV::FPFastMathDefaultInfo &getFPFastMathDefaultInfo( + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty) { size_t BitWidth = Ty->getScalarSizeInBits(); - int Index = computeFPFastMathDefaultInfoVecIndex(BitWidth); + int Index = + SPIRV::FPFastMathDefaultInfoVector::computeFPFastMathDefaultInfoVecIndex( + BitWidth); assert(Index >= 0 && Index < 3 && "Expected FPFastMathDefaultInfo for half, float, or double"); assert(FPFastMathDefaultInfoVec.size() == 3 && @@ -2352,7 +2326,7 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { // 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} // in the order of their bit widths. - DenseMap> + DenseMap FPFastMathDefaultInfoMap; for (unsigned i = 0; i < Node->getNumOperands(); i++) { @@ -2372,9 +2346,9 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { cast( cast(MDN->getOperand(3))->getValue()) ->getZExtValue(); - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); - FPFastMathDefaultInfo &Info = + SPIRV::FPFastMathDefaultInfo &Info = getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T); Info.FastMathFlags = Flags; Info.FPFastMathDefault = true; @@ -2384,9 +2358,9 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { // We need to save this info for every possible FP type, i.e. {half, // float, double, fp128}. - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); - for (FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { + for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { Info.ContractionOff = true; } } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) { @@ -2397,9 +2371,10 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { cast(MDN->getOperand(2))->getValue()) ->getZExtValue(); // We need to save this info only for the FP type with TargetWidth. - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F); - int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth); + int Index = SPIRV::FPFastMathDefaultInfoVector:: + computeFPFastMathDefaultInfoVecIndex(TargetWidth); assert(Index >= 0 && Index < 3 && "Expected FPFastMathDefaultInfo for half, float, or double"); assert(FPFastMathDefaultInfoVec.size() == 3 && @@ -2413,7 +2388,7 @@ void SPIRVEmitIntrinsics::insertConstantsForFPFastMathDefault(Module &M) { if (FPFastMathDefaultInfoVec.empty()) continue; - for (const FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { + for (const SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { assert(Info.Ty && "Expected target type for FPFastMathDefaultInfo"); // Skip if none of the execution modes was used. unsigned Flags = Info.FastMathFlags; diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 1d3bd1f667569..7ae46efcb6421 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -2139,7 +2139,7 @@ static bool isFastMathModeAvailable(const SPIRVSubtarget &ST) { static void handleMIFlagDecoration( MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII, SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR, - SmallVector &FPFastMathDefaultInfoVec) { + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) { if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) && getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, SPIRV::Decoration::NoSignedWrap, ST, Reqs) @@ -2267,10 +2267,8 @@ static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR, } } -static SmallVector & -getOrCreateFPFastMathDefaultInfoVec(const Module &M, - SPIRV::ModuleAnalysisInfo &MAI, - const Function *F) { +static SPIRV::FPFastMathDefaultInfoVector &getOrCreateFPFastMathDefaultInfoVec( + const Module &M, SPIRV::ModuleAnalysisInfo &MAI, const Function *F) { auto it = MAI.FPFastMathDefaultInfoMap.find(F); if (it != MAI.FPFastMathDefaultInfoMap.end()) return it->second; @@ -2278,7 +2276,7 @@ getOrCreateFPFastMathDefaultInfoVec(const Module &M, // If the map does not contain the entry, create a new one. Initialize it to // contain all 3 elements sorted by bit width of target type: {half, float, // double}. - SmallVector FPFastMathDefaultInfoVec; + SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec; FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()), SPIRV::FPFastMathMode::None); FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()), @@ -2289,10 +2287,12 @@ getOrCreateFPFastMathDefaultInfoVec(const Module &M, } static SPIRV::FPFastMathDefaultInfo &getFPFastMathDefaultInfo( - SmallVector &FPFastMathDefaultInfoVec, + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty) { size_t BitWidth = Ty->getScalarSizeInBits(); - int Index = computeFPFastMathDefaultInfoVecIndex(BitWidth); + int Index = + SPIRV::FPFastMathDefaultInfoVector::computeFPFastMathDefaultInfoVecIndex( + BitWidth); assert(Index >= 0 && Index < 3 && "Expected FPFastMathDefaultInfo for half, float, or double"); assert(FPFastMathDefaultInfoVec.size() == 3 && @@ -2334,7 +2334,7 @@ static void collectFPFastMathDefaults(const Module &M, cast( cast(MDN->getOperand(3))->getValue()) ->getZExtValue(); - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); SPIRV::FPFastMathDefaultInfo &Info = getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T); @@ -2346,7 +2346,7 @@ static void collectFPFastMathDefaults(const Module &M, // We need to save this info for every possible FP type, i.e. {half, // float, double, fp128}. - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) { Info.ContractionOff = true; @@ -2359,9 +2359,10 @@ static void collectFPFastMathDefaults(const Module &M, cast(MDN->getOperand(2))->getValue()) ->getZExtValue(); // We need to save this info only for the FP type with TargetWidth. - SmallVector &FPFastMathDefaultInfoVec = + SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec = getOrCreateFPFastMathDefaultInfoVec(M, MAI, F); - int Index = computeFPFastMathDefaultInfoVecIndex(TargetWidth); + int Index = SPIRV::FPFastMathDefaultInfoVector:: + computeFPFastMathDefaultInfoVecIndex(TargetWidth); assert(Index >= 0 && Index < 3 && "Expected FPFastMathDefaultInfo for half, float, or double"); assert(FPFastMathDefaultInfoVec.size() == 3 && diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h index 4fa840da05463..c4e39a044aeea 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h @@ -131,32 +131,6 @@ using LocalToGlobalRegTable = std::map; using RegisterAliasMapTy = std::map; -struct FPFastMathDefaultInfo { - const Type *Ty = nullptr; - unsigned FastMathFlags = 0; - // 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 FPFastMathDefault = 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 && - ContractionOff == Other.ContractionOff && - SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve && - FPFastMathDefault == Other.FPFastMathDefault; - } -}; // The struct contains results of the module analysis and methods // to access them. @@ -191,7 +165,7 @@ struct ModuleAnalysisInfo { // first element is the smallest bit width, and the last element is the // largest bit width, therefore, we will have {half, float, double} in // the order of their bit widths. - DenseMap> + DenseMap FPFastMathDefaultInfoMap; MCRegister getFuncReg(const Function *F) { diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index e0dc9440bbe59..327c011ea178f 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -1011,20 +1011,6 @@ 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; - default: - report_fatal_error("Expected BitWidth to be 16, 32, 64", false); - } - llvm_unreachable("Unreachable code in computeFPFastMathDefaultInfoVecIndex"); -} - MachineBasicBlock::iterator getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) { // Find the position to insert the OpVariable instruction. diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h index 735969f955a3f..409a0fd758a32 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.h +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h @@ -113,6 +113,54 @@ class PartialOrderingVisitor { std::function Op); }; +namespace SPIRV { +struct FPFastMathDefaultInfo { + const Type *Ty = nullptr; + unsigned FastMathFlags = 0; + // 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 FPFastMathDefault = 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 && + ContractionOff == Other.ContractionOff && + SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve && + FPFastMathDefault == Other.FPFastMathDefault; + } +}; + +struct FPFastMathDefaultInfoVector + : public SmallVector { + static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth) { + switch (BitWidth) { + case 16: // half + return 0; + case 32: // float + return 1; + case 64: // double + return 2; + default: + report_fatal_error("Expected BitWidth to be 16, 32, 64", false); + } + llvm_unreachable( + "Unreachable code in computeFPFastMathDefaultInfoVecIndex"); + } +}; + +} // namespace SPIRV + // Add the given string as a series of integer operand, inserting null // terminators and padding to make sure the operands all have 32-bit // little-endian words. @@ -508,7 +556,5 @@ unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, const MachineInstr *ResType); MachineBasicBlock::iterator getFirstValidInstructionInsertPoint(MachineBasicBlock &BB); - -size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth); } // namespace llvm #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H From f2af0d4a3deaa6f04a0c4537cae56dcbf45efa02 Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Thu, 11 Sep 2025 16:50:36 +0200 Subject: [PATCH 30/31] Fix clang-format issue. --- llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h index c4e39a044aeea..d8376cd1aeb5a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h @@ -131,7 +131,6 @@ using LocalToGlobalRegTable = std::map; using RegisterAliasMapTy = std::map; - // The struct contains results of the module analysis and methods // to access them. struct ModuleAnalysisInfo { From fe49f8b223cd23d65b01f12dbf9934a39d28b4bf Mon Sep 17 00:00:00 2001 From: Marcos Maronas Date: Tue, 30 Sep 2025 15:12:59 +0200 Subject: [PATCH 31/31] Address test failures caused by main branch merge. --- .../SPIRV/extensions/SPV_KHR_float_controls2/exec_mode.ll | 4 ++-- .../SPIRV/extensions/SPV_KHR_float_controls2/exec_mode2.ll | 4 ++-- .../SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) 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 index 303aef1873cac..4b3c13c260c51 100644 --- 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 @@ -1,5 +1,5 @@ -; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s -; 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-unknown --spirv-ext=+SPV_KHR_float_controls2,+SPV_KHR_bfloat16 %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2,+SPV_KHR_bfloat16 %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: Capability FloatControls2 ; CHECK: Extension "SPV_KHR_float_controls2" 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 index 4bed484609393..c0632725e38d9 100644 --- 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 @@ -14,7 +14,7 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d) { +define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, float %f, double %d) { entry: ret void } @@ -24,7 +24,7 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x bfloat> %b, <2 x float> %f, <2 x double> %d) { +define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x float> %f, <2 x double> %d) { entry: ret void } diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll index d635383729b1f..1d09187b7f6a1 100644 --- a/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_KHR_float_controls2/exec_mode3.ll @@ -49,7 +49,7 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, bfloat %b, float %f, double %d) { +define dso_local dllexport spir_kernel void @k_float_controls_all(half %h, float %f, double %d) { entry: ; CHECK-DAG: %[[#addResH]] = OpFAdd %[[#HALF_TYPE]] ; CHECK-DAG: %[[#addResF]] = OpFAdd %[[#FLOAT_TYPE]] @@ -67,7 +67,7 @@ entry: ret void } -define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x bfloat> %b, <2 x float> %f, <2 x double> %d) { +define dso_local dllexport spir_kernel void @k_float_controls_all_v(<2 x half> %h, <2 x float> %f, <2 x double> %d) { entry: ; CHECK-DAG: %[[#addResH_V]] = OpFAdd %[[#HALF_V_TYPE]] ; CHECK-DAG: %[[#addResF_V]] = OpFAdd %[[#FLOAT_V_TYPE]]