[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