Skip to content

[SPIRV] Change how to detect OpenCL/Vulkan Env and update tests accordingly. #129689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bbf7b42
Dissociate Logical/Physical from OpenCL/Vulkan env.
Apr 16, 2025
f6bf74b
Extra change to complete dissociation.
maarquitos14 Apr 16, 2025
4c7bbc2
Use entry points to help determine the env.
maarquitos14 Apr 23, 2025
ecb4f79
Explicitly add vulkan to triple of failing tests.
maarquitos14 Apr 24, 2025
1a4e754
Fix clang-format issue.
maarquitos14 May 1, 2025
54adad6
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 1, 2025
314f4e0
Fix failing test.
maarquitos14 May 1, 2025
6d0cf9e
Fix debug build.
maarquitos14 May 1, 2025
0f95726
Fix failing tests.
maarquitos14 May 1, 2025
a42ecac
Fix test failure.
maarquitos14 May 1, 2025
3221f7e
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 14, 2025
0cb18d0
Address code review feedback.
maarquitos14 May 14, 2025
4d84546
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 14, 2025
7a0be57
Fix build issues.
maarquitos14 May 14, 2025
70835b9
Fix typo.
maarquitos14 May 14, 2025
afa72c1
Fix test failure.
maarquitos14 May 14, 2025
b7879b5
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 15, 2025
85d600f
Fix test failure.
maarquitos14 May 15, 2025
5513335
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 27, 2025
61f2abd
Address code review feedback.
maarquitos14 May 27, 2025
a36faa4
Address more code review feedback.
maarquitos14 May 28, 2025
fcc219a
Turn assertion into fatal error.
maarquitos14 May 28, 2025
42df23d
Replace is[Kernel|Shader]Env with is[Kernel|Shader].
maarquitos14 May 30, 2025
dd530b9
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
maarquitos14 May 30, 2025
248c5e6
Fix test failure.
maarquitos14 May 30, 2025
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
2 changes: 1 addition & 1 deletion llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
Inst.addOperand(MCOperand::createImm(TypeCode));
outputMCInst(Inst);
}
if (ST->isOpenCLEnv() && !M.getNamedMetadata("spirv.ExecutionMode") &&
if (ST->isKernel() && !M.getNamedMetadata("spirv.ExecutionMode") &&
!M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
MCInst Inst;
Inst.setOpcode(SPIRV::OpExecutionMode);
Expand Down
36 changes: 32 additions & 4 deletions llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,37 @@ static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx,

static SPIRV::ExecutionModel::ExecutionModel
getExecutionModel(const SPIRVSubtarget &STI, const Function &F) {
if (STI.isOpenCLEnv())
if (STI.isKernel())
return SPIRV::ExecutionModel::Kernel;

if (STI.isShader()) {
auto attribute = F.getFnAttribute("hlsl.shader");
if (!attribute.isValid()) {
report_fatal_error(
"This entry point lacks mandatory hlsl.shader attribute.");
}

const auto value = attribute.getValueAsString();
if (value == "compute")
return SPIRV::ExecutionModel::GLCompute;

report_fatal_error(
"This HLSL entry point is not supported by this backend.");
}

assert(STI.getEnv() == SPIRVSubtarget::Unknown);
// "hlsl.shader" attribute is mandatory for Vulkan, so we can set Env to
// Shader whenever we find it, and to Kernel otherwise.

// We will now change the Env based on the attribute, so we need to strip
// `const` out of the ref to STI.
SPIRVSubtarget *NonConstSTI = const_cast<SPIRVSubtarget *>(&STI);
auto attribute = F.getFnAttribute("hlsl.shader");
if (!attribute.isValid()) {
report_fatal_error(
"This entry point lacks mandatory hlsl.shader attribute.");
NonConstSTI->setEnv(SPIRVSubtarget::Kernel);
return SPIRV::ExecutionModel::Kernel;
}
NonConstSTI->setEnv(SPIRVSubtarget::Shader);

const auto value = attribute.getValueAsString();
if (value == "compute")
Expand Down Expand Up @@ -319,7 +342,7 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
buildOpDecorate(VRegs[i][0], MIRBuilder,
SPIRV::Decoration::MaxByteOffset, {DerefBytes});
}
if (Arg.hasAttribute(Attribute::Alignment) && !ST->isVulkanEnv()) {
if (Arg.hasAttribute(Attribute::Alignment) && !ST->isShader()) {
auto Alignment = static_cast<unsigned>(
Arg.getAttribute(Attribute::Alignment).getValueAsInt());
buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment,
Expand Down Expand Up @@ -439,6 +462,11 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,

// Handle entry points and function linkage.
if (isEntryPoint(F)) {
// EntryPoints can help us to determine the environment we're working on.
// Therefore, we need a non-const pointer to SPIRVSubtarget to update the
// environment if we need to.
const SPIRVSubtarget *ST =
static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint)
.addImm(static_cast<uint32_t>(getExecutionModel(*ST, F)))
.addUse(FuncVReg);
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,10 +772,10 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
// TODO: maybe move to GenerateDecorations pass.
const SPIRVSubtarget &ST =
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
if (IsConst && ST.isOpenCLEnv())
if (IsConst && !ST.isShader())
buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::Constant, {});

if (GVar && GVar->getAlign().valueOrOne().value() != 1 && !ST.isVulkanEnv()) {
if (GVar && GVar->getAlign().valueOrOne().value() != 1 && !ST.isShader()) {
unsigned Alignment = (unsigned)GVar->getAlign().valueOrOne().value();
buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::Alignment, {Alignment});
}
Expand Down Expand Up @@ -988,7 +988,7 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeStruct(
Register ResVReg = createTypeVReg(MIRBuilder);
if (Ty->hasName())
buildOpName(ResVReg, Ty->getName(), MIRBuilder);
if (Ty->isPacked() && !ST.isVulkanEnv())
if (Ty->isPacked() && !ST.isShader())
buildOpDecorate(ResVReg, MIRBuilder, SPIRV::Decoration::CPacked, {});

SPIRVType *SPVType =
Expand Down
34 changes: 17 additions & 17 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
.addUse(GV);
return MIB.constrainAllUses(TII, TRI, RBI) &&
BuildMI(BB, I, I.getDebugLoc(),
TII.get(STI.isVulkanEnv()
TII.get(STI.isLogicalSPIRV()
? SPIRV::OpInBoundsAccessChain
: SPIRV::OpInBoundsPtrAccessChain))
.addDef(ResVReg)
Expand Down Expand Up @@ -1034,7 +1034,7 @@ bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
const SPIRVType *ResType,
MachineInstr &I,
unsigned Opcode) const {
if (STI.isOpenCLEnv() && I.getOperand(1).isReg()) {
if (STI.isPhysicalSPIRV() && I.getOperand(1).isReg()) {
Register SrcReg = I.getOperand(1).getReg();
bool IsGV = false;
for (MachineRegisterInfo::def_instr_iterator DefIt =
Expand Down Expand Up @@ -2062,7 +2062,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
auto ExtractOp =
Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;

bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
// Extract the i8 element, multiply and add it to the accumulator
for (unsigned i = 0; i < 4; i++) {
// A[i]
Expand Down Expand Up @@ -2202,7 +2202,7 @@ bool SPIRVInstructionSelector::selectWaveOpInst(Register ResVReg,
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I,
IntTy, TII, STI.isOpenCLEnv()));
IntTy, TII, !STI.isShader()));

for (unsigned J = 2; J < I.getNumOperands(); J++) {
BMI.addUse(I.getOperand(J).getReg());
Expand All @@ -2226,7 +2226,7 @@ bool SPIRVInstructionSelector::selectWaveActiveCountBits(
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy,
TII, STI.isOpenCLEnv()))
TII, !STI.isShader()))
.addImm(SPIRV::GroupOperation::Reduce)
.addUse(BallotReg)
.constrainAllUses(TII, TRI, RBI);
Expand Down Expand Up @@ -2257,7 +2257,7 @@ bool SPIRVInstructionSelector::selectWaveReduceMax(Register ResVReg,
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
STI.isOpenCLEnv()))
!STI.isShader()))
.addImm(SPIRV::GroupOperation::Reduce)
.addUse(I.getOperand(2).getReg())
.constrainAllUses(TII, TRI, RBI);
Expand All @@ -2284,7 +2284,7 @@ bool SPIRVInstructionSelector::selectWaveReduceSum(Register ResVReg,
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup, I, IntTy, TII,
STI.isOpenCLEnv()))
!STI.isShader()))
.addImm(SPIRV::GroupOperation::Reduce)
.addUse(I.getOperand(2).getReg());
}
Expand Down Expand Up @@ -2506,7 +2506,7 @@ bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
MachineInstr &I) const {
// OpenCL uses nulls for Zero. In HLSL we don't use null constants.
bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
if (ResType->getOpcode() == SPIRV::OpTypeVector)
return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
Expand All @@ -2515,7 +2515,7 @@ Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType,
MachineInstr &I) const {
// OpenCL uses nulls for Zero. In HLSL we don't use null constants.
bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
if (ResType->getOpcode() == SPIRV::OpTypeVector)
return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
Expand All @@ -2525,7 +2525,7 @@ Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType,
Register SPIRVInstructionSelector::buildOnesValF(const SPIRVType *ResType,
MachineInstr &I) const {
// OpenCL uses nulls for Zero. In HLSL we don't use null constants.
bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
APFloat VOne = getOneFP(GR.getTypeForSPIRVType(ResType));
if (ResType->getOpcode() == SPIRV::OpTypeVector)
return GR.getOrCreateConstVector(VOne, I, ResType, TII, ZeroAsNull);
Expand Down Expand Up @@ -2713,10 +2713,10 @@ bool SPIRVInstructionSelector::selectConst(Register ResVReg,
Reg = GR.getOrCreateConstNullPtr(MIRBuilder, ResType);
} else if (Opcode == TargetOpcode::G_FCONSTANT) {
Reg = GR.getOrCreateConstFP(I.getOperand(1).getFPImm()->getValue(), I,
ResType, TII, STI.isOpenCLEnv());
ResType, TII, !STI.isShader());
} else {
Reg = GR.getOrCreateConstInt(I.getOperand(1).getCImm()->getZExtValue(), I,
ResType, TII, STI.isOpenCLEnv());
ResType, TII, !STI.isShader());
}
return Reg == ResVReg ? true : BuildCOPY(ResVReg, Reg, I);
}
Expand Down Expand Up @@ -2796,7 +2796,7 @@ bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
// OpAccessChain could be used for OpenCL, but the SPIRV-LLVM Translator only
// relies on PtrAccessChain, so we'll try not to deviate. For Vulkan however,
// we have to use Op[InBounds]AccessChain.
const unsigned Opcode = STI.isVulkanEnv()
const unsigned Opcode = STI.isLogicalSPIRV()
? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
: SPIRV::OpAccessChain)
: (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
Expand Down Expand Up @@ -3493,7 +3493,7 @@ bool SPIRVInstructionSelector::selectFirstBitSet64Overflow(

// On odd component counts we need to handle one more component
if (CurrentComponent != ComponentCount) {
bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
Register FinalElemReg = MRI->createVirtualRegister(GR.getRegClass(I64Type));
Register ConstIntLastIdx = GR.getOrCreateConstInt(
ComponentCount - 1, I, BaseType, TII, ZeroAsNull);
Expand Down Expand Up @@ -3523,7 +3523,7 @@ bool SPIRVInstructionSelector::selectFirstBitSet64(
Register SrcReg, unsigned BitSetOpcode, bool SwapPrimarySide) const {
unsigned ComponentCount = GR.getScalarOrVectorComponentCount(ResType);
SPIRVType *BaseType = GR.retrieveScalarOrVectorIntType(ResType);
bool ZeroAsNull = STI.isOpenCLEnv();
bool ZeroAsNull = !STI.isShader();
Register ConstIntZero =
GR.getOrCreateConstInt(0, I, BaseType, TII, ZeroAsNull);
Register ConstIntOne =
Expand Down Expand Up @@ -3725,7 +3725,7 @@ bool SPIRVInstructionSelector::selectAllocaArray(Register ResVReg,
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(I.getOperand(2).getReg())
.constrainAllUses(TII, TRI, RBI);
if (!STI.isVulkanEnv()) {
if (!STI.isShader()) {
unsigned Alignment = I.getOperand(3).getImm();
buildOpDecorate(ResVReg, I, TII, SPIRV::Decoration::Alignment, {Alignment});
}
Expand All @@ -3744,7 +3744,7 @@ bool SPIRVInstructionSelector::selectFrameIndex(Register ResVReg,
.addUse(GR.getSPIRVTypeID(ResType))
.addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function))
.constrainAllUses(TII, TRI, RBI);
if (!STI.isVulkanEnv()) {
if (!STI.isShader()) {
unsigned Alignment = I.getOperand(2).getImm();
buildOpDecorate(ResVReg, *It, TII, SPIRV::Decoration::Alignment,
{Alignment});
Expand Down
26 changes: 14 additions & 12 deletions llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
SPIRV::RequirementHandler &Reqs) {
// A set of capabilities to avoid if there is another option.
AvoidCapabilitiesSet AvoidCaps;
if (ST.isOpenCLEnv())
if (!ST.isShader())
AvoidCaps.S.insert(SPIRV::Capability::Shader);

VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
Expand Down Expand Up @@ -144,8 +144,8 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1));
} else {
// TODO: Add support for VulkanMemoryModel.
MAI.Mem = ST->isOpenCLEnv() ? SPIRV::MemoryModel::OpenCL
: SPIRV::MemoryModel::GLSL450;
MAI.Mem = ST->isShader() ? SPIRV::MemoryModel::GLSL450
: SPIRV::MemoryModel::OpenCL;
if (MAI.Mem == SPIRV::MemoryModel::OpenCL) {
unsigned PtrSize = ST->getPointerSize();
MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
Expand Down Expand Up @@ -175,7 +175,7 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
// OpenCL 1.0 by default for the OpenCL environment to avoid puzzling
// run-times with Unknown/0.0 version output. For a reference, LLVM-SPIRV
// Translator avoids potential issues with run-times in a similar manner.
if (ST->isOpenCLEnv()) {
if (!ST->isShader()) {
MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_CPP;
MAI.SrcLangVersion = 100000;
} else {
Expand Down Expand Up @@ -203,7 +203,7 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
MAI.Addr, *ST);

if (ST->isOpenCLEnv()) {
if (!ST->isShader()) {
// TODO: check if it's required by default.
MAI.ExtInstSetMap[static_cast<unsigned>(
SPIRV::InstructionSet::OpenCL_std)] = MAI.getNextIDRegister();
Expand Down Expand Up @@ -804,12 +804,12 @@ void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
addAvailableCaps(EnabledCapabilities);
}

if (ST.isOpenCLEnv()) {
if (!ST.isShader()) {
initAvailableCapabilitiesForOpenCL(ST);
return;
}

if (ST.isVulkanEnv()) {
if (ST.isShader()) {
initAvailableCapabilitiesForVulkan(ST);
return;
}
Expand Down Expand Up @@ -969,7 +969,7 @@ static void addOpTypeImageReqs(const MachineInstr &MI,
}

// Has optional access qualifier.
if (ST.isOpenCLEnv()) {
if (!ST.isShader()) {
if (MI.getNumOperands() > 8 &&
MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
Expand Down Expand Up @@ -1267,7 +1267,7 @@ void addInstrRequirements(const MachineInstr &MI,
ST);
// If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
// capability.
if (!ST.isOpenCLEnv())
if (ST.isShader())
break;
assert(MI.getOperand(2).isReg());
const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
Expand Down Expand Up @@ -1342,7 +1342,7 @@ void addInstrRequirements(const MachineInstr &MI,
addOpTypeImageReqs(MI, Reqs, ST);
break;
case SPIRV::OpTypeSampler:
if (!ST.isVulkanEnv()) {
if (!ST.isShader()) {
Reqs.addCapability(SPIRV::Capability::ImageBasic);
}
break;
Expand Down Expand Up @@ -1793,7 +1793,8 @@ void addInstrRequirements(const MachineInstr &MI,
// not allowed to produce
// StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
// https://github.com/KhronosGroup/SPIRV-Headers/issues/487
if (isImageTypeWithUnknownFormat(TypeDef) && !ST.isOpenCLEnv())

if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
break;
}
Expand All @@ -1806,7 +1807,8 @@ void addInstrRequirements(const MachineInstr &MI,
// not allowed to produce
// StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
// https://github.com/KhronosGroup/SPIRV-Headers/issues/487
if (isImageTypeWithUnknownFormat(TypeDef) && !ST.isOpenCLEnv())

if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
break;
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,13 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
Changed = true;
break;
case Intrinsic::lifetime_start:
if (STI.isOpenCLEnv()) {
if (!STI.isShader()) {
Changed |= toSpvOverloadedIntrinsic(
II, Intrinsic::SPVIntrinsics::spv_lifetime_start, {1});
}
break;
case Intrinsic::lifetime_end:
if (STI.isOpenCLEnv()) {
if (!STI.isShader()) {
Changed |= toSpvOverloadedIntrinsic(
II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1});
}
Expand Down
Loading