Skip to content
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

[SPIR-V] Improve Tablegen instruction selection and account for a pointer size of the target #88725

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,8 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
auto MRI = MIRBuilder.getMRI();
assert(MRI->getType(ResVReg).isPointer() && "Pointer type is expected");
if (Reg != ResVReg) {
LLT RegLLTy = LLT::pointer(MRI->getType(ResVReg).getAddressSpace(), 32);
LLT RegLLTy =
LLT::pointer(MRI->getType(ResVReg).getAddressSpace(), getPointerSize());
MRI->setType(Reg, RegLLTy);
assignSPIRVTypeToVReg(BaseType, Reg, MIRBuilder.getMF());
} else {
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,10 @@ void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,

bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID ||
MI.getOpcode() == SPIRV::GET_pID || MI.getOpcode() == SPIRV::GET_vfID ||
MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID) {
MI.getOpcode() == SPIRV::GET_pID32 ||
MI.getOpcode() == SPIRV::GET_pID64 || MI.getOpcode() == SPIRV::GET_vfID ||
MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID32 ||
MI.getOpcode() == SPIRV::GET_vpID64) {
auto &MRI = MI.getMF()->getRegInfo();
MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
MI.eraseFromParent();
Expand Down
18 changes: 12 additions & 6 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ let isCodeGenOnly=1 in {
def DECL_TYPE: Pseudo<(outs ANYID:$dst_id), (ins ANYID:$src_id, TYPE:$src_ty)>;
def GET_ID: Pseudo<(outs ID:$dst_id), (ins ANYID:$src)>;
def GET_fID: Pseudo<(outs fID:$dst_id), (ins ANYID:$src)>;
def GET_pID: Pseudo<(outs pID:$dst_id), (ins ANYID:$src)>;
def GET_pID32: Pseudo<(outs pID32:$dst_id), (ins ANYID:$src)>;
def GET_pID64: Pseudo<(outs pID64:$dst_id), (ins ANYID:$src)>;
def GET_vID: Pseudo<(outs vID:$dst_id), (ins ANYID:$src)>;
def GET_vfID: Pseudo<(outs vfID:$dst_id), (ins ANYID:$src)>;
def GET_vpID: Pseudo<(outs vpID:$dst_id), (ins ANYID:$src)>;
def GET_vpID32: Pseudo<(outs vpID32:$dst_id), (ins ANYID:$src)>;
def GET_vpID64: Pseudo<(outs vpID64:$dst_id), (ins ANYID:$src)>;
}

def SPVTypeBin : SDTypeProfile<1, 2, []>;
Expand Down Expand Up @@ -66,8 +68,10 @@ multiclass TernOpTypedGen<string name, bits<16> opCode, SDNode node, bit genP =
def SIVCond: TernOpTyped<name, opCode, vID, ID, node>;
}
if genP then {
def SPSCond: TernOpTyped<name, opCode, ID, pID, node>;
def SPVCond: TernOpTyped<name, opCode, vID, pID, node>;
def SPSCond32: TernOpTyped<name, opCode, ID, pID32, node>;
def SPVCond32: TernOpTyped<name, opCode, vID, pID32, node>;
def SPSCond64: TernOpTyped<name, opCode, ID, pID64, node>;
def SPVCond64: TernOpTyped<name, opCode, vID, pID64, node>;
}
if genV then {
if genF then {
Expand All @@ -79,8 +83,10 @@ multiclass TernOpTypedGen<string name, bits<16> opCode, SDNode node, bit genP =
def VIVCond: TernOpTyped<name, opCode, vID, vID, node>;
}
if genP then {
def VPSCond: TernOpTyped<name, opCode, ID, vpID, node>;
def VPVCond: TernOpTyped<name, opCode, vID, vpID, node>;
def VPSCond32: TernOpTyped<name, opCode, ID, vpID32, node>;
def VPVCond32: TernOpTyped<name, opCode, vID, vpID32, node>;
def VPSCond64: TernOpTyped<name, opCode, ID, vpID64, node>;
def VPVCond64: TernOpTyped<name, opCode, vID, vpID64, node>;
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,18 @@ bool SPIRVInstructionSelector::select(MachineInstr &I) {
// If it's not a GMIR instruction, we've selected it already.
if (!isPreISelGenericOpcode(Opcode)) {
if (Opcode == SPIRV::ASSIGN_TYPE) { // These pseudos aren't needed any more.
auto *Def = MRI->getVRegDef(I.getOperand(1).getReg());
Register DstReg = I.getOperand(0).getReg();
Register SrcReg = I.getOperand(1).getReg();
auto *Def = MRI->getVRegDef(SrcReg);
if (isTypeFoldingSupported(Def->getOpcode())) {
if (MRI->getType(DstReg).isPointer())
MRI->setType(DstReg, LLT::scalar(32));
bool Res = selectImpl(I, *CoverageInfo);
assert(Res || Def->getOpcode() == TargetOpcode::G_CONSTANT);
if (Res)
return Res;
}
MRI->replaceRegWith(I.getOperand(1).getReg(), I.getOperand(0).getReg());
MRI->replaceRegWith(SrcReg, DstReg);
I.removeFromParent();
return true;
} else if (I.getNumDefs() == 1) {
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,

static bool isMetaInstrGET(unsigned Opcode) {
return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_fID ||
Opcode == SPIRV::GET_pID || Opcode == SPIRV::GET_vID ||
Opcode == SPIRV::GET_vfID || Opcode == SPIRV::GET_vpID;
Opcode == SPIRV::GET_pID32 || Opcode == SPIRV::GET_pID64 ||
Opcode == SPIRV::GET_vID || Opcode == SPIRV::GET_vfID ||
Opcode == SPIRV::GET_vpID32 || Opcode == SPIRV::GET_vpID64;
}

static bool mayBeInserted(unsigned Opcode) {
Expand Down
62 changes: 45 additions & 17 deletions llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,12 @@ static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR,
}

static std::pair<Register, unsigned>
createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI,
createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI,
const SPIRVGlobalRegistry &GR) {
LLT NewT = LLT::scalar(32);
SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg);
if (!SpvType)
SpvType = GR.getSPIRVTypeForVReg(SrcReg);
assert(SpvType && "VReg is expected to have SPIRV type");
LLT NewT = LLT::scalar(32);
bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;
bool IsVectorFloat =
SpvType->getOpcode() == SPIRV::OpTypeVector &&
Expand All @@ -236,14 +237,38 @@ createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI,
IsFloat |= IsVectorFloat;
auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
if (MRI.getType(ValReg).isPointer()) {
NewT = LLT::pointer(0, 32);
GetIdOp = SPIRV::GET_pID;
DstClass = &SPIRV::pIDRegClass;
} else if (MRI.getType(ValReg).isVector()) {
if (MRI.getType(SrcReg).isPointer()) {
unsigned PtrSz = GR.getPointerSize();
NewT = LLT::pointer(0, PtrSz);
bool IsVec = MRI.getType(SrcReg).isVector();
if (IsVec)
NewT = LLT::fixed_vector(2, NewT);
if (PtrSz == 64) {
if (IsVec) {
GetIdOp = SPIRV::GET_vpID64;
DstClass = &SPIRV::vpID64RegClass;
} else {
GetIdOp = SPIRV::GET_pID64;
DstClass = &SPIRV::pID64RegClass;
}
} else {
if (IsVec) {
GetIdOp = SPIRV::GET_vpID32;
DstClass = &SPIRV::vpID32RegClass;
} else {
GetIdOp = SPIRV::GET_pID32;
DstClass = &SPIRV::pID32RegClass;
}
}
} else if (MRI.getType(SrcReg).isVector()) {
NewT = LLT::fixed_vector(2, NewT);
GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID;
DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass;
if (IsFloat) {
GetIdOp = SPIRV::GET_vfID;
DstClass = &SPIRV::vfIDRegClass;
} else {
GetIdOp = SPIRV::GET_vID;
DstClass = &SPIRV::vIDRegClass;
}
}
Register IdReg = MRI.createGenericVirtualRegister(NewT);
MRI.setRegClass(IdReg, DstClass);
Expand All @@ -264,14 +289,14 @@ Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
MIB.setInsertPt(*Def->getParent(),
(Def->getNextNode() ? Def->getNextNode()->getIterator()
: Def->getParent()->end()));
SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
if (auto *RC = MRI.getRegClassOrNull(Reg)) {
MRI.setRegClass(NewReg, RC);
} else {
MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
MRI.setRegClass(Reg, &SPIRV::IDRegClass);
}
SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);
GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());
// This is to make it convenient for Legalizer to get the SPIRVType
// when processing the actual MI (i.e. not pseudo one).
Expand All @@ -290,11 +315,11 @@ Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,

void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) {
unsigned Opc = MI.getOpcode();
assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));
MachineInstr &AssignTypeInst =
*(MRI.use_instr_begin(MI.getOperand(0).getReg()));
auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first;
auto NewReg =
createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;
AssignTypeInst.getOperand(1).setReg(NewReg);
MI.getOperand(0).setReg(NewReg);
MIB.setInsertPt(*MI.getParent(),
Expand All @@ -303,7 +328,7 @@ void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
for (auto &Op : MI.operands()) {
if (!Op.isReg() || Op.isDef())
continue;
auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR);
auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);
MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());
Op.setReg(IdOpInfo.first);
}
Expand Down Expand Up @@ -419,6 +444,7 @@ static void processInstrsWithTypeFolding(MachineFunction &MF,
processInstr(MI, MIB, MRI, GR);
}
}

for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
// We need to rewrite dst types for ASSIGN_TYPE instrs to be able
Expand All @@ -431,16 +457,18 @@ static void processInstrsWithTypeFolding(MachineFunction &MF,
if (!isTypeFoldingSupported(Opcode))
continue;
Register DstReg = MI.getOperand(0).getReg();
if (MRI.getType(DstReg).isVector())
bool IsDstPtr = MRI.getType(DstReg).isPointer();
if (IsDstPtr || MRI.getType(DstReg).isVector())
MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
// Don't need to reset type of register holding constant and used in
// G_ADDRSPACE_CAST, since it braaks legalizer.
// G_ADDRSPACE_CAST, since it breaks legalizer.
if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {
MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);
if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
continue;
}
MRI.setType(DstReg, LLT::scalar(32));
MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())
: LLT::scalar(32));
}
}
}
Expand Down
20 changes: 2 additions & 18 deletions llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,7 @@ using namespace llvm;
const RegisterBank &
SPIRVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
LLT Ty) const {
switch (RC.getID()) {
case SPIRV::TYPERegClassID:
if (RC.getID() == SPIRV::TYPERegClassID)
return SPIRV::TYPERegBank;
case SPIRV::pIDRegClassID:
case SPIRV::IDRegClassID:
return SPIRV::IDRegBank;
case SPIRV::fIDRegClassID:
return SPIRV::fIDRegBank;
case SPIRV::vIDRegClassID:
return SPIRV::vIDRegBank;
case SPIRV::vfIDRegClassID:
return SPIRV::vfIDRegBank;
case SPIRV::vpIDRegClassID:
return SPIRV::vpIDRegBank;
case SPIRV::ANYIDRegClassID:
case SPIRV::ANYRegClassID:
return SPIRV::IDRegBank;
}
llvm_unreachable("Unknown register class");
return SPIRV::IDRegBank;
}
7 changes: 2 additions & 5 deletions llvm/lib/Target/SPIRV/SPIRVRegisterBanks.td
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

// Although RegisterBankSelection is disabled we need to distinct the banks
// as InstructionSelector RegClass checking code relies on them
def IDRegBank : RegisterBank<"IDBank", [ID]>;
def fIDRegBank : RegisterBank<"fIDBank", [fID]>;
def vIDRegBank : RegisterBank<"vIDBank", [vID]>;
def vfIDRegBank : RegisterBank<"vfIDBank", [vfID]>;
def vpIDRegBank : RegisterBank<"vpIDBank", [vpID]>;

def TYPERegBank : RegisterBank<"TYPEBank", [TYPE]>;
def IDRegBank : RegisterBank<"IDBank", [ID, fID, pID32, pID64, vID, vfID, vpID32, vpID64]>;
49 changes: 28 additions & 21 deletions llvm/lib/Target/SPIRV/SPIRVRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,46 @@
//===----------------------------------------------------------------------===//

let Namespace = "SPIRV" in {
def p0 : PtrValueType <i32, 0>;

class P0Vec<ValueType scalar>
: PtrValueType <scalar, 0> {
let nElem = 2;
let ElementType = p0;
let isInteger = false;
let isFP = false;
let isVector = true;
// Pointer types for patterns with the GlobalISelEmitter
def p32 : PtrValueType <i32, 0>;
def p64 : PtrValueType <i64, 0>;

class VTPtrVec<int nelem, PtrValueType ptr>
: VTVec<nelem, ValueType<ptr.Size, ptr.Value>, ptr.Value> {
int isPointer = true;
}

def v2p0 : P0Vec<i32>;
// All registers are for 32-bit identifiers, so have a single dummy register
def v2p32 : VTPtrVec<2, p32>;
def v2p64 : VTPtrVec<2, p64>;

// Class for registers that are the result of OpTypeXXX instructions
// Class for type registers
def TYPE0 : Register<"TYPE0">;
def TYPE : RegisterClass<"SPIRV", [i32], 32, (add TYPE0)>;

// Class for every other non-type ID
// Class for non-type registers
def ID0 : Register<"ID0">;
def ID : RegisterClass<"SPIRV", [i32], 32, (add ID0)>;
def fID0 : Register<"fID0">;
def fID : RegisterClass<"SPIRV", [f32], 32, (add fID0)>;
def pID0 : Register<"pID0">;
def pID : RegisterClass<"SPIRV", [p0], 32, (add pID0)>;
def pID320 : Register<"pID320">;
def pID640 : Register<"pID640">;
def vID0 : Register<"vID0">;
def vID : RegisterClass<"SPIRV", [v2i32], 32, (add vID0)>;
def vfID0 : Register<"vfID0">;
def vpID320 : Register<"vpID320">;
def vpID640 : Register<"vpID640">;

def ID : RegisterClass<"SPIRV", [i32], 32, (add ID0)>;
def fID : RegisterClass<"SPIRV", [f32], 32, (add fID0)>;
def pID32 : RegisterClass<"SPIRV", [p32], 32, (add pID320)>;
def pID64 : RegisterClass<"SPIRV", [p64], 32, (add pID640)>;
def vID : RegisterClass<"SPIRV", [v2i32], 32, (add vID0)>;
def vfID : RegisterClass<"SPIRV", [v2f32], 32, (add vfID0)>;
def vpID0 : Register<"vpID0">;
def vpID : RegisterClass<"SPIRV", [v2p0], 32, (add vpID0)>;
def vpID32 : RegisterClass<"SPIRV", [v2p32], 32, (add vpID320)>;
def vpID64 : RegisterClass<"SPIRV", [v2p64], 32, (add vpID640)>;

def ANYID : RegisterClass<"SPIRV", [i32, f32, p0, v2i32, v2f32], 32, (add ID, fID, pID, vID, vfID)>;
def ANYID : RegisterClass<
"SPIRV",
[i32, f32, p32, p64, v2i32, v2f32, v2p32, v2p64],
32,
(add ID0, fID0, pID320, pID640, vID0, vfID0, vpID320, vpID640)>;

// A few instructions like OpName can take ids from both type and non-type
// instructions, so we need a super-class to allow for both to count as valid
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/CodeGen/SPIRV/instructions/select-phi.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s

; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --translator-compatibility-mode %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --translator-compatibility-mode %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-DAG: %[[Char:.*]] = OpTypeInt 8 0
; CHECK-DAG: %[[Long:.*]] = OpTypeInt 32 0
Expand Down
25 changes: 25 additions & 0 deletions llvm/test/CodeGen/SPIRV/instructions/select-ptr-load.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-SPIRV-DAG: %[[Float:.*]] = OpTypeFloat 32
; CHECK-SPIRV-DAG: %[[FloatPtr:.*]] = OpTypePointer Function %[[Float]]
; CHECK-SPIRV: OpInBoundsPtrAccessChain %[[FloatPtr]]
; CHECK-SPIRV: OpInBoundsPtrAccessChain %[[FloatPtr]]
; CHECK-SPIRV: OpSelect %[[FloatPtr]]
; CHECK-SPIRV: OpLoad %[[Float]]

%struct = type { [3 x float] }

define spir_kernel void @bar(i1 %sw) {
entry:
%var1 = alloca %struct
%var2 = alloca %struct
%elem1 = getelementptr inbounds [3 x float], ptr %var1, i64 0, i64 0
%elem2 = getelementptr inbounds [3 x float], ptr %var2, i64 0, i64 1
%elem = select i1 %sw, ptr %elem1, ptr %elem2
%res = load float, ptr %elem
ret void
}
3 changes: 3 additions & 0 deletions llvm/test/CodeGen/SPIRV/instructions/select.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-DAG: OpName [[SCALARi32:%.+]] "select_i32"
; CHECK-DAG: OpName [[SCALARPTR:%.+]] "select_ptr"
; CHECK-DAG: OpName [[VEC2i32:%.+]] "select_i32v2"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}

; CHECK-SPIRV: OpSelect

Expand Down
Loading