Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7ca5c71
Implement extension SPV_KHR_float_controls2
jmmartinez Nov 18, 2025
bd74ca9
[Review] set FPFastMathDefault equal to 0 for every entry-point
jmmartinez Dec 22, 2025
d0d26f2
[Review] Add test showing reassoc->AllowTransform->reassoc contract
jmmartinez Dec 22, 2025
2b25d20
[Review] add fcmp and ExtInst tests
jmmartinez Dec 22, 2025
08aee52
Ignore FPFastMathMode decorations attached as metadata
jmmartinez Dec 22, 2025
03e9a61
Add test with multiple floating point types
jmmartinez Dec 22, 2025
e8eb865
[Review] reword FPFastMathMode decoration metadata comment
jmmartinez Jan 5, 2026
97211a8
[Review] fix typo in execution_mode_default.ll
jmmartinez Jan 5, 2026
d58da85
[Review] rename CHECK->SPIRV in execution_mode_default.ll
jmmartinez Jan 5, 2026
7321ab2
[Review] add reverse translation tests for execution_mode_default.ll
jmmartinez Jan 5, 2026
0f02365
[Review] remove word-count from SPIRV checks in execution_mode_defaul…
jmmartinez Jan 5, 2026
fe86d9c
[Review] remove word-count from SPIRV checks in fp-decorate-twice.ll
jmmartinez Jan 5, 2026
48424af
[Review] Pre-commit tests before changing the logic of transFPFastMat…
jmmartinez Jan 5, 2026
49600ab
[Review] Update transFPFastMathDefault
jmmartinez Jan 5, 2026
e7f4886
[Review][NFC] Comments and renames
jmmartinez Jan 9, 2026
1802fde
[Review][NFC] Add assertions
jmmartinez Jan 9, 2026
4967f1c
[Review] Propagate FP mode to vector types
jmmartinez Jan 9, 2026
97c9d7a
[Review] missing space
jmmartinez Jan 13, 2026
5e6e80b
[Review] missing .
jmmartinez Jan 13, 2026
b1b0d71
[Review] operaiton -> operation
jmmartinez Jan 13, 2026
437daf5
[Review] Do not set FPFastMathDefault to 0 by default / translate Con…
jmmartinez Jan 19, 2026
ebdcd76
[Review] make tests more reliable
jmmartinez Jan 23, 2026
2c6901c
[Review] Emit the FastMathDefaultMode in a consistent order
jmmartinez Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/LLVMSPIRVExtensions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,4 @@ EXT(SPV_INTEL_predicated_io)
EXT(SPV_INTEL_sigmoid)
EXT(SPV_INTEL_float4)
EXT(SPV_INTEL_fp_conversions)
EXT(SPV_KHR_float_controls2)
10 changes: 7 additions & 3 deletions lib/SPIRV/SPIRVMDWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class SPIRVMDWalker {

bool atEnd() const { return !(M && I < E); }

template <typename T> MDWrapper &get(T &V) {
template <typename IntegerType,
typename = std::enable_if_t<std::is_integral_v<IntegerType>>>
MDWrapper &get(IntegerType &V) {
if (!Q)
assert(I < E && "out of bound");
if (atEnd())
Expand All @@ -115,12 +117,14 @@ class SPIRVMDWalker {
return *this;
}

MDWrapper &get(Function *&F) {
template <typename ValueType,
typename = std::enable_if_t<std::is_base_of_v<Value, ValueType>>>
MDWrapper &get(ValueType *&V) {
if (!Q)
assert(I < E && "out of bound");
if (atEnd())
return *this;
F = mdconst::dyn_extract<Function>(M->getOperand(I++));
V = mdconst::dyn_extract<ValueType>(M->getOperand(I++));
return *this;
}

Expand Down
103 changes: 85 additions & 18 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1218,26 +1218,24 @@ static void applyNoIntegerWrapDecorations(const SPIRVValue *BV,
}
}

static void applyFPFastMathModeDecorations(const SPIRVValue *BV,
Instruction *Inst) {
SPIRVWord V;
FastMathFlags FMF;
void SPIRVToLLVM::applyFPFastMathModeDecorations(const SPIRVValue *BV,
Instruction *Inst) {
if (!isa<FPMathOperator>(Inst))
return;

SPIRVWord V{0};
if (BV->hasDecorate(DecorationFPFastMathMode, 0, &V)) {
if (V & FPFastMathModeNotNaNMask)
FMF.setNoNaNs();
if (V & FPFastMathModeNotInfMask)
FMF.setNoInfs();
if (V & FPFastMathModeNSZMask)
FMF.setNoSignedZeros();
if (V & FPFastMathModeAllowRecipMask)
FMF.setAllowReciprocal();
if (V & FPFastMathModeAllowContractFastINTELMask)
FMF.setAllowContract();
if (V & FPFastMathModeAllowReassocINTELMask)
FMF.setAllowReassoc();
if (V & FPFastMathModeFastMask)
FMF.setFast();
FastMathFlags FMF = translateFastMathFlags(V);
Inst->setFastMathFlags(FMF);
return;
}

// Get the scalar type to handle vector operands. And get the first operand
// type (instead of the result) due to fcmp instructions.
Type *FloatType = Inst->getOperand(0)->getType()->getScalarType();
auto Func2FMF = FuncToFastMathFlags.find({Inst->getFunction(), FloatType});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm tempted to remove this FuncToFastMathFlags stuff.

It's used to set the FPFastMathFlags that are attached to the execution mode to the individual instructions of a kernel.

But since we're preserving the FPFastMathFlags in the metadata; I'm thinking that this is not needed anymore.

@maarquitos14 should I remove this ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this logic should be still placed somewhere as the middleend and backend are unlikely to know about this metadata out of the box and honestly it feels like for optimization passes it's easier to work with individual instruction flags. IMHO resolving ExecutionMode to FP flag right away in the SPIR-V consumer won't harm and actually make implementation lower-level drivers friendly.

@svenvh @vmaksimo WDYT?

if (Func2FMF != FuncToFastMathFlags.end()) {
Inst->setFastMathFlags(Func2FMF->second);
}
}

Expand Down Expand Up @@ -3443,6 +3441,73 @@ static void validatePhiPredecessors(Function *F) {
}
} // namespace

FastMathFlags SPIRVToLLVM::translateFastMathFlags(SPIRVWord V) const {
FastMathFlags FMF;
if (V & FPFastMathModeNotNaNMask)
FMF.setNoNaNs();
if (V & FPFastMathModeNotInfMask)
FMF.setNoInfs();
if (V & FPFastMathModeNSZMask)
FMF.setNoSignedZeros();
if (V & FPFastMathModeAllowRecipMask)
FMF.setAllowReciprocal();
static_assert(FPFastMathModeAllowContractFastINTELMask ==
FPFastMathModeAllowContractMask);
if (V & FPFastMathModeAllowContractFastINTELMask)
FMF.setAllowContract();
static_assert(FPFastMathModeAllowReassocINTELMask ==
FPFastMathModeAllowReassocMask);
if (V & FPFastMathModeAllowReassocINTELMask)
FMF.setAllowReassoc();
// There is no FPFastMathMode flag that represents LLVM approximate functions
// flag `afn`. Even the FPFastMathMode Fast flag should not imply it, but to
// avoid changing the previous behaviour we make it equivalent to LLVM's.
if (V & FPFastMathModeFastMask)
FMF.setFast();
if (V & FPFastMathModeAllowTransformMask) {
// AllowTransform requires the AllowContract and AllowReassoc bits to be
// set.
assert(FMF.allowContract() && FMF.allowReassoc() &&
"The FPFastMathMode AllowTransform requires AllowContract and "
"AllowReassoc to be set");
}

return FMF;
}

void SPIRVToLLVM::parseFloatControls2ExecutionModeId(SPIRVFunction *BF,
Function *F) {

auto [Begin, End] =
BF->getExecutionModeRange(spv::ExecutionModeFPFastMathDefault);
if (Begin == End)
return;

LLVMContext &C = F->getContext();
NamedMDNode *ExecModeMD =
M->getOrInsertNamedMetadata(kSPIRVMD::ExecutionMode);

Metadata *FPFastMathMode[4] = {ConstantAsMetadata::get(F),
ConstantAsMetadata::get(getUInt32(
M, spv::ExecutionModeFPFastMathDefault)),
nullptr, nullptr};

for (auto [_, EM] : make_range(Begin, End)) {
const auto &Literals = EM->getLiterals();
assert(Literals.size() == 2);
SPIRVWord FloatTyId = Literals[0];
SPIRVType *FloatSPIRVType = BM->get<SPIRVType>(FloatTyId);
Type *FloatType = transFPType(FloatSPIRVType);
SPIRVWord Flags = *transIdAsConstant(Literals[1]);
FuncToFastMathFlags.try_emplace({F, FloatType},
translateFastMathFlags(Flags));

FPFastMathMode[2] = ConstantAsMetadata::get(PoisonValue::get(FloatType));
FPFastMathMode[3] = ConstantAsMetadata::get(getUInt32(M, Flags));
ExecModeMD->addOperand(MDNode::get(C, FPFastMathMode));
}
}

Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF, unsigned AS) {
auto Loc = FuncMap.find(BF);
if (Loc != FuncMap.end())
Expand Down Expand Up @@ -3520,6 +3585,8 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF, unsigned AS) {
: CallingConv::SPIR_FUNC);
transFunctionAttrs(BF, F);

parseFloatControls2ExecutionModeId(BF, F);

// Creating all basic blocks before creating instructions.
for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) {
transValue(BF->getBasicBlock(I), F, nullptr);
Expand Down
8 changes: 8 additions & 0 deletions lib/SPIRV/SPIRVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ class SPIRVToLLVM : private BuiltinCallHelper {
void
transFunctionPointerCallArgumentAttributes(SPIRVValue *BV, CallInst *CI,
SPIRVTypeFunction *CalledFnTy);

using FunctionAndTypeIdPair = std::pair<Function *, Type *>;
using FunctionToFastMathFlagsMap =
DenseMap<FunctionAndTypeIdPair, FastMathFlags>;
FunctionToFastMathFlagsMap FuncToFastMathFlags;
FastMathFlags translateFastMathFlags(SPIRVWord V) const;
void parseFloatControls2ExecutionModeId(SPIRVFunction *BF, Function *F);
void applyFPFastMathModeDecorations(const SPIRVValue *BV, Instruction *Inst);
}; // class SPIRVToLLVM

} // namespace SPIRV
Expand Down
Loading
Loading