Skip to content
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.
Apr 16, 2025
4c7bbc2
Use entry points to help determine the env.
Apr 23, 2025
ecb4f79
Explicitly add vulkan to triple of failing tests.
Apr 24, 2025
1a4e754
Fix clang-format issue.
May 1, 2025
54adad6
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 1, 2025
314f4e0
Fix failing test.
May 1, 2025
6d0cf9e
Fix debug build.
May 1, 2025
0f95726
Fix failing tests.
May 1, 2025
a42ecac
Fix test failure.
May 1, 2025
3221f7e
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 14, 2025
0cb18d0
Address code review feedback.
May 14, 2025
4d84546
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 14, 2025
7a0be57
Fix build issues.
May 14, 2025
70835b9
Fix typo.
May 14, 2025
afa72c1
Fix test failure.
May 14, 2025
b7879b5
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 15, 2025
85d600f
Fix test failure.
May 15, 2025
5513335
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 27, 2025
61f2abd
Address code review feedback.
May 27, 2025
a36faa4
Address more code review feedback.
May 28, 2025
fcc219a
Turn assertion into fatal error.
May 28, 2025
42df23d
Replace is[Kernel|Shader]Env with is[Kernel|Shader].
May 30, 2025
dd530b9
Merge remote-tracking branch 'origin/main' into maronas/use-spirv-fri…
May 30, 2025
248c5e6
Fix test failure.
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);
Comment on lines +297 to +300
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I just notice this causes the result of isShader to change part way through the compilation. This can cause inconsistent results. I've opened issue #171898 to follow up on this.


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