[llvm] [SPIR-V] Add saturation and float rounding mode decorations, a subset of arithmetic constrained floating-point intrinsics, and SPV_INTEL_float_controls2 extension (PR #119862)
Vyacheslav Levytskyy via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 13 12:31:30 PST 2024
https://github.com/VyacheslavLevytskyy updated https://github.com/llvm/llvm-project/pull/119862
>From 7d6a5d3f29864fc3cb3ff05a8ff8ff47251f22cf Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Thu, 12 Dec 2024 09:47:18 -0800
Subject: [PATCH 1/5] introduce SPV_INTEL_float_controls2; add arith
Constrained Floating-Point Intrinsics; add float rounding mode decoration
---
llvm/docs/SPIRVUsage.rst | 2 +
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 10 ++-
llvm/lib/Target/SPIRV/SPIRVBuiltins.h | 3 +-
llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp | 2 +
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 79 ++++++++++++++++-
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 11 +++
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 8 ++
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 25 +++++-
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 8 ++
.../exec_mode_float_control_empty.ll | 18 ++++
.../exec_mode_float_control_intel.ll | 74 ++++++++++++++++
.../SPIRV/instructions/integer-casts.ll | 8 ++
.../llvm-intrinsics/constrained-arithmetic.ll | 84 +++++++++++++++++++
13 files changed, 323 insertions(+), 9 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_empty.ll
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_intel.ll
create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 8f7ac71f8026b3..b7b3d21545168c 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -159,6 +159,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
- Adds instructions to convert between single-precision 32-bit floating-point values and 16-bit bfloat16 values.
* - ``SPV_INTEL_cache_controls``
- Allows cache control information to be applied to memory access instructions.
+ * - ``SPV_INTEL_float_controls2``
+ - Adds execution modes and decorations to control floating-point computations.
* - ``SPV_INTEL_function_pointers``
- Allows translation of function pointers.
* - ``SPV_INTEL_inline_assembly``
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index f4bfda4932b167..806eadffca6e72 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -173,7 +173,8 @@ using namespace InstructionSet;
namespace SPIRV {
/// Parses the name part of the demangled builtin call.
-std::string lookupBuiltinNameHelper(StringRef DemangledCall) {
+std::string lookupBuiltinNameHelper(StringRef DemangledCall,
+ std::string *Postfix) {
const static std::string PassPrefix = "(anonymous namespace)::";
std::string BuiltinName;
// Itanium Demangler result may have "(anonymous namespace)::" prefix
@@ -231,10 +232,13 @@ std::string lookupBuiltinNameHelper(StringRef DemangledCall) {
"ReadClockKHR|SubgroupBlockReadINTEL|SubgroupImageBlockReadINTEL|"
"SubgroupImageMediaBlockReadINTEL|SubgroupImageMediaBlockWriteINTEL|"
"Convert|"
- "UConvert|SConvert|FConvert|SatConvert).*)_R.*");
+ "UConvert|SConvert|FConvert|SatConvert).*)_R(.*)");
std::smatch Match;
- if (std::regex_match(BuiltinName, Match, SpvWithR) && Match.size() > 2)
+ if (std::regex_match(BuiltinName, Match, SpvWithR) && Match.size() > 3) {
BuiltinName = Match[1].str();
+ if (Postfix)
+ *Postfix = Match[3].str();
+ }
return BuiltinName;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
index 42b452db8b9fb4..0182d9652d18c9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
@@ -20,7 +20,8 @@
namespace llvm {
namespace SPIRV {
/// Parses the name part of the demangled builtin call.
-std::string lookupBuiltinNameHelper(StringRef DemangledCall);
+std::string lookupBuiltinNameHelper(StringRef DemangledCall,
+ std::string *Postfix = nullptr);
/// Lowers a builtin function call using the provided \p DemangledCall skeleton
/// and external instruction \p Set.
///
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index fb05c1fdbd1e3b..45b39c51164795 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -36,6 +36,8 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
{"SPV_INTEL_cache_controls",
SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
+ {"SPV_INTEL_float_controls2",
+ SPIRV::Extension::Extension::SPV_INTEL_float_controls2},
{"SPV_INTEL_global_variable_fpga_decorations",
SPIRV::Extension::Extension::
SPV_INTEL_global_variable_fpga_decorations},
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 2b623136e602e5..5ab38109000330 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -216,6 +216,8 @@ class SPIRVEmitIntrinsics
bool processFunctionPointers(Module &M);
void parseFunDeclarations(Module &M);
+ void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
+
public:
static char ID;
SPIRVEmitIntrinsics() : ModulePass(ID) {
@@ -1291,6 +1293,21 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
}
}
+static void createRoundingModeDecoration(Instruction *I,
+ unsigned RoundingModeDeco,
+ IRBuilder<> &B) {
+ LLVMContext &Ctx = I->getContext();
+ Type *Int32Ty = Type::getInt32Ty(Ctx);
+ SmallVector<Metadata *> MDs = {
+ MDNode::get(Ctx, ConstantAsMetadata::get(ConstantInt::get(
+ Int32Ty, SPIRV::Decoration::FPRoundingMode))),
+ MDNode::get(Ctx, ConstantAsMetadata::get(
+ ConstantInt::get(Int32Ty, RoundingModeDeco)))};
+ setInsertPointAfterDef(B, I);
+ B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
+ {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
+}
+
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
if (!Call.isInlineAsm())
return &Call;
@@ -1312,6 +1329,40 @@ Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
return &Call;
}
+// Use a tip about rounding mode to create a decoration.
+void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
+ IRBuilder<> &B) {
+ std::optional<RoundingMode> RM = FPI->getRoundingMode();
+ if (!RM.has_value())
+ return;
+ unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
+ switch (RM.value()) {
+ default:
+ // ignore unknown rounding modes
+ break;
+ case RoundingMode::NearestTiesToEven:
+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
+ break;
+ case RoundingMode::TowardNegative:
+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
+ break;
+ case RoundingMode::TowardPositive:
+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
+ break;
+ case RoundingMode::TowardZero:
+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
+ break;
+ case RoundingMode::Dynamic:
+ case RoundingMode::NearestTiesToAway:
+ // TODO: check if supported
+ break;
+ }
+ if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
+ return;
+ // Convert the tip about rounding mode into a decoration record.
+ createRoundingModeDecoration(FPI, RoundingModeDeco, B);
+}
+
Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
BasicBlock *ParentBB = I.getParent();
IRBuilder<> B(ParentBB);
@@ -1809,6 +1860,18 @@ bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
return true;
}
+static unsigned roundingModeMDToDecorationConst(StringRef S) {
+ if (S == "rte")
+ return SPIRV::FPRoundingMode::FPRoundingMode::RTE;
+ if (S == "rtz")
+ return SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
+ if (S == "rtp")
+ return SPIRV::FPRoundingMode::FPRoundingMode::RTP;
+ if (S == "rtn")
+ return SPIRV::FPRoundingMode::FPRoundingMode::RTN;
+ return std::numeric_limits<unsigned>::max();
+}
+
void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
IRBuilder<> &B) {
// TODO: extend the list of functions with known result types
@@ -1826,8 +1889,9 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
Function *CalledF = CI->getCalledFunction();
std::string DemangledName =
getOclOrSpirvBuiltinDemangledName(CalledF->getName());
+ std::string Postfix;
if (DemangledName.length() > 0)
- DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
+ DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName, &Postfix);
auto ResIt = ResTypeWellKnown.find(DemangledName);
if (ResIt != ResTypeWellKnown.end()) {
IsKnown = true;
@@ -1839,6 +1903,16 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
break;
}
}
+ // check if a floating rounding mode info is present
+ StringRef S = Postfix;
+ SmallVector<StringRef, 8> Parts;
+ S.split(Parts, "_", -1, false);
+ if (Parts.size() > 1) {
+ // Convert the tip about rounding mode into a decoration record.
+ unsigned RoundingModeDeco = roundingModeMDToDecorationConst(Parts[1]);
+ if (RoundingModeDeco != std::numeric_limits<unsigned>::max())
+ createRoundingModeDecoration(CI, RoundingModeDeco, B);
+ }
}
}
@@ -2264,6 +2338,9 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
// already, and force it to be i8 if not
if (Postpone && !GR->findAssignPtrTypeInstr(I))
insertAssignPtrTypeIntrs(I, B, true);
+
+ if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
+ useRoundingMode(FPI, B);
}
// Pass backward: use instructions results to specify/update/cast operands
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index b64030508cfc11..690b6b57211bb7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -560,6 +560,17 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
case TargetOpcode::G_FMA:
return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
+ case TargetOpcode::G_STRICT_FSQRT:
+ case TargetOpcode::G_STRICT_FADD:
+ case TargetOpcode::G_STRICT_FSUB:
+ case TargetOpcode::G_STRICT_FMUL:
+ case TargetOpcode::G_STRICT_FDIV:
+ case TargetOpcode::G_STRICT_FREM:
+ case TargetOpcode::G_STRICT_FLDEXP:
+ return false;
+ case TargetOpcode::G_STRICT_FMA:
+ return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
+
case TargetOpcode::G_FPOW:
return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
case TargetOpcode::G_FPOWI:
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 7230e0e6b9fca1..583a95150ef0cd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -221,6 +221,14 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
getActionDefinitionsBuilder(G_FMA).legalFor(allFloatScalarsAndVectors);
+ getActionDefinitionsBuilder({G_STRICT_FSQRT, G_STRICT_FADD, G_STRICT_FSUB, G_STRICT_FMUL,
+ G_STRICT_FDIV, G_STRICT_FREM, G_STRICT_FMA})
+ .legalFor(allFloatScalarsAndVectors);
+
+ getActionDefinitionsBuilder(G_STRICT_FLDEXP)
+ .legalForCartesianProduct(allFloatScalarsAndVectors,
+ allFloatScalarsAndVectors);
+
getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
.legalForCartesianProduct(allIntScalarsAndVectors,
allFloatScalarsAndVectors);
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 4dea4056799fec..6371c67d924580 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -1626,9 +1626,10 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
// Collect requirements for OpExecutionMode instructions.
auto Node = M.getNamedMetadata("spirv.ExecutionMode");
if (Node) {
- // SPV_KHR_float_controls is not available until v1.4
- bool RequireFloatControls = false,
+ bool RequireFloatControls = false, RequireFloatControls2 = false,
VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
+ bool HasFloatControls2 =
+ ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
for (unsigned i = 0; i < Node->getNumOperands(); i++) {
MDNode *MDN = cast<MDNode>(Node->getOperand(i));
const MDOperand &MDOp = MDN->getOperand(1);
@@ -1636,8 +1637,7 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
Constant *C = CMeta->getValue();
if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
auto EM = Const->getZExtValue();
- MAI.Reqs.getAndAddRequirements(
- SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
+ // SPV_KHR_float_controls is not available until v1.4:
// add SPV_KHR_float_controls if the version is too low
switch (EM) {
case SPIRV::ExecutionMode::DenormPreserve:
@@ -1646,7 +1646,22 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
case SPIRV::ExecutionMode::RoundingModeRTE:
case SPIRV::ExecutionMode::RoundingModeRTZ:
RequireFloatControls = VerLower14;
+ MAI.Reqs.getAndAddRequirements(
+ SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
break;
+ case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
+ case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
+ case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
+ case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
+ if (HasFloatControls2) {
+ RequireFloatControls2 = true;
+ MAI.Reqs.getAndAddRequirements(
+ SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
+ }
+ break;
+ default:
+ MAI.Reqs.getAndAddRequirements(
+ SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
}
}
}
@@ -1654,6 +1669,8 @@ 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)
+ MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
}
for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
const Function &F = *FI;
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 745d1e1aec67aa..3071df0e28c56e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -308,6 +308,7 @@ defm SPV_KHR_cooperative_matrix : ExtensionOperand<111>;
defm SPV_EXT_arithmetic_fence : ExtensionOperand<112>;
defm SPV_EXT_optnone : ExtensionOperand<113>;
defm SPV_INTEL_joint_matrix : ExtensionOperand<114>;
+defm SPV_INTEL_float_controls2 : ExtensionOperand<115>;
//===----------------------------------------------------------------------===//
// Multiclass used to define Capabilities enum values and at the same time
@@ -501,6 +502,9 @@ defm PackedCooperativeMatrixINTEL : CapabilityOperand<6434, 0, 0, [SPV_INTEL_joi
defm CooperativeMatrixInvocationInstructionsINTEL : CapabilityOperand<6435, 0, 0, [SPV_INTEL_joint_matrix], []>;
defm CooperativeMatrixTF32ComponentTypeINTEL : CapabilityOperand<6436, 0, 0, [SPV_INTEL_joint_matrix], []>;
defm CooperativeMatrixBFloat16ComponentTypeINTEL : CapabilityOperand<6437, 0, 0, [SPV_INTEL_joint_matrix], []>;
+defm RoundToInfinityINTEL : CapabilityOperand<5582, 0, 0, [SPV_INTEL_float_controls2], []>;
+defm FloatingPointModeINTEL : CapabilityOperand<5583, 0, 0, [SPV_INTEL_float_controls2], []>;
+defm FunctionFloatControlINTEL : CapabilityOperand<5821, 0, 0, [SPV_INTEL_float_controls2], []>;
//===----------------------------------------------------------------------===//
// Multiclass used to define SourceLanguage enum values and at the same time
@@ -694,6 +698,10 @@ defm OutputLinesNV : ExecutionModeOperand<5269, [MeshShadingNV]>;
defm DerivativeGroupQuadsNV : ExecutionModeOperand<5289, [ComputeDerivativeGroupQuadsNV]>;
defm DerivativeGroupLinearNV : ExecutionModeOperand<5290, [ComputeDerivativeGroupLinearNV]>;
defm OutputTrianglesNV : ExecutionModeOperand<5298, [MeshShadingNV]>;
+defm RoundingModeRTPINTEL : ExecutionModeOperand<5620, [RoundToInfinityINTEL]>;
+defm RoundingModeRTNINTEL : ExecutionModeOperand<5621, [RoundToInfinityINTEL]>;
+defm FloatingPointModeALTINTEL : ExecutionModeOperand<5622, [FloatingPointModeINTEL]>;
+defm FloatingPointModeIEEEINTEL : ExecutionModeOperand<5623, [FloatingPointModeINTEL]>;
//===----------------------------------------------------------------------===//
// Multiclass used to define StorageClass enum values and at the same time
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_empty.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_empty.ll
new file mode 100644
index 00000000000000..dca777a150a5bf
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_empty.ll
@@ -0,0 +1,18 @@
+; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_float_controls2
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls,+SPV_INTEL_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls,+SPV_INTEL_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-NOT: {{ExecutionMode.*(DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|RoundingModeRTPINTEL|RoundingModeRTNINTEL|FloatingPointModeALTINTEL|FloatingPointModeIEEEINTEL)}}
+define dso_local dllexport spir_kernel void @k_no_fc(i32 %ibuf, i32 %obuf) local_unnamed_addr #16 {
+entry:
+ ret void
+}
+
+attributes #16 = { noinline norecurse nounwind readnone "VCMain" "VCFunction" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 8.0.1"}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_intel.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_intel.ll
new file mode 100644
index 00000000000000..5de154053da831
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_float_controls2/exec_mode_float_control_intel.ll
@@ -0,0 +1,74 @@
+; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_float_controls2
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability RoundToInfinityINTEL
+; CHECK-DAG: Capability FloatingPointModeINTEL
+; CHECK: Extension "SPV_INTEL_float_controls2"
+
+define dso_local dllexport spir_kernel void @k_float_controls_0(i32 %ibuf, i32 %obuf) {
+entry:
+ ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_1(i32 %ibuf, i32 %obuf) {
+entry:
+ ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_2(i32 %ibuf, i32 %obuf) {
+entry:
+ ret void
+}
+
+define dso_local dllexport spir_kernel void @k_float_controls_3(i32 %ibuf, i32 %obuf) {
+entry:
+ ret void
+}
+
+!llvm.module.flags = !{!12}
+!llvm.ident = !{!13}
+!spirv.EntryPoint = !{}
+!spirv.ExecutionMode = !{!15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26}
+
+; CHECK-DAG: OpEntryPoint Kernel %[[#KERNEL0:]] "k_float_controls_0"
+; CHECK-DAG: OpEntryPoint Kernel %[[#KERNEL1:]] "k_float_controls_1"
+; CHECK-DAG: OpEntryPoint Kernel %[[#KERNEL2:]] "k_float_controls_2"
+; CHECK-DAG: OpEntryPoint Kernel %[[#KERNEL3:]] "k_float_controls_3"
+!0 = !{ptr @k_float_controls_0, !"k_float_controls_0", !1, i32 0, !2, !3, !4, i32 0, i32 0}
+!1 = !{i32 2, i32 2}
+!2 = !{i32 32, i32 36}
+!3 = !{i32 0, i32 0}
+!4 = !{!"", !""}
+!12 = !{i32 1, !"wchar_size", i32 4}
+!13 = !{!"clang version 8.0.1"}
+!14 = !{i32 1, i32 0}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL0]] RoundingModeRTPINTEL 64
+!15 = !{ptr @k_float_controls_0, i32 5620, i32 64}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL0]] RoundingModeRTPINTEL 32
+!16 = !{ptr @k_float_controls_0, i32 5620, i32 32}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL0]] RoundingModeRTPINTEL 16
+!17 = !{ptr @k_float_controls_0, i32 5620, i32 16}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL1]] RoundingModeRTNINTEL 64
+!18 = !{ptr @k_float_controls_1, i32 5621, i32 64}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL1]] RoundingModeRTNINTEL 32
+!19 = !{ptr @k_float_controls_1, i32 5621, i32 32}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL1]] RoundingModeRTNINTEL 16
+!20 = !{ptr @k_float_controls_1, i32 5621, i32 16}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL2]] FloatingPointModeALTINTEL 64
+!21 = !{ptr @k_float_controls_2, i32 5622, i32 64}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL2]] FloatingPointModeALTINTEL 32
+!22 = !{ptr @k_float_controls_2, i32 5622, i32 32}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL2]] FloatingPointModeALTINTEL 16
+!23 = !{ptr @k_float_controls_2, i32 5622, i32 16}
+
+; CHECK-DAG: OpExecutionMode %[[#KERNEL3]] FloatingPointModeIEEEINTEL 64
+!24 = !{ptr @k_float_controls_3, i32 5623, i32 64}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL3]] FloatingPointModeIEEEINTEL 32
+!25 = !{ptr @k_float_controls_3, i32 5623, i32 32}
+; CHECK-DAG: OpExecutionMode %[[#KERNEL3]] FloatingPointModeIEEEINTEL 16
+!26 = !{ptr @k_float_controls_3, i32 5623, i32 16}
diff --git a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
index 640dc273dfa62e..6763c95b51bf51 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
@@ -272,6 +272,10 @@ define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %arg
%r14 = call spir_func <4 x i32> @_Z22__spirv_SConvert_Rint2Dv2_a(<4 x i8> %arg_v2)
%r15 = call spir_func float @_Z30__spirv_ConvertUToF_Rfloat_rtz(i64 %arg_ptr)
%r16 = call spir_func float @__spirv_ConvertUToF_Rfloat_rtz(i64 %arg_ptr)
+ %r17 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtzDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
+ %r18 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rteDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
+ %r19 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtpDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
+ %r20 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtnDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
ret void
}
@@ -291,3 +295,7 @@ declare dso_local spir_func <4 x i32> @_Z22__spirv_UConvert_Rint2Dv2_a(<4 x i8>)
declare dso_local spir_func <4 x i32> @_Z22__spirv_SConvert_Rint2Dv2_a(<4 x i8>)
declare dso_local spir_func float @_Z30__spirv_ConvertUToF_Rfloat_rtz(i64)
declare dso_local spir_func float @__spirv_ConvertUToF_Rfloat_rtz(i64)
+declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtzDv2_DF16_(<2 x half> noundef)
+declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rteDv2_DF16_(<2 x half> noundef)
+declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtpDv2_DF16_(<2 x half> noundef)
+declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtnDv2_DF16_(<2 x half> noundef)
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
new file mode 100644
index 00000000000000..e30a2fef1d8cd4
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
@@ -0,0 +1,84 @@
+; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/llvm-intrinsics
+
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: OpName %[[#ad:]] "add"
+; CHECK: OpName %[[#di:]] "div"
+; CHECK: OpName %[[#su:]] "sub"
+; CHECK: OpName %[[#mu:]] "mul"
+
+; CHECK-NOT: OpDecorate %[[#]] FPRoundingMode
+
+; CHECK-DAG: OpDecorate %[[#ad]] FPRoundingMode 0
+; CHECK-DAG: OpDecorate %[[#di]] FPRoundingMode 1
+; CHECK-DAG: OpDecorate %[[#su]] FPRoundingMode 2
+; CHECK-DAG: OpDecorate %[[#mu]] FPRoundingMode 3
+
+; CHECK-NOT: OpDecorate %[[#]] FPRoundingMode
+
+; CHECK: OpFAdd %[[#]] %[[#ad]]
+; CHECK: OpFDiv %[[#]] %[[#di]]
+; CHECK: OpFSub %[[#]] %[[#su]]
+; CHECK: OpFMul %[[#]] %[[#mu]]
+; CHECK: OpFMul
+; CHECK: OpFAdd
+; CHECK: OpExtInst %[[#]] %[[#]] %[[#]] fma
+; CHECK: OpFRem
+
+; Function Attrs: norecurse nounwind strictfp
+define dso_local spir_kernel void @test(float %a, i32 %in, i32 %ui) local_unnamed_addr #0 !kernel_arg_addr_space !5 !kernel_arg_access_qual !6 !kernel_arg_type !7 !kernel_arg_base_type !7 !kernel_arg_type_qual !8 !kernel_arg_buffer_location !9 {
+entry:
+ %add = tail call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") #2
+ %div = tail call float @llvm.experimental.constrained.fdiv.f32(float %add, float %add, metadata !"round.towardzero", metadata !"fpexcept.strict") #2, !fpmath !10
+ %sub = tail call float @llvm.experimental.constrained.fsub.f32(float %div, float %div, metadata !"round.upward", metadata !"fpexcept.strict") #2
+ %mul = tail call float @llvm.experimental.constrained.fmul.f32(float %sub, float %sub, metadata !"round.downward", metadata !"fpexcept.strict") #2
+ ; TODO: @llvm.experimental.constrained.fmuladd is not supported at the moment
+ ; %0 = tail call float @llvm.experimental.constrained.fmuladd.f32(float %mul, float %mul, float %mul, metadata !"round.tonearestaway", metadata !"fpexcept.strict") #2
+ %r1 = tail call float @llvm.experimental.constrained.fma.f32(float %a, float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
+ %r2 = tail call float @llvm.experimental.constrained.frem.f32(float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
+ ret void
+}
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fmuladd.f32(float, float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) #1
+
+; Function Attrs: inaccessiblememonly nounwind willreturn
+declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata) #1
+
+attributes #0 = { norecurse nounwind strictfp "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="test2.cl" "uniform-work-group-size"="true" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { inaccessiblememonly nounwind willreturn }
+attributes #2 = { strictfp }
+
+!llvm.module.flags = !{!0}
+!opencl.ocl.version = !{!1}
+!opencl.spir.version = !{!2, !2}
+!spirv.Source = !{!3}
+!llvm.ident = !{!4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, i32 0}
+!2 = !{i32 1, i32 2}
+!3 = !{i32 4, i32 100000}
+!4 = !{!"clang version 12.0.0 (https://github.com/c199914007/llvm.git f0c85a8adeb49638c01eee1451aa9b35462cbfd5)"}
+!5 = !{i32 0, i32 0, i32 0}
+!6 = !{!"none", !"none", !"none"}
+!7 = !{!"float", !"int", !"uint"}
+!8 = !{!"", !"", !""}
+!9 = !{i32 -1, i32 -1, i32 -1}
+!10 = !{float 2.500000e+00}
>From 34e83541bb4ca6036881adfef15295bfbe05bb8c Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Thu, 12 Dec 2024 14:26:27 -0800
Subject: [PATCH 2/5] generate OpDecorate from demangled postfix (_R*) of a
builtin
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 18 +++++++++++-------
.../SPIRV/instructions/integer-casts.ll | 10 ++++++++++
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 5ab38109000330..4377dd085522d1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -1298,14 +1298,18 @@ static void createRoundingModeDecoration(Instruction *I,
IRBuilder<> &B) {
LLVMContext &Ctx = I->getContext();
Type *Int32Ty = Type::getInt32Ty(Ctx);
- SmallVector<Metadata *> MDs = {
- MDNode::get(Ctx, ConstantAsMetadata::get(ConstantInt::get(
- Int32Ty, SPIRV::Decoration::FPRoundingMode))),
- MDNode::get(Ctx, ConstantAsMetadata::get(
- ConstantInt::get(Int32Ty, RoundingModeDeco)))};
setInsertPointAfterDef(B, I);
- B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
- {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
+ B.CreateIntrinsic(
+ Intrinsic::spv_assign_decoration, {I->getType()},
+ {I,
+ MetadataAsValue::get(
+ Ctx,
+ MDNode::get(
+ Ctx, {MDNode::get(
+ Ctx, {ConstantAsMetadata::get(ConstantInt::get(
+ Int32Ty, SPIRV::Decoration::FPRoundingMode)),
+ ConstantAsMetadata::get(ConstantInt::get(
+ Int32Ty, RoundingModeDeco))})}))});
}
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
diff --git a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
index 6763c95b51bf51..7691d2d6b4dd19 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
@@ -24,12 +24,18 @@
; CHECK-DAG: OpName [[ZEXT8_16v4:%.*]] "u8tou16v4"
; CHECK-DAG: OpName [[ZEXT16_32v4:%.*]] "u16tou32v4"
+; CHECK-DAG: OpDecorate %[[#R17:]] FPRoundingMode RTZ
+; CHECK-DAG: OpDecorate %[[#R18:]] FPRoundingMode RTE
+; CHECK-DAG: OpDecorate %[[#R19:]] FPRoundingMode RTP
+; CHECK-DAG: OpDecorate %[[#R20:]] FPRoundingMode RTN
+
; CHECK-DAG: [[F32:%.*]] = OpTypeFloat 32
; CHECK-DAG: [[F16:%.*]] = OpTypeFloat 16
; CHECK-DAG: [[U64:%.*]] = OpTypeInt 64 0
; CHECK-DAG: [[U32:%.*]] = OpTypeInt 32 0
; CHECK-DAG: [[U16:%.*]] = OpTypeInt 16 0
; CHECK-DAG: [[U8:%.*]] = OpTypeInt 8 0
+; CHECK-DAG: [[F32v2:%.*]] = OpTypeVector [[F32]] 2
; CHECK-DAG: [[U32v4:%.*]] = OpTypeVector [[U32]] 4
; CHECK-DAG: [[U16v4:%.*]] = OpTypeVector [[U16]] 4
; CHECK-DAG: [[U8v4:%.*]] = OpTypeVector [[U8]] 4
@@ -254,6 +260,10 @@ define <4 x i32> @u16tou32v4(<4 x i16> %a) {
; CHECK: %[[#]] = OpSConvert [[U32v4]] %[[#]]
; CHECK: %[[#]] = OpConvertUToF [[F32]] %[[#]]
; CHECK: %[[#]] = OpConvertUToF [[F32]] %[[#]]
+; CHECK: %[[#R17:]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R18:]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R19:]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R20:]] = OpFConvert [[F32v2]] %[[#]]
; CHECK: OpFunctionEnd
define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %arg_ptr, <4 x i8> %arg_v2) {
%r1 = call spir_func i32 @__spirv_ConvertFToU(float 0.000000e+00)
>From 10ab51c5d66d345f0d399fec950c122f6b87bc27 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Fri, 13 Dec 2024 03:40:54 -0800
Subject: [PATCH 3/5] implement arith Constrained Floating-Point Intrinsics via
Tablegen; add float Saturation decoration
---
.../SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp | 9 ++--
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 41 +++++++++++++------
llvm/lib/Target/SPIRV/SPIRVInstrInfo.td | 6 +++
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 12 ++----
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 10 +++--
llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp | 7 ++--
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 4 +-
.../SPIRV/instructions/integer-casts.ll | 26 ++++++++----
.../llvm-intrinsics/constrained-arithmetic.ll | 15 +++----
9 files changed, 78 insertions(+), 52 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
index 42567f695395ef..68cc6a3a7aac1b 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
@@ -65,11 +65,10 @@ static bool hasType(const MCInst &MI, const MCInstrInfo &MII) {
// If we define an output, and have at least one other argument.
if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) {
// Check if we define an ID, and take a type as operand 1.
- auto &DefOpInfo = MCDesc.operands()[0];
- auto &FirstArgOpInfo = MCDesc.operands()[1];
- return DefOpInfo.RegClass >= 0 && FirstArgOpInfo.RegClass >= 0 &&
- DefOpInfo.RegClass != SPIRV::TYPERegClassID &&
- FirstArgOpInfo.RegClass == SPIRV::TYPERegClassID;
+ return MCDesc.operands()[0].RegClass >= 0 &&
+ MCDesc.operands()[1].RegClass >= 0 &&
+ MCDesc.operands()[0].RegClass != SPIRV::TYPERegClassID &&
+ MCDesc.operands()[1].RegClass == SPIRV::TYPERegClassID;
}
return false;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 4377dd085522d1..433956f44917fb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -1293,23 +1293,35 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
}
}
+static void createDecorationIntrinsic(Instruction *I, MDNode *Node,
+ IRBuilder<> &B) {
+ LLVMContext &Ctx = I->getContext();
+ setInsertPointAfterDef(B, I);
+ B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
+ {I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, {Node}))});
+}
+
static void createRoundingModeDecoration(Instruction *I,
unsigned RoundingModeDeco,
IRBuilder<> &B) {
LLVMContext &Ctx = I->getContext();
Type *Int32Ty = Type::getInt32Ty(Ctx);
- setInsertPointAfterDef(B, I);
- B.CreateIntrinsic(
- Intrinsic::spv_assign_decoration, {I->getType()},
- {I,
- MetadataAsValue::get(
- Ctx,
- MDNode::get(
- Ctx, {MDNode::get(
- Ctx, {ConstantAsMetadata::get(ConstantInt::get(
- Int32Ty, SPIRV::Decoration::FPRoundingMode)),
- ConstantAsMetadata::get(ConstantInt::get(
- Int32Ty, RoundingModeDeco))})}))});
+ MDNode *RoundingModeNode = MDNode::get(
+ Ctx,
+ {ConstantAsMetadata::get(
+ ConstantInt::get(Int32Ty, SPIRV::Decoration::FPRoundingMode)),
+ ConstantAsMetadata::get(ConstantInt::get(Int32Ty, RoundingModeDeco))});
+ createDecorationIntrinsic(I, RoundingModeNode, B);
+}
+
+static void createSaturatedConversionDecoration(Instruction *I,
+ IRBuilder<> &B) {
+ LLVMContext &Ctx = I->getContext();
+ Type *Int32Ty = Type::getInt32Ty(Ctx);
+ MDNode *SaturatedConversionNode =
+ MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(
+ Int32Ty, SPIRV::Decoration::SaturatedConversion))});
+ createDecorationIntrinsic(I, SaturatedConversionNode, B);
}
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
@@ -1912,10 +1924,13 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
SmallVector<StringRef, 8> Parts;
S.split(Parts, "_", -1, false);
if (Parts.size() > 1) {
- // Convert the tip about rounding mode into a decoration record.
+ // Convert the info about rounding mode into a decoration record.
unsigned RoundingModeDeco = roundingModeMDToDecorationConst(Parts[1]);
if (RoundingModeDeco != std::numeric_limits<unsigned>::max())
createRoundingModeDecoration(CI, RoundingModeDeco, B);
+ // Check if the SaturatedConversion info is present.
+ if (Parts[1] == "sat")
+ createSaturatedConversionDecoration(CI, B);
}
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
index d95803fea56a58..1bc35c6e57a4f6 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
@@ -491,16 +491,20 @@ def OpFNegate: UnOpTyped<"OpFNegate", 127, fID, fneg>;
def OpFNegateV: UnOpTyped<"OpFNegate", 127, vfID, fneg>;
defm OpIAdd: BinOpTypedGen<"OpIAdd", 128, add, 0, 1>;
defm OpFAdd: BinOpTypedGen<"OpFAdd", 129, fadd, 1, 1>;
+defm OpStrictFAdd: BinOpTypedGen<"OpFAdd", 129, strict_fadd, 1, 1>;
defm OpISub: BinOpTypedGen<"OpISub", 130, sub, 0, 1>;
defm OpFSub: BinOpTypedGen<"OpFSub", 131, fsub, 1, 1>;
+defm OpStrictFSub: BinOpTypedGen<"OpFSub", 131, strict_fsub, 1, 1>;
defm OpIMul: BinOpTypedGen<"OpIMul", 132, mul, 0, 1>;
defm OpFMul: BinOpTypedGen<"OpFMul", 133, fmul, 1, 1>;
+defm OpStrictFMul: BinOpTypedGen<"OpFMul", 133, strict_fmul, 1, 1>;
defm OpUDiv: BinOpTypedGen<"OpUDiv", 134, udiv, 0, 1>;
defm OpSDiv: BinOpTypedGen<"OpSDiv", 135, sdiv, 0, 1>;
defm OpFDiv: BinOpTypedGen<"OpFDiv", 136, fdiv, 1, 1>;
+defm OpStrictFDiv: BinOpTypedGen<"OpFDiv", 136, strict_fdiv, 1, 1>;
defm OpUMod: BinOpTypedGen<"OpUMod", 137, urem, 0, 1>;
defm OpSRem: BinOpTypedGen<"OpSRem", 138, srem, 0, 1>;
@@ -508,6 +512,8 @@ defm OpSRem: BinOpTypedGen<"OpSRem", 138, srem, 0, 1>;
def OpSMod: BinOp<"OpSMod", 139>;
defm OpFRem: BinOpTypedGen<"OpFRem", 140, frem, 1, 1>;
+defm OpStrictFRem: BinOpTypedGen<"OpFRem", 140, strict_frem, 1, 1>;
+
def OpFMod: BinOp<"OpFMod", 141>;
def OpVectorTimesScalar: BinOp<"OpVectorTimesScalar", 142>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 690b6b57211bb7..42fb7038a20b7e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -557,19 +557,12 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
case TargetOpcode::G_UCMP:
return selectSUCmp(ResVReg, ResType, I, false);
+ case TargetOpcode::G_STRICT_FMA:
case TargetOpcode::G_FMA:
return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
- case TargetOpcode::G_STRICT_FSQRT:
- case TargetOpcode::G_STRICT_FADD:
- case TargetOpcode::G_STRICT_FSUB:
- case TargetOpcode::G_STRICT_FMUL:
- case TargetOpcode::G_STRICT_FDIV:
- case TargetOpcode::G_STRICT_FREM:
case TargetOpcode::G_STRICT_FLDEXP:
- return false;
- case TargetOpcode::G_STRICT_FMA:
- return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
+ return selectExtInst(ResVReg, ResType, I, CL::ldexp);
case TargetOpcode::G_FPOW:
return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
@@ -629,6 +622,7 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
case TargetOpcode::G_FTANH:
return selectExtInst(ResVReg, ResType, I, CL::tanh, GL::Tanh);
+ case TargetOpcode::G_STRICT_FSQRT:
case TargetOpcode::G_FSQRT:
return selectExtInst(ResVReg, ResType, I, CL::sqrt, GL::Sqrt);
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 583a95150ef0cd..2950bc86072cf0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -27,16 +27,21 @@ using namespace llvm::LegalityPredicates;
static const std::set<unsigned> TypeFoldingSupportingOpcs = {
TargetOpcode::G_ADD,
TargetOpcode::G_FADD,
+ TargetOpcode::G_STRICT_FADD,
TargetOpcode::G_SUB,
TargetOpcode::G_FSUB,
+ TargetOpcode::G_STRICT_FSUB,
TargetOpcode::G_MUL,
TargetOpcode::G_FMUL,
+ TargetOpcode::G_STRICT_FMUL,
TargetOpcode::G_SDIV,
TargetOpcode::G_UDIV,
TargetOpcode::G_FDIV,
+ TargetOpcode::G_STRICT_FDIV,
TargetOpcode::G_SREM,
TargetOpcode::G_UREM,
TargetOpcode::G_FREM,
+ TargetOpcode::G_STRICT_FREM,
TargetOpcode::G_FNEG,
TargetOpcode::G_CONSTANT,
TargetOpcode::G_FCONSTANT,
@@ -219,10 +224,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
.legalFor(allIntScalarsAndVectors)
.legalIf(extendedScalarsAndVectors);
- getActionDefinitionsBuilder(G_FMA).legalFor(allFloatScalarsAndVectors);
-
- getActionDefinitionsBuilder({G_STRICT_FSQRT, G_STRICT_FADD, G_STRICT_FSUB, G_STRICT_FMUL,
- G_STRICT_FDIV, G_STRICT_FREM, G_STRICT_FMA})
+ getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
.legalFor(allFloatScalarsAndVectors);
getActionDefinitionsBuilder(G_STRICT_FLDEXP)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
index 3373d8e24dab48..a78c490bc9faa2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
@@ -55,10 +55,11 @@ extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR);
} // namespace llvm
-static bool isMetaInstrGET(unsigned Opcode) {
+static bool isMetaInstr(unsigned Opcode) {
return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_fID ||
Opcode == SPIRV::GET_pID || Opcode == SPIRV::GET_vID ||
- Opcode == SPIRV::GET_vfID || Opcode == SPIRV::GET_vpID;
+ Opcode == SPIRV::GET_vfID || Opcode == SPIRV::GET_vpID ||
+ Opcode == SPIRV::ASSIGN_TYPE;
}
static bool mayBeInserted(unsigned Opcode) {
@@ -128,7 +129,7 @@ static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
if (isTypeFoldingSupported(Opcode)) {
// Check if the instruction newly generated or already processed
MachineInstr *NextMI = I.getNextNode();
- if (NextMI && isMetaInstrGET(NextMI->getOpcode()))
+ if (NextMI && isMetaInstr(NextMI->getOpcode()))
continue;
// Restore usual instructions pattern for the newly inserted
// instruction
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index ceccf55d1de4df..cc48115240490d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -458,8 +458,10 @@ void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
MachineInstr &AssignTypeInst =
*(MRI.use_instr_begin(MI.getOperand(0).getReg()));
+ SPIRVType *SpvTypeRes = GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg());
auto NewReg =
- createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
+ createNewIdReg(SpvTypeRes, MI.getOperand(0).getReg(), MRI, *GR).first;
+ GR->assignSPIRVTypeToVReg(SpvTypeRes, NewReg, MIB.getMF());
AssignTypeInst.getOperand(1).setReg(NewReg);
MI.getOperand(0).setReg(NewReg);
MIB.setInsertPt(*MI.getParent(), MI.getIterator());
diff --git a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
index 7691d2d6b4dd19..6a4b4f593bf3b8 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/integer-casts.ll
@@ -14,6 +14,12 @@
; CHECK-DAG: OpName [[ZEXT8_16:%.*]] "u8tou16"
; CHECK-DAG: OpName [[ZEXT16_32:%.*]] "u16tou32"
+; CHECK-DAG: OpName %[[#R17:]] "r17"
+; CHECK-DAG: OpName %[[#R18:]] "r18"
+; CHECK-DAG: OpName %[[#R19:]] "r19"
+; CHECK-DAG: OpName %[[#R20:]] "r20"
+; CHECK-DAG: OpName %[[#R21:]] "r21"
+
; CHECK-DAG: OpName [[TRUNC32_16v4:%.*]] "i32toi16v4"
; CHECK-DAG: OpName [[TRUNC32_8v4:%.*]] "i32toi8v4"
; CHECK-DAG: OpName [[TRUNC16_8v4:%.*]] "i16toi8v4"
@@ -24,10 +30,11 @@
; CHECK-DAG: OpName [[ZEXT8_16v4:%.*]] "u8tou16v4"
; CHECK-DAG: OpName [[ZEXT16_32v4:%.*]] "u16tou32v4"
-; CHECK-DAG: OpDecorate %[[#R17:]] FPRoundingMode RTZ
-; CHECK-DAG: OpDecorate %[[#R18:]] FPRoundingMode RTE
-; CHECK-DAG: OpDecorate %[[#R19:]] FPRoundingMode RTP
-; CHECK-DAG: OpDecorate %[[#R20:]] FPRoundingMode RTN
+; CHECK-DAG: OpDecorate %[[#R17]] FPRoundingMode RTZ
+; CHECK-DAG: OpDecorate %[[#R18]] FPRoundingMode RTE
+; CHECK-DAG: OpDecorate %[[#R19]] FPRoundingMode RTP
+; CHECK-DAG: OpDecorate %[[#R20]] FPRoundingMode RTN
+; CHECK-DAG: OpDecorate %[[#R21]] SaturatedConversion
; CHECK-DAG: [[F32:%.*]] = OpTypeFloat 32
; CHECK-DAG: [[F16:%.*]] = OpTypeFloat 16
@@ -260,10 +267,11 @@ define <4 x i32> @u16tou32v4(<4 x i16> %a) {
; CHECK: %[[#]] = OpSConvert [[U32v4]] %[[#]]
; CHECK: %[[#]] = OpConvertUToF [[F32]] %[[#]]
; CHECK: %[[#]] = OpConvertUToF [[F32]] %[[#]]
-; CHECK: %[[#R17:]] = OpFConvert [[F32v2]] %[[#]]
-; CHECK: %[[#R18:]] = OpFConvert [[F32v2]] %[[#]]
-; CHECK: %[[#R19:]] = OpFConvert [[F32v2]] %[[#]]
-; CHECK: %[[#R20:]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R17]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R18]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R19]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R20]] = OpFConvert [[F32v2]] %[[#]]
+; CHECK: %[[#R21]] = OpConvertFToU [[U8]] %[[#]]
; CHECK: OpFunctionEnd
define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %arg_ptr, <4 x i8> %arg_v2) {
%r1 = call spir_func i32 @__spirv_ConvertFToU(float 0.000000e+00)
@@ -286,6 +294,7 @@ define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %arg
%r18 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rteDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
%r19 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtpDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
%r20 = call spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtnDv2_DF16_(<2 x half> noundef <half 0xH409A, half 0xH439A>)
+ %r21 = call spir_func i8 @_Z30__spirv_ConvertFToU_Ruchar_satf(float noundef 42.0)
ret void
}
@@ -309,3 +318,4 @@ declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtzDv2_DF1
declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rteDv2_DF16_(<2 x half> noundef)
declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtpDv2_DF16_(<2 x half> noundef)
declare dso_local spir_func <2 x float> @_Z28__spirv_FConvert_Rfloat2_rtnDv2_DF16_(<2 x half> noundef)
+declare dso_local spir_func i8 @_Z30__spirv_ConvertFToU_Ruchar_satf(float)
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
index e30a2fef1d8cd4..8b8d9973943b8f 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
@@ -21,8 +21,6 @@
; CHECK: OpFDiv %[[#]] %[[#di]]
; CHECK: OpFSub %[[#]] %[[#su]]
; CHECK: OpFMul %[[#]] %[[#mu]]
-; CHECK: OpFMul
-; CHECK: OpFAdd
; CHECK: OpExtInst %[[#]] %[[#]] %[[#]] fma
; CHECK: OpFRem
@@ -30,13 +28,12 @@
define dso_local spir_kernel void @test(float %a, i32 %in, i32 %ui) local_unnamed_addr #0 !kernel_arg_addr_space !5 !kernel_arg_access_qual !6 !kernel_arg_type !7 !kernel_arg_base_type !7 !kernel_arg_type_qual !8 !kernel_arg_buffer_location !9 {
entry:
%add = tail call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") #2
- %div = tail call float @llvm.experimental.constrained.fdiv.f32(float %add, float %add, metadata !"round.towardzero", metadata !"fpexcept.strict") #2, !fpmath !10
- %sub = tail call float @llvm.experimental.constrained.fsub.f32(float %div, float %div, metadata !"round.upward", metadata !"fpexcept.strict") #2
- %mul = tail call float @llvm.experimental.constrained.fmul.f32(float %sub, float %sub, metadata !"round.downward", metadata !"fpexcept.strict") #2
- ; TODO: @llvm.experimental.constrained.fmuladd is not supported at the moment
- ; %0 = tail call float @llvm.experimental.constrained.fmuladd.f32(float %mul, float %mul, float %mul, metadata !"round.tonearestaway", metadata !"fpexcept.strict") #2
- %r1 = tail call float @llvm.experimental.constrained.fma.f32(float %a, float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
- %r2 = tail call float @llvm.experimental.constrained.frem.f32(float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
+ %add2 = fadd float %a, %a
+; %div = tail call float @llvm.experimental.constrained.fdiv.f32(float %a, float %a, metadata !"round.towardzero", metadata !"fpexcept.strict") #2, !fpmath !10
+; %sub = tail call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.upward", metadata !"fpexcept.strict") #2
+; %mul = tail call float @llvm.experimental.constrained.fmul.f32(float %a, float %a, metadata !"round.downward", metadata !"fpexcept.strict") #2
+; %r1 = tail call float @llvm.experimental.constrained.fma.f32(float %a, float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
+; %r2 = tail call float @llvm.experimental.constrained.frem.f32(float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
ret void
}
>From 8cf4bd91d49346c5eddcd0f74683df27576a3e7a Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Fri, 13 Dec 2024 08:30:45 -0800
Subject: [PATCH 4/5] improve instruction selection
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 33 +++++-
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 3 +-
.../llvm-intrinsics/constrained-arithmetic.ll | 105 ++++++------------
3 files changed, 67 insertions(+), 74 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 42fb7038a20b7e..856caf2074fba4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -61,6 +61,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
/// We need to keep track of the number we give to anonymous global values to
/// generate the same name every time when this is needed.
mutable DenseMap<const GlobalValue *, unsigned> UnnamedGlobalIDs;
+ SmallPtrSet<MachineInstr *, 8> DeadMIs;
public:
SPIRVInstructionSelector(const SPIRVTargetMachine &TM,
@@ -382,6 +383,24 @@ static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI);
// Defined in SPIRVLegalizerInfo.cpp.
extern bool isTypeFoldingSupported(unsigned Opcode);
+bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI) {
+ for (const auto &MO : MI.all_defs()) {
+ Register Reg = MO.getReg();
+ if (Reg.isPhysical() || !MRI.use_nodbg_empty(Reg))
+ return false;
+ }
+ if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE || MI.isFakeUse() ||
+ MI.isLifetimeMarker())
+ return false;
+ if (MI.isPHI())
+ return true;
+ if (MI.mayStore() || MI.isCall() ||
+ (MI.mayLoad() && MI.hasOrderedMemoryRef()) || MI.isPosition() ||
+ MI.isDebugInstr() || MI.isTerminator() || MI.isJumpTableDebugInfo())
+ return false;
+ return true;
+}
+
bool SPIRVInstructionSelector::select(MachineInstr &I) {
resetVRegsType(*I.getParent()->getParent());
@@ -404,8 +423,11 @@ bool SPIRVInstructionSelector::select(MachineInstr &I) {
}
});
assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
- if (Res)
+ if (Res) {
+ if (!isTriviallyDead(*Def, *MRI) && isDead(*Def, *MRI))
+ DeadMIs.insert(Def);
return Res;
+ }
}
MRI->setRegClass(SrcReg, MRI->getRegClass(DstReg));
MRI->replaceRegWith(SrcReg, DstReg);
@@ -418,6 +440,15 @@ bool SPIRVInstructionSelector::select(MachineInstr &I) {
return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
}
+ if (DeadMIs.contains(&I)) {
+ // if the instruction has been already made dead by folding it away
+ // erase it
+ LLVM_DEBUG(dbgs() << "Instruction is folded and dead.\n");
+ salvageDebugInfo(*MRI, I);
+ I.eraseFromParent();
+ return true;
+ }
+
if (I.getNumOperands() != I.getNumExplicitOperands()) {
LLVM_DEBUG(errs() << "Generic instr has unexpected implicit operands\n");
return false;
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 2950bc86072cf0..80464e14b2cc26 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -228,8 +228,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
.legalFor(allFloatScalarsAndVectors);
getActionDefinitionsBuilder(G_STRICT_FLDEXP)
- .legalForCartesianProduct(allFloatScalarsAndVectors,
- allFloatScalarsAndVectors);
+ .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);
getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
.legalForCartesianProduct(allIntScalarsAndVectors,
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
index 8b8d9973943b8f..11bedfa605f9b4 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-arithmetic.ll
@@ -1,81 +1,44 @@
-; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/llvm-intrinsics
-
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-; CHECK: OpName %[[#ad:]] "add"
-; CHECK: OpName %[[#di:]] "div"
-; CHECK: OpName %[[#su:]] "sub"
-; CHECK: OpName %[[#mu:]] "mul"
-
-; CHECK-NOT: OpDecorate %[[#]] FPRoundingMode
-
-; CHECK-DAG: OpDecorate %[[#ad]] FPRoundingMode 0
-; CHECK-DAG: OpDecorate %[[#di]] FPRoundingMode 1
-; CHECK-DAG: OpDecorate %[[#su]] FPRoundingMode 2
-; CHECK-DAG: OpDecorate %[[#mu]] FPRoundingMode 3
-
-; CHECK-NOT: OpDecorate %[[#]] FPRoundingMode
-
-; CHECK: OpFAdd %[[#]] %[[#ad]]
-; CHECK: OpFDiv %[[#]] %[[#di]]
-; CHECK: OpFSub %[[#]] %[[#su]]
-; CHECK: OpFMul %[[#]] %[[#mu]]
-; CHECK: OpExtInst %[[#]] %[[#]] %[[#]] fma
+; CHECK-DAG: OpName %[[#r1:]] "r1"
+; CHECK-DAG: OpName %[[#r2:]] "r2"
+; CHECK-DAG: OpName %[[#r3:]] "r3"
+; CHECK-DAG: OpName %[[#r4:]] "r4"
+; CHECK-DAG: OpName %[[#r5:]] "r5"
+; CHECK-DAG: OpName %[[#r6:]] "r6"
+
+; CHECK-NOT: OpDecorate %[[#r5]] FPRoundingMode
+; CHECK-NOT: OpDecorate %[[#r6]] FPRoundingMode
+
+; CHECK-DAG: OpDecorate %[[#r1]] FPRoundingMode RTE
+; CHECK-DAG: OpDecorate %[[#r2]] FPRoundingMode RTZ
+; CHECK-DAG: OpDecorate %[[#r4]] FPRoundingMode RTN
+; CHECK-DAG: OpDecorate %[[#r3]] FPRoundingMode RTP
+
+; CHECK: OpFAdd %[[#]] %[[#]]
+; CHECK: OpFDiv %[[#]] %[[#]]
+; CHECK: OpFSub %[[#]] %[[#]]
+; CHECK: OpFMul %[[#]] %[[#]]
+; CHECK: OpExtInst %[[#]] %[[#]] fma %[[#]] %[[#]] %[[#]]
; CHECK: OpFRem
; Function Attrs: norecurse nounwind strictfp
-define dso_local spir_kernel void @test(float %a, i32 %in, i32 %ui) local_unnamed_addr #0 !kernel_arg_addr_space !5 !kernel_arg_access_qual !6 !kernel_arg_type !7 !kernel_arg_base_type !7 !kernel_arg_type_qual !8 !kernel_arg_buffer_location !9 {
+define dso_local spir_kernel void @test(float %a, i32 %in, i32 %ui) {
entry:
- %add = tail call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") #2
- %add2 = fadd float %a, %a
-; %div = tail call float @llvm.experimental.constrained.fdiv.f32(float %a, float %a, metadata !"round.towardzero", metadata !"fpexcept.strict") #2, !fpmath !10
-; %sub = tail call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.upward", metadata !"fpexcept.strict") #2
-; %mul = tail call float @llvm.experimental.constrained.fmul.f32(float %a, float %a, metadata !"round.downward", metadata !"fpexcept.strict") #2
-; %r1 = tail call float @llvm.experimental.constrained.fma.f32(float %a, float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
-; %r2 = tail call float @llvm.experimental.constrained.frem.f32(float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict") #2
+ %r1 = tail call float @llvm.experimental.constrained.fadd.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ %r2 = tail call float @llvm.experimental.constrained.fdiv.f32(float %a, float %a, metadata !"round.towardzero", metadata !"fpexcept.strict")
+ %r3 = tail call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.upward", metadata !"fpexcept.strict")
+ %r4 = tail call float @llvm.experimental.constrained.fmul.f32(float %a, float %a, metadata !"round.downward", metadata !"fpexcept.strict")
+ %r5 = tail call float @llvm.experimental.constrained.fma.f32(float %a, float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict")
+ %r6 = tail call float @llvm.experimental.constrained.frem.f32(float %a, float %a, metadata !"round.dynamic", metadata !"fpexcept.strict")
ret void
}
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fmuladd.f32(float, float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) #1
-
-; Function Attrs: inaccessiblememonly nounwind willreturn
-declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata) #1
-
-attributes #0 = { norecurse nounwind strictfp "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "sycl-module-id"="test2.cl" "uniform-work-group-size"="true" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { inaccessiblememonly nounwind willreturn }
-attributes #2 = { strictfp }
-
-!llvm.module.flags = !{!0}
-!opencl.ocl.version = !{!1}
-!opencl.spir.version = !{!2, !2}
-!spirv.Source = !{!3}
-!llvm.ident = !{!4}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 1, i32 0}
-!2 = !{i32 1, i32 2}
-!3 = !{i32 4, i32 100000}
-!4 = !{!"clang version 12.0.0 (https://github.com/c199914007/llvm.git f0c85a8adeb49638c01eee1451aa9b35462cbfd5)"}
-!5 = !{i32 0, i32 0, i32 0}
-!6 = !{!"none", !"none", !"none"}
-!7 = !{!"float", !"int", !"uint"}
-!8 = !{!"", !"", !""}
-!9 = !{i32 -1, i32 -1, i32 -1}
-!10 = !{float 2.500000e+00}
+declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.fmuladd.f32(float, float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata)
+declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata)
>From 9e0a5a1c2497f92a76cc1c994e06464ca5376a8b Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Fri, 13 Dec 2024 12:31:14 -0800
Subject: [PATCH 5/5] add Decoration for SPV_INTEL_float_controls2; fix
postlegalizer
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 14 ++++----
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 2 ++
llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp | 32 ++++++-------------
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 3 ++
4 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 5f72a41ddb8647..3e913646d57c80 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -126,14 +126,14 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeInt(unsigned Width,
Width = adjustOpTypeIntWidth(Width);
const SPIRVSubtarget &ST =
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
- if (ST.canUseExtension(
- SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers)) {
- MIRBuilder.buildInstr(SPIRV::OpExtension)
- .addImm(SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers);
- MIRBuilder.buildInstr(SPIRV::OpCapability)
- .addImm(SPIRV::Capability::ArbitraryPrecisionIntegersINTEL);
- }
return createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+ if (ST.canUseExtension(
+ SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers)) {
+ MIRBuilder.buildInstr(SPIRV::OpExtension)
+ .addImm(SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers);
+ MIRBuilder.buildInstr(SPIRV::OpCapability)
+ .addImm(SPIRV::Capability::ArbitraryPrecisionIntegersINTEL);
+ }
return MIRBuilder.buildInstr(SPIRV::OpTypeInt)
.addDef(createTypeVReg(MIRBuilder))
.addImm(Width)
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 80464e14b2cc26..b22027cd2cb931 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -24,6 +24,7 @@ using namespace llvm;
using namespace llvm::LegalizeActions;
using namespace llvm::LegalityPredicates;
+// clang-format off
static const std::set<unsigned> TypeFoldingSupportingOpcs = {
TargetOpcode::G_ADD,
TargetOpcode::G_FADD,
@@ -54,6 +55,7 @@ static const std::set<unsigned> TypeFoldingSupportingOpcs = {
TargetOpcode::G_SELECT,
TargetOpcode::G_EXTRACT_VECTOR_ELT,
};
+// clang-format on
bool isTypeFoldingSupported(unsigned Opcode) {
return TypeFoldingSupportingOpcs.count(Opcode) > 0;
diff --git a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
index a78c490bc9faa2..6027d24636d69a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
@@ -55,13 +55,6 @@ extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR);
} // namespace llvm
-static bool isMetaInstr(unsigned Opcode) {
- return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_fID ||
- Opcode == SPIRV::GET_pID || Opcode == SPIRV::GET_vID ||
- Opcode == SPIRV::GET_vfID || Opcode == SPIRV::GET_vpID ||
- Opcode == SPIRV::ASSIGN_TYPE;
-}
-
static bool mayBeInserted(unsigned Opcode) {
switch (Opcode) {
case TargetOpcode::G_SMAX:
@@ -112,27 +105,20 @@ static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
// registers, we must decorate them as if they were introduced in a
// non-automatic way
Register ResVReg = I.getOperand(0).getReg();
- SPIRVType *ResVType = GR->getSPIRVTypeForVReg(ResVReg);
// Check if the register defined by the instruction is newly generated
// or already processed
- if (!ResVType) {
- // Set type of the defined register
- ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
- // Check if we have type defined for operands of the new instruction
- if (!ResVType)
- continue;
- // Set type & class
- setRegClassType(ResVReg, ResVType, GR, &MRI, *GR->CurMF, true);
- }
+ if (MRI.getRegClassOrNull(ResVReg))
+ continue;
+ assert(GR->getSPIRVTypeForVReg(ResVReg) == nullptr);
+ // Check if we have type defined for operands of the new instruction
+ SPIRVType *ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
+ if (!ResVType)
+ continue;
+ // Set type & class
+ setRegClassType(ResVReg, ResVType, GR, &MRI, *GR->CurMF, true);
// If this is a simple operation that is to be reduced by TableGen
// definition we must apply some of pre-legalizer rules here
if (isTypeFoldingSupported(Opcode)) {
- // Check if the instruction newly generated or already processed
- MachineInstr *NextMI = I.getNextNode();
- if (NextMI && isMetaInstr(NextMI->getOpcode()))
- continue;
- // Restore usual instructions pattern for the newly inserted
- // instruction
insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
processInstr(I, MIB, MRI, GR);
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 3071df0e28c56e..fec3cb0091bf57 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -1250,6 +1250,9 @@ defm CacheControlStoreINTEL : DecorationOperand<6443, 0, 0, [], [CacheControlsIN
defm HostAccessINTEL : DecorationOperand<6188, 0, 0, [], [GlobalVariableHostAccessINTEL]>;
defm InitModeINTEL : DecorationOperand<6190, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
defm ImplementInRegisterMapINTEL : DecorationOperand<6191, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
+defm FunctionRoundingModeINTEL : DecorationOperand<5822, 0, 0, [], [FunctionFloatControlINTEL]>;
+defm FunctionDenormModeINTEL : DecorationOperand<5823, 0, 0, [], [FunctionFloatControlINTEL]>;
+defm FunctionFloatingPointModeINTEL : DecorationOperand<6080, 0, 0, [], [FunctionFloatControlINTEL]>;
//===----------------------------------------------------------------------===//
// Multiclass used to define BuiltIn enum values and at the same time
More information about the llvm-commits
mailing list