Skip to content

Commit 7d6a5d3

Browse files
introduce SPV_INTEL_float_controls2; add arith Constrained Floating-Point Intrinsics; add float rounding mode decoration
1 parent 42633cf commit 7d6a5d3

File tree

13 files changed

+323
-9
lines changed

13 files changed

+323
-9
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
159159
- Adds instructions to convert between single-precision 32-bit floating-point values and 16-bit bfloat16 values.
160160
* - ``SPV_INTEL_cache_controls``
161161
- Allows cache control information to be applied to memory access instructions.
162+
* - ``SPV_INTEL_float_controls2``
163+
- Adds execution modes and decorations to control floating-point computations.
162164
* - ``SPV_INTEL_function_pointers``
163165
- Allows translation of function pointers.
164166
* - ``SPV_INTEL_inline_assembly``

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ using namespace InstructionSet;
173173

174174
namespace SPIRV {
175175
/// Parses the name part of the demangled builtin call.
176-
std::string lookupBuiltinNameHelper(StringRef DemangledCall) {
176+
std::string lookupBuiltinNameHelper(StringRef DemangledCall,
177+
std::string *Postfix) {
177178
const static std::string PassPrefix = "(anonymous namespace)::";
178179
std::string BuiltinName;
179180
// Itanium Demangler result may have "(anonymous namespace)::" prefix
@@ -231,10 +232,13 @@ std::string lookupBuiltinNameHelper(StringRef DemangledCall) {
231232
"ReadClockKHR|SubgroupBlockReadINTEL|SubgroupImageBlockReadINTEL|"
232233
"SubgroupImageMediaBlockReadINTEL|SubgroupImageMediaBlockWriteINTEL|"
233234
"Convert|"
234-
"UConvert|SConvert|FConvert|SatConvert).*)_R.*");
235+
"UConvert|SConvert|FConvert|SatConvert).*)_R(.*)");
235236
std::smatch Match;
236-
if (std::regex_match(BuiltinName, Match, SpvWithR) && Match.size() > 2)
237+
if (std::regex_match(BuiltinName, Match, SpvWithR) && Match.size() > 3) {
237238
BuiltinName = Match[1].str();
239+
if (Postfix)
240+
*Postfix = Match[3].str();
241+
}
238242

239243
return BuiltinName;
240244
}

llvm/lib/Target/SPIRV/SPIRVBuiltins.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
namespace llvm {
2121
namespace SPIRV {
2222
/// Parses the name part of the demangled builtin call.
23-
std::string lookupBuiltinNameHelper(StringRef DemangledCall);
23+
std::string lookupBuiltinNameHelper(StringRef DemangledCall,
24+
std::string *Postfix = nullptr);
2425
/// Lowers a builtin function call using the provided \p DemangledCall skeleton
2526
/// and external instruction \p Set.
2627
///

llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
3636
SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
3737
{"SPV_INTEL_cache_controls",
3838
SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
39+
{"SPV_INTEL_float_controls2",
40+
SPIRV::Extension::Extension::SPV_INTEL_float_controls2},
3941
{"SPV_INTEL_global_variable_fpga_decorations",
4042
SPIRV::Extension::Extension::
4143
SPV_INTEL_global_variable_fpga_decorations},

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ class SPIRVEmitIntrinsics
216216
bool processFunctionPointers(Module &M);
217217
void parseFunDeclarations(Module &M);
218218

219+
void useRoundingMode(ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
220+
219221
public:
220222
static char ID;
221223
SPIRVEmitIntrinsics() : ModulePass(ID) {
@@ -1291,6 +1293,21 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
12911293
}
12921294
}
12931295

1296+
static void createRoundingModeDecoration(Instruction *I,
1297+
unsigned RoundingModeDeco,
1298+
IRBuilder<> &B) {
1299+
LLVMContext &Ctx = I->getContext();
1300+
Type *Int32Ty = Type::getInt32Ty(Ctx);
1301+
SmallVector<Metadata *> MDs = {
1302+
MDNode::get(Ctx, ConstantAsMetadata::get(ConstantInt::get(
1303+
Int32Ty, SPIRV::Decoration::FPRoundingMode))),
1304+
MDNode::get(Ctx, ConstantAsMetadata::get(
1305+
ConstantInt::get(Int32Ty, RoundingModeDeco)))};
1306+
setInsertPointAfterDef(B, I);
1307+
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
1308+
{I, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
1309+
}
1310+
12941311
Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
12951312
if (!Call.isInlineAsm())
12961313
return &Call;
@@ -1312,6 +1329,40 @@ Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
13121329
return &Call;
13131330
}
13141331

1332+
// Use a tip about rounding mode to create a decoration.
1333+
void SPIRVEmitIntrinsics::useRoundingMode(ConstrainedFPIntrinsic *FPI,
1334+
IRBuilder<> &B) {
1335+
std::optional<RoundingMode> RM = FPI->getRoundingMode();
1336+
if (!RM.has_value())
1337+
return;
1338+
unsigned RoundingModeDeco = std::numeric_limits<unsigned>::max();
1339+
switch (RM.value()) {
1340+
default:
1341+
// ignore unknown rounding modes
1342+
break;
1343+
case RoundingMode::NearestTiesToEven:
1344+
RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1345+
break;
1346+
case RoundingMode::TowardNegative:
1347+
RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1348+
break;
1349+
case RoundingMode::TowardPositive:
1350+
RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1351+
break;
1352+
case RoundingMode::TowardZero:
1353+
RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1354+
break;
1355+
case RoundingMode::Dynamic:
1356+
case RoundingMode::NearestTiesToAway:
1357+
// TODO: check if supported
1358+
break;
1359+
}
1360+
if (RoundingModeDeco == std::numeric_limits<unsigned>::max())
1361+
return;
1362+
// Convert the tip about rounding mode into a decoration record.
1363+
createRoundingModeDecoration(FPI, RoundingModeDeco, B);
1364+
}
1365+
13151366
Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
13161367
BasicBlock *ParentBB = I.getParent();
13171368
IRBuilder<> B(ParentBB);
@@ -1809,6 +1860,18 @@ bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
18091860
return true;
18101861
}
18111862

1863+
static unsigned roundingModeMDToDecorationConst(StringRef S) {
1864+
if (S == "rte")
1865+
return SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1866+
if (S == "rtz")
1867+
return SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1868+
if (S == "rtp")
1869+
return SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1870+
if (S == "rtn")
1871+
return SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1872+
return std::numeric_limits<unsigned>::max();
1873+
}
1874+
18121875
void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
18131876
IRBuilder<> &B) {
18141877
// TODO: extend the list of functions with known result types
@@ -1826,8 +1889,9 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
18261889
Function *CalledF = CI->getCalledFunction();
18271890
std::string DemangledName =
18281891
getOclOrSpirvBuiltinDemangledName(CalledF->getName());
1892+
std::string Postfix;
18291893
if (DemangledName.length() > 0)
1830-
DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName);
1894+
DemangledName = SPIRV::lookupBuiltinNameHelper(DemangledName, &Postfix);
18311895
auto ResIt = ResTypeWellKnown.find(DemangledName);
18321896
if (ResIt != ResTypeWellKnown.end()) {
18331897
IsKnown = true;
@@ -1839,6 +1903,16 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
18391903
break;
18401904
}
18411905
}
1906+
// check if a floating rounding mode info is present
1907+
StringRef S = Postfix;
1908+
SmallVector<StringRef, 8> Parts;
1909+
S.split(Parts, "_", -1, false);
1910+
if (Parts.size() > 1) {
1911+
// Convert the tip about rounding mode into a decoration record.
1912+
unsigned RoundingModeDeco = roundingModeMDToDecorationConst(Parts[1]);
1913+
if (RoundingModeDeco != std::numeric_limits<unsigned>::max())
1914+
createRoundingModeDecoration(CI, RoundingModeDeco, B);
1915+
}
18421916
}
18431917
}
18441918

@@ -2264,6 +2338,9 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
22642338
// already, and force it to be i8 if not
22652339
if (Postpone && !GR->findAssignPtrTypeInstr(I))
22662340
insertAssignPtrTypeIntrs(I, B, true);
2341+
2342+
if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
2343+
useRoundingMode(FPI, B);
22672344
}
22682345

22692346
// Pass backward: use instructions results to specify/update/cast operands

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,17 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
560560
case TargetOpcode::G_FMA:
561561
return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
562562

563+
case TargetOpcode::G_STRICT_FSQRT:
564+
case TargetOpcode::G_STRICT_FADD:
565+
case TargetOpcode::G_STRICT_FSUB:
566+
case TargetOpcode::G_STRICT_FMUL:
567+
case TargetOpcode::G_STRICT_FDIV:
568+
case TargetOpcode::G_STRICT_FREM:
569+
case TargetOpcode::G_STRICT_FLDEXP:
570+
return false;
571+
case TargetOpcode::G_STRICT_FMA:
572+
return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
573+
563574
case TargetOpcode::G_FPOW:
564575
return selectExtInst(ResVReg, ResType, I, CL::pow, GL::Pow);
565576
case TargetOpcode::G_FPOWI:

llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
221221

222222
getActionDefinitionsBuilder(G_FMA).legalFor(allFloatScalarsAndVectors);
223223

224+
getActionDefinitionsBuilder({G_STRICT_FSQRT, G_STRICT_FADD, G_STRICT_FSUB, G_STRICT_FMUL,
225+
G_STRICT_FDIV, G_STRICT_FREM, G_STRICT_FMA})
226+
.legalFor(allFloatScalarsAndVectors);
227+
228+
getActionDefinitionsBuilder(G_STRICT_FLDEXP)
229+
.legalForCartesianProduct(allFloatScalarsAndVectors,
230+
allFloatScalarsAndVectors);
231+
224232
getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
225233
.legalForCartesianProduct(allIntScalarsAndVectors,
226234
allFloatScalarsAndVectors);

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,18 +1626,18 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
16261626
// Collect requirements for OpExecutionMode instructions.
16271627
auto Node = M.getNamedMetadata("spirv.ExecutionMode");
16281628
if (Node) {
1629-
// SPV_KHR_float_controls is not available until v1.4
1630-
bool RequireFloatControls = false,
1629+
bool RequireFloatControls = false, RequireFloatControls2 = false,
16311630
VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
1631+
bool HasFloatControls2 =
1632+
ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
16321633
for (unsigned i = 0; i < Node->getNumOperands(); i++) {
16331634
MDNode *MDN = cast<MDNode>(Node->getOperand(i));
16341635
const MDOperand &MDOp = MDN->getOperand(1);
16351636
if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
16361637
Constant *C = CMeta->getValue();
16371638
if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
16381639
auto EM = Const->getZExtValue();
1639-
MAI.Reqs.getAndAddRequirements(
1640-
SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1640+
// SPV_KHR_float_controls is not available until v1.4:
16411641
// add SPV_KHR_float_controls if the version is too low
16421642
switch (EM) {
16431643
case SPIRV::ExecutionMode::DenormPreserve:
@@ -1646,14 +1646,31 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
16461646
case SPIRV::ExecutionMode::RoundingModeRTE:
16471647
case SPIRV::ExecutionMode::RoundingModeRTZ:
16481648
RequireFloatControls = VerLower14;
1649+
MAI.Reqs.getAndAddRequirements(
1650+
SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
16491651
break;
1652+
case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
1653+
case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
1654+
case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
1655+
case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
1656+
if (HasFloatControls2) {
1657+
RequireFloatControls2 = true;
1658+
MAI.Reqs.getAndAddRequirements(
1659+
SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1660+
}
1661+
break;
1662+
default:
1663+
MAI.Reqs.getAndAddRequirements(
1664+
SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
16501665
}
16511666
}
16521667
}
16531668
}
16541669
if (RequireFloatControls &&
16551670
ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
16561671
MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
1672+
if (RequireFloatControls2)
1673+
MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
16571674
}
16581675
for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
16591676
const Function &F = *FI;

llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ defm SPV_KHR_cooperative_matrix : ExtensionOperand<111>;
308308
defm SPV_EXT_arithmetic_fence : ExtensionOperand<112>;
309309
defm SPV_EXT_optnone : ExtensionOperand<113>;
310310
defm SPV_INTEL_joint_matrix : ExtensionOperand<114>;
311+
defm SPV_INTEL_float_controls2 : ExtensionOperand<115>;
311312

312313
//===----------------------------------------------------------------------===//
313314
// 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
501502
defm CooperativeMatrixInvocationInstructionsINTEL : CapabilityOperand<6435, 0, 0, [SPV_INTEL_joint_matrix], []>;
502503
defm CooperativeMatrixTF32ComponentTypeINTEL : CapabilityOperand<6436, 0, 0, [SPV_INTEL_joint_matrix], []>;
503504
defm CooperativeMatrixBFloat16ComponentTypeINTEL : CapabilityOperand<6437, 0, 0, [SPV_INTEL_joint_matrix], []>;
505+
defm RoundToInfinityINTEL : CapabilityOperand<5582, 0, 0, [SPV_INTEL_float_controls2], []>;
506+
defm FloatingPointModeINTEL : CapabilityOperand<5583, 0, 0, [SPV_INTEL_float_controls2], []>;
507+
defm FunctionFloatControlINTEL : CapabilityOperand<5821, 0, 0, [SPV_INTEL_float_controls2], []>;
504508

505509
//===----------------------------------------------------------------------===//
506510
// Multiclass used to define SourceLanguage enum values and at the same time
@@ -694,6 +698,10 @@ defm OutputLinesNV : ExecutionModeOperand<5269, [MeshShadingNV]>;
694698
defm DerivativeGroupQuadsNV : ExecutionModeOperand<5289, [ComputeDerivativeGroupQuadsNV]>;
695699
defm DerivativeGroupLinearNV : ExecutionModeOperand<5290, [ComputeDerivativeGroupLinearNV]>;
696700
defm OutputTrianglesNV : ExecutionModeOperand<5298, [MeshShadingNV]>;
701+
defm RoundingModeRTPINTEL : ExecutionModeOperand<5620, [RoundToInfinityINTEL]>;
702+
defm RoundingModeRTNINTEL : ExecutionModeOperand<5621, [RoundToInfinityINTEL]>;
703+
defm FloatingPointModeALTINTEL : ExecutionModeOperand<5622, [FloatingPointModeINTEL]>;
704+
defm FloatingPointModeIEEEINTEL : ExecutionModeOperand<5623, [FloatingPointModeINTEL]>;
697705

698706
//===----------------------------------------------------------------------===//
699707
// Multiclass used to define StorageClass enum values and at the same time
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_float_controls2
2+
3+
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls,+SPV_INTEL_float_controls2 %s -o - | FileCheck %s
4+
; 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 %}
5+
6+
; CHECK-NOT: {{ExecutionMode.*(DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|RoundingModeRTPINTEL|RoundingModeRTNINTEL|FloatingPointModeALTINTEL|FloatingPointModeIEEEINTEL)}}
7+
define dso_local dllexport spir_kernel void @k_no_fc(i32 %ibuf, i32 %obuf) local_unnamed_addr #16 {
8+
entry:
9+
ret void
10+
}
11+
12+
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" }
13+
14+
!llvm.module.flags = !{!0}
15+
!llvm.ident = !{!1}
16+
17+
!0 = !{i32 1, !"wchar_size", i32 4}
18+
!1 = !{!"clang version 8.0.1"}

0 commit comments

Comments
 (0)