[llvm] 56396b2 - [SPIRV-V] Add SPIR-V logical triple to llc
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 11 01:32:27 PDT 2023
Author: Nathan Gauër
Date: 2023-09-11T10:31:50+02:00
New Revision: 56396b25f1793a4853561efe89df04f61b0306a0
URL: https://github.com/llvm/llvm-project/commit/56396b25f1793a4853561efe89df04f61b0306a0
DIFF: https://github.com/llvm/llvm-project/commit/56396b25f1793a4853561efe89df04f61b0306a0.diff
LOG: [SPIRV-V] Add SPIR-V logical triple to llc
This commits adds the minimal required bits to build a logical SPIR-V
compute shader using LLC.
- Skip OpenCL-only capabilities & extensions for Logical SPIR-V.
- Generate required metadata for entrypoints from HLSL frontend.
- Fix execution mode to GLCompute in logical.
The main issue is the lack of "vulkan" bit in the triple.
This might need to be added as a vendor?
Because as-is, SPIRV32/64 assumes OpenCL, and then, SPIRV assumes
Vulkan. This is ok-ish today, but not correct.
Differential Revision: https://reviews.llvm.org/D156424
Added:
llvm/test/CodeGen/SPIRV/ExecutionMode_GLCompute.ll
llvm/test/CodeGen/SPIRV/capability-Shader.ll
llvm/test/CodeGen/SPIRV/empty-logical.ll
Modified:
llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp
llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
llvm/lib/Target/SPIRV/SPIRVSubtarget.h
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp
llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp
index 62ce15550ae7dc8..78dfbf4ec9327a2 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp
@@ -88,7 +88,8 @@ static MCInstrAnalysis *createSPIRVInstrAnalysis(const MCInstrInfo *Info) {
}
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTargetMC() {
- for (Target *T : {&getTheSPIRV32Target(), &getTheSPIRV64Target()}) {
+ for (Target *T : {&getTheSPIRV32Target(), &getTheSPIRV64Target(),
+ &getTheSPIRVLogicalTarget()}) {
RegisterMCAsmInfo<SPIRVMCAsmInfo> X(*T);
TargetRegistry::RegisterMCInstrInfo(*T, createSPIRVMCInstrInfo);
TargetRegistry::RegisterMCRegInfo(*T, createSPIRVMCRegisterInfo);
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index d07c0bcdf9af2c7..27da0f21f1571d3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -66,6 +66,9 @@ class SPIRVAsmPrinter : public AsmPrinter {
void outputExtFuncDecls();
void outputExecutionModeFromMDNode(Register Reg, MDNode *Node,
SPIRV::ExecutionMode::ExecutionMode EM);
+ void outputExecutionModeFromNumthreadsAttribute(
+ const Register &Reg, const Attribute &Attr,
+ SPIRV::ExecutionMode::ExecutionMode EM);
void outputExecutionMode(const Module &M);
void outputAnnotations(const Module &M);
void outputModuleSections();
@@ -412,6 +415,29 @@ void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
outputMCInst(Inst);
}
+void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
+ const Register &Reg, const Attribute &Attr,
+ SPIRV::ExecutionMode::ExecutionMode EM) {
+ assert(Attr.isValid() && "Function called with an invalid attribute.");
+
+ MCInst Inst;
+ Inst.setOpcode(SPIRV::OpExecutionMode);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
+
+ SmallVector<StringRef> NumThreads;
+ Attr.getValueAsString().split(NumThreads, ',');
+ assert(NumThreads.size() == 3 && "invalid numthreads");
+ for (uint32_t i = 0; i < 3; ++i) {
+ uint32_t V;
+ [[maybe_unused]] bool Result = NumThreads[i].getAsInteger(10, V);
+ assert(!Result && "Failed to parse numthreads");
+ Inst.addOperand(MCOperand::createImm(V));
+ }
+
+ outputMCInst(Inst);
+}
+
void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
if (Node) {
@@ -431,6 +457,9 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
if (MDNode *Node = F.getMetadata("reqd_work_group_size"))
outputExecutionModeFromMDNode(FReg, Node,
SPIRV::ExecutionMode::LocalSize);
+ if (Attribute Attr = F.getFnAttribute("hlsl.numthreads"); Attr.isValid())
+ outputExecutionModeFromNumthreadsAttribute(
+ FReg, Attr, SPIRV::ExecutionMode::LocalSize);
if (MDNode *Node = F.getMetadata("work_group_size_hint"))
outputExecutionModeFromMDNode(FReg, Node,
SPIRV::ExecutionMode::LocalSizeHint);
@@ -447,7 +476,7 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
Inst.addOperand(MCOperand::createImm(TypeCode));
outputMCInst(Inst);
}
- if (!M.getNamedMetadata("spirv.ExecutionMode") &&
+ if (ST->isOpenCLEnv() && !M.getNamedMetadata("spirv.ExecutionMode") &&
!M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
MCInst Inst;
Inst.setOpcode(SPIRV::OpExecutionMode);
@@ -542,4 +571,5 @@ bool SPIRVAsmPrinter::doInitialization(Module &M) {
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() {
RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target());
RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target());
+ RegisterAsmPrinter<SPIRVAsmPrinter> Z(getTheSPIRVLogicalTarget());
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 47b25a1f8351595..cae7c0e9ac5b8ac 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -213,6 +213,38 @@ static Type *getArgType(const Function &F, unsigned ArgIdx) {
: StructType::create(F.getContext(), KernelArgTypeStr);
}
+static bool isEntryPoint(const Function &F) {
+ // OpenCL handling: any function with the SPIR_KERNEL
+ // calling convention will be a potential entry point.
+ if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
+ return true;
+
+ // HLSL handling: special attribute are emitted from the
+ // front-end.
+ if (F.getFnAttribute("hlsl.shader").isValid())
+ return true;
+
+ return false;
+}
+
+static SPIRV::ExecutionModel::ExecutionModel
+getExecutionModel(const SPIRVSubtarget &STI, const Function &F) {
+ if (STI.isOpenCLEnv())
+ return SPIRV::ExecutionModel::Kernel;
+
+ 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.");
+}
+
bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
const Function &F,
ArrayRef<ArrayRef<Register>> VRegs,
@@ -336,9 +368,11 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
buildOpName(FuncVReg, F.getName(), MIRBuilder);
// Handle entry points and function linkage.
- if (F.getCallingConv() == CallingConv::SPIR_KERNEL) {
+ if (isEntryPoint(F)) {
+ const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
+ auto executionModel = getExecutionModel(STI, F);
auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint)
- .addImm(static_cast<uint32_t>(SPIRV::ExecutionModel::Kernel))
+ .addImm(static_cast<uint32_t>(executionModel))
.addUse(FuncVReg);
addStringImm(F.getName(), MIB);
} else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage ||
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index c3fc255e4b3df14..89f198b8af52397 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -106,11 +106,18 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
MAI.Mem =
static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1));
} else {
- MAI.Mem = SPIRV::MemoryModel::OpenCL;
- unsigned PtrSize = ST->getPointerSize();
- MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
- : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
- : SPIRV::AddressingModel::Logical;
+ // TODO: Add support for VulkanMemoryModel.
+ MAI.Mem = ST->isOpenCLEnv() ? SPIRV::MemoryModel::OpenCL
+ : SPIRV::MemoryModel::GLSL450;
+ if (MAI.Mem == SPIRV::MemoryModel::OpenCL) {
+ unsigned PtrSize = ST->getPointerSize();
+ MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
+ : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
+ : SPIRV::AddressingModel::Logical;
+ } else {
+ // TODO: Add support for PhysicalStorageBufferAddress.
+ MAI.Addr = SPIRV::AddressingModel::Logical;
+ }
}
// Get the OpenCL version number from metadata.
// TODO: support other source languages.
@@ -148,9 +155,12 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
MAI.Addr, *ST);
- // TODO: check if it's required by default.
- MAI.ExtInstSetMap[static_cast<unsigned>(SPIRV::InstructionSet::OpenCL_std)] =
- Register::index2VirtReg(MAI.getNextID());
+ if (ST->isOpenCLEnv()) {
+ // TODO: check if it's required by default.
+ MAI.ExtInstSetMap[static_cast<unsigned>(
+ SPIRV::InstructionSet::OpenCL_std)] =
+ Register::index2VirtReg(MAI.getNextID());
+ }
}
// Collect MI which defines the register in the given machine function.
@@ -516,9 +526,21 @@ void SPIRV::RequirementHandler::addAvailableCaps(const CapabilityList &ToAdd) {
namespace llvm {
namespace SPIRV {
void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
- // TODO: Implemented for other targets other then OpenCL.
- if (!ST.isOpenCLEnv())
+ if (ST.isOpenCLEnv()) {
+ initAvailableCapabilitiesForOpenCL(ST);
+ return;
+ }
+
+ if (ST.isVulkanEnv()) {
+ initAvailableCapabilitiesForVulkan(ST);
return;
+ }
+
+ report_fatal_error("Unimplemented environment for SPIR-V generation.");
+}
+
+void RequirementHandler::initAvailableCapabilitiesForOpenCL(
+ const SPIRVSubtarget &ST) {
// Add the min requirements for
diff erent OpenCL and SPIR-V versions.
addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
Capability::Int16, Capability::Int8, Capability::Kernel,
@@ -558,6 +580,12 @@ void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
// TODO: add OpenCL extensions.
}
+
+void RequirementHandler::initAvailableCapabilitiesForVulkan(
+ const SPIRVSubtarget &ST) {
+ addAvailableCaps({Capability::Shader, Capability::Linkage});
+}
+
} // namespace SPIRV
} // namespace llvm
@@ -890,6 +918,11 @@ static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
MAI.Reqs.getAndAddRequirements(
SPIRV::OperandCategory::ExecutionModeOperand,
SPIRV::ExecutionMode::LocalSize, ST);
+ if (F.getFnAttribute("hlsl.numthreads").isValid()) {
+ MAI.Reqs.getAndAddRequirements(
+ SPIRV::OperandCategory::ExecutionModeOperand,
+ SPIRV::ExecutionMode::LocalSize, ST);
+ }
if (F.getMetadata("work_group_size_hint"))
MAI.Reqs.getAndAddRequirements(
SPIRV::OperandCategory::ExecutionModeOperand,
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
index abb6797c52180c7..b57a5f4c28278ac 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h
@@ -69,6 +69,9 @@ struct RequirementHandler {
// recursing through their implicitly declared capabilities too.
void pruneCapabilities(const CapabilityList &ToPrune);
+ void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST);
+ void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST);
+
public:
RequirementHandler() : MinVersion(0), MaxVersion(0) {}
void clear() {
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
index 05f871a88db0dff..d1d7a31dbaf48c9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
@@ -36,7 +36,15 @@ static unsigned computePointerSize(const Triple &TT) {
const auto Arch = TT.getArch();
// TODO: unify this with pointers legalization.
assert(TT.isSPIRV());
- return Arch == Triple::spirv32 ? 32 : 64;
+
+ if (Arch == Triple::spirv64)
+ return 64;
+
+ // TODO: this probably needs to be revisited:
+ // AFAIU Logical SPIR-V has no pointer size. So falling-back on ID size.
+ // Addressing mode can change how some pointers are handled
+ // (PhysicalStorageBuffer64).
+ return 32;
}
SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU,
@@ -45,7 +53,7 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU,
: SPIRVGenSubtargetInfo(TT, CPU, /*TuneCPU=*/CPU, FS),
PointerSize(computePointerSize(TT)), SPIRVVersion(0), OpenCLVersion(0),
InstrInfo(), FrameLowering(initSubtargetDependencies(CPU, FS)),
- TLInfo(TM, *this) {
+ TLInfo(TM, *this), TargetTriple(TT) {
// The order of initialization is important.
initAvailableExtensions();
initAvailableExtInstSets();
@@ -82,6 +90,8 @@ bool SPIRVSubtarget::isAtLeastSPIRVVer(uint32_t VerToCompareTo) const {
}
bool SPIRVSubtarget::isAtLeastOpenCLVer(uint32_t VerToCompareTo) const {
+ if (!isOpenCLEnv())
+ return false;
return isAtLeastVer(OpenCLVersion, VerToCompareTo);
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index 27286fe98fa783b..f81d7a240480d35 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -25,6 +25,7 @@
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/TargetParser/Triple.h"
#define GET_SUBTARGETINFO_HEADER
#include "SPIRVGenSubtargetInfo.inc"
@@ -46,6 +47,7 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
SPIRVInstrInfo InstrInfo;
SPIRVFrameLowering FrameLowering;
SPIRVTargetLowering TLInfo;
+ Triple TargetTriple;
// GlobalISel related APIs.
std::unique_ptr<CallLowering> CallLoweringInfo;
@@ -71,9 +73,13 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
unsigned getPointerSize() const { return PointerSize; }
bool canDirectlyComparePointers() const;
// TODO: this environment is not implemented in Triple, we need to decide
- // how to standartize its support. For now, let's assume that we always
- // operate with OpenCL.
- bool isOpenCLEnv() const { return true; }
+ // how to standardize its support. For now, let's assume SPIR-V with physical
+ // addressing is OpenCL, and Logical addressing is Vulkan.
+ bool isOpenCLEnv() const {
+ return TargetTriple.getArch() == Triple::spirv32 ||
+ TargetTriple.getArch() == Triple::spirv64;
+ }
+ bool isVulkanEnv() const { return TargetTriple.getArch() == Triple::spirv; }
uint32_t getSPIRVVersion() const { return SPIRVVersion; };
bool isAtLeastSPIRVVer(uint32_t VerToCompareTo) const;
bool isAtLeastOpenCLVer(uint32_t VerToCompareTo) const;
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 6721c60834bdfcb..9ca291bdd5f3568 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -37,6 +37,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
// Register the target.
RegisterTargetMachine<SPIRVTargetMachine> X(getTheSPIRV32Target());
RegisterTargetMachine<SPIRVTargetMachine> Y(getTheSPIRV64Target());
+ RegisterTargetMachine<SPIRVTargetMachine> Z(getTheSPIRVLogicalTarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeGlobalISel(PR);
@@ -45,6 +46,11 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
static std::string computeDataLayout(const Triple &TT) {
const auto Arch = TT.getArch();
+ // TODO: this probably needs to be revisited:
+ // Logical SPIR-V has no pointer size, so any fixed pointer size would be
+ // wrong. The choice to default to 32 or 64 is just motivated by another
+ // memory model used for graphics: PhysicalStorageBuffer64. But it shouldn't
+ // mean anything.
if (Arch == Triple::spirv32)
return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024";
diff --git a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp
index fb7cab4fe779cab..febefc024920499 100644
--- a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp
+++ b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp
@@ -19,10 +19,16 @@ Target &llvm::getTheSPIRV64Target() {
static Target TheSPIRV64Target;
return TheSPIRV64Target;
}
+Target &llvm::getTheSPIRVLogicalTarget() {
+ static Target TheSPIRVLogicalTarget;
+ return TheSPIRVLogicalTarget;
+}
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTargetInfo() {
RegisterTarget<Triple::spirv32> X(getTheSPIRV32Target(), "spirv32",
"SPIR-V 32-bit", "SPIRV");
RegisterTarget<Triple::spirv64> Y(getTheSPIRV64Target(), "spirv64",
"SPIR-V 64-bit", "SPIRV");
+ RegisterTarget<Triple::spirv> Z(getTheSPIRVLogicalTarget(), "spirv",
+ "SPIR-V Logical", "SPIRV");
}
diff --git a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.h b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.h
index 4353258e1d1a9aa..9131b2598a7dfcd 100644
--- a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.h
+++ b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.h
@@ -15,6 +15,7 @@ class Target;
Target &getTheSPIRV32Target();
Target &getTheSPIRV64Target();
+Target &getTheSPIRVLogicalTarget();
} // namespace llvm
diff --git a/llvm/test/CodeGen/SPIRV/ExecutionMode_GLCompute.ll b/llvm/test/CodeGen/SPIRV/ExecutionMode_GLCompute.ll
new file mode 100644
index 000000000000000..9eb4fefb738b829
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/ExecutionMode_GLCompute.ll
@@ -0,0 +1,11 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: OpEntryPoint GLCompute %[[#entry:]] "main"
+; CHECK-DAG: OpExecutionMode %[[#entry]] LocalSize 4 8 16
+
+define void @main() #1 {
+entry:
+ ret void
+}
+
+attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/capability-Shader.ll b/llvm/test/CodeGen/SPIRV/capability-Shader.ll
new file mode 100644
index 000000000000000..76adcd04a127075
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/capability-Shader.ll
@@ -0,0 +1,12 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: OpCapability Shader
+;; Ensure no other capability is listed.
+; CHECK-NOT: OpCapability
+
+define void @main() #1 {
+entry:
+ ret void
+}
+
+attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/empty-logical.ll b/llvm/test/CodeGen/SPIRV/empty-logical.ll
new file mode 100644
index 000000000000000..a99df5f7eaaa71f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/empty-logical.ll
@@ -0,0 +1,9 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+;; Ensure the required Capabilities are listed.
+; CHECK-DAG: OpCapability Shader
+; CHECK-DAG: OpCapability Linkage
+
+;; Ensure one, and only one, OpMemoryModel is defined.
+; CHECK: OpMemoryModel Logical GLSL450
+; CHECK-NOT: OpMemoryModel
More information about the llvm-commits
mailing list