Skip to content

[MachineVerifier] Query TargetInstrInfo for PHI nodes. #110507

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

Closed
wants to merge 6 commits into from
Closed
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
26 changes: 26 additions & 0 deletions llvm/include/llvm/CodeGen/TargetInstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2278,6 +2278,32 @@ class TargetInstrInfo : public MCInstrInfo {
llvm_unreachable("unknown number of operands necessary");
}

// Returns true if this instruction is a PHI node.
// This function should be favored over MI.isPHI() as it allows backends to
// report actual PHI instructions in their ISA as such.
virtual bool isPhiInstr(const MachineInstr &MI) const {
return MI.getOpcode() == TargetOpcode::G_PHI ||
MI.getOpcode() == TargetOpcode::PHI;
}

// Returns the number of [Value, Src] pairs this phi instruction has.
// Only valid to call on a phi node.
virtual unsigned getNumPhiIncomingPair(const MachineInstr &MI) const {
assert(isPhiInstr(MI));
// G_PHI/PHI only have a single operand before the pairs. 2 Operands per
// pair.
return (MI.getNumOperands() - 1) >> 1;
}

// Returns the |index|'th [Value, Src] pair of this phi instruction.
virtual std::pair<MachineOperand, MachineBasicBlock *>
getPhiIncomingPair(const MachineInstr &MI, unsigned index) const {
// Behavior for G_PHI/PHI instructions.
MachineOperand Operand = MI.getOperand(index * 2 + 1);
MachineBasicBlock *MBB = MI.getOperand(index * 2 + 2).getMBB();
return {Operand, MBB};
}

private:
mutable std::unique_ptr<MIRFormatter> Formatter;
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;
Expand Down
33 changes: 19 additions & 14 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2231,7 +2231,7 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
if (MI->getFlag(MachineInstr::NoConvergent) && !MCID.isConvergent())
report("NoConvergent flag expected only on convergent instructions.", MI);

if (MI->isPHI()) {
if (TII->isPhiInstr(*MI)) {
if (MF->getProperties().hasProperty(
MachineFunctionProperties::Property::NoPHIs))
report("Found PHI instruction with NoPHIs property set", MI);
Expand Down Expand Up @@ -2734,7 +2734,7 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) {
break;

case MachineOperand::MO_MachineBasicBlock:
if (MI->isPHI() && !MO->getMBB()->isSuccessor(MI->getParent()))
if (TII->isPhiInstr(*MI) && !MO->getMBB()->isSuccessor(MI->getParent()))
report("PHI operand is not in the CFG", MO, MONum);
break;

Expand Down Expand Up @@ -2805,7 +2805,7 @@ void MachineVerifier::checkLivenessAtUse(const MachineOperand *MO,
}

LiveQueryResult LRQ = LR.Query(UseIdx);
bool HasValue = LRQ.valueIn() || (MI->isPHI() && LRQ.valueOut());
bool HasValue = LRQ.valueIn() || (TII->isPhiInstr(*MI) && LRQ.valueOut());
// Check if we have a segment at the use, note however that we only need one
// live subregister range, the others may be dead.
if (!HasValue && LaneMask.none()) {
Expand Down Expand Up @@ -2924,7 +2924,7 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
// Check LiveInts liveness and kill.
if (LiveInts && !LiveInts->isNotInMIMap(*MI)) {
SlotIndex UseIdx;
if (MI->isPHI()) {
if (TII->isPhiInstr(*MI)) {
// PHI use occurs on the edge, so check for live out here instead.
UseIdx = LiveInts->getMBBEndIdx(
MI->getOperand(MONum + 1).getMBB()).getPrevSlot();
Expand Down Expand Up @@ -2955,7 +2955,7 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
continue;
checkLivenessAtUse(MO, MONum, UseIdx, SR, Reg, SR.LaneMask);
LiveQueryResult LRQ = SR.Query(UseIdx);
if (LRQ.valueIn() || (MI->isPHI() && LRQ.valueOut()))
if (LRQ.valueIn() || (TII->isPhiInstr(*MI) && LRQ.valueOut()))
LiveInMask |= SR.LaneMask;
}
// At least parts of the register has to be live at the use.
Expand All @@ -2965,7 +2965,7 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
report_context(UseIdx);
}
// For PHIs all lanes should be live
if (MI->isPHI() && LiveInMask != MOMask) {
if (TII->isPhiInstr(*MI) && LiveInMask != MOMask) {
report("Not all lanes of PHI source live at use", MO, MONum);
report_context(*LI);
report_context(UseIdx);
Expand Down Expand Up @@ -3016,7 +3016,7 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
// must be live in. PHI instructions are handled separately.
if (MInfo.regsKilled.count(Reg))
report("Using a killed virtual register", MO, MONum);
else if (!MI->isPHI())
else if (!TII->isPhiInstr(*MI))
MInfo.vregsLiveIn.insert(std::make_pair(Reg, MI));
}
}
Expand Down Expand Up @@ -3240,17 +3240,22 @@ void MachineVerifier::calcRegsRequired() {
todo.insert(Pred);
}

// Handle the PHI node.
for (const MachineInstr &MI : MBB.phis()) {
for (unsigned i = 1, e = MI.getNumOperands(); i != e; i += 2) {
// Handle the PHI nodes.
// Note: MBB.phis() only returns range containing PHI/G_PHI instructions.
// MachineVerifier checks MIR post-ISel, and some target ISA can have actual
// PHI instructions that would be missed in MBB.phis() (e.g. SPIR-V).
for (const MachineInstr &MI : MBB) {
// PHI nodes must be the first instructions of the MBB.
if (!TII->isPhiInstr(MI))
break;
for (unsigned i = 0; i < TII->getNumPhiIncomingPair(MI); ++i) {
auto [Op, Pred] = TII->getPhiIncomingPair(MI, i);
// Skip those Operands which are undef regs or not regs.
if (!MI.getOperand(i).isReg() || !MI.getOperand(i).readsReg())
if (!Op.isReg() || !Op.readsReg())
continue;

// Get register and predecessor for one PHI edge.
Register Reg = MI.getOperand(i).getReg();
const MachineBasicBlock *Pred = MI.getOperand(i + 1).getMBB();

Register Reg = Op.getReg();
BBInfo &PInfo = MBBInfoMap[Pred];
if (PInfo.addRequired(Reg))
todo.insert(Pred);
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,27 @@ bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
}
return false;
}

// The SPIR-V backends can emit the OpPhi instruction.
bool SPIRVInstrInfo::isPhiInstr(const MachineInstr &MI) const {
return TargetInstrInfo::isPhiInstr(MI) || MI.getOpcode() == SPIRV::OpPhi;
}

unsigned SPIRVInstrInfo::getNumPhiIncomingPair(const MachineInstr &MI) const {
// OpPhi has 2 operands before the [Value, Src] pairs.
if (MI.getOpcode() == SPIRV::OpPhi)
return (MI.getNumOperands() - 2) >> 1;
return TargetInstrInfo::getNumPhiIncomingPair(MI);
}

std::pair<MachineOperand, MachineBasicBlock *>
SPIRVInstrInfo::getPhiIncomingPair(const MachineInstr &MI,
unsigned index) const {
if (MI.getOpcode() != SPIRV::OpPhi)
return TargetInstrInfo::getPhiIncomingPair(MI, index);

// Skip the first 2 operands (dst, type), and access each [Value, Src] pairs.
MachineOperand Operand = MI.getOperand(index * 2 + 2);
MachineBasicBlock *MBB = MI.getOperand(index * 2 + 3).getMBB();
return {Operand, MBB};
}
5 changes: 5 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ class SPIRVInstrInfo : public SPIRVGenInstrInfo {
bool KillSrc, bool RenamableDest = false,
bool RenamableSrc = false) const override;
bool expandPostRAPseudo(MachineInstr &MI) const override;

bool isPhiInstr(const MachineInstr &MI) const override;
unsigned getNumPhiIncomingPair(const MachineInstr &MI) const override;
std::pair<MachineOperand, MachineBasicBlock *>
getPhiIncomingPair(const MachineInstr &MI, unsigned index) const override;
};

namespace SPIRV {
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/SPIRV/branching/if-merging.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -verify-machineinstrs | FileCheck %s

;; NOTE: This does not check for structured control-flow operations.

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/SPIRV/llvm-intrinsics/memset.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -verify-machineinstrs | FileCheck %s

; CHECK-DAG: OpDecorate %[[#Memset_p0i32:]] LinkageAttributes "spirv.llvm_memset_p0_i32" Export
; CHECK-DAG: OpDecorate %[[#Memset_p3i32:]] LinkageAttributes "spirv.llvm_memset_p3_i32" Export
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/SPIRV/optimizations/add-check-overflow.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
; in the special case when those intrinsics are being generated by the CodeGenPrepare;
; pass during translations with optimization (note -O3 in llc arguments).

; RUN: llc -O3 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
; RUN: llc -O3 -mtriple=spirv32-unknown-unknown %s -o - -verify-machineinstrs | FileCheck %s
; RUN: %if spirv-tools %{ llc -O3 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}

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

; CHECK-DAG: OpName %[[Val:.*]] "math"
Expand Down
10 changes: 5 additions & 5 deletions llvm/test/CodeGen/SPIRV/passes/translate-aggregate-uaddo.ll
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
; This test shows how value attributes are being passed during different translation steps.
; See also test/CodeGen/SPIRV/optimizations/add-check-overflow.ll.

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=prepare-functions 2>&1 | FileCheck %s --check-prefix=CHECK-PREPARE
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=prepare-functions 2>&1 -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-PREPARE
; Intrinsics with aggregate return type are not substituted/removed.
; CHECK-PREPARE: @llvm.uadd.with.overflow.i32

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=emit-intrinsics 2>&1 | FileCheck %s --check-prefix=CHECK-IR
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=emit-intrinsics 2>&1 -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-IR
; Aggregate data are wrapped into @llvm.fake.use(),
; and their attributes are packed into a metadata for @llvm.spv.value.md().
; CHECK-IR: %[[R1:.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32
Expand All @@ -18,20 +18,20 @@
; Origin data type of the value.
; CHECK-IR: !1 = !{{[{]}}{{[{]}} i32, i1 {{[}]}} poison{{[}]}}

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=irtranslator 2>&1 | FileCheck %s --check-prefix=CHECK-GMIR
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=irtranslator 2>&1 -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-GMIR
; Required info succeeded to get through IRTranslator.
; CHECK-GMIR: %[[phires:.*]]:_(s32) = G_PHI
; CHECK-GMIR: %[[math:.*]]:id(s32), %[[ov:.*]]:_(s1) = G_UADDO %[[phires]]:_, %[[#]]:_
; CHECK-GMIR: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.value.md), !0
; CHECK-GMIR: FAKE_USE %[[math]]:id(s32), %[[ov]]:_(s1)

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=spirv-prelegalizer 2>&1 | FileCheck %s --check-prefix=CHECK-PRE
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=spirv-prelegalizer 2>&1 -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-PRE
; Internal service instructions are consumed.
; CHECK-PRE: G_UADDO
; CHECK-PRE-NO: llvm.spv.value.md
; CHECK-PRE-NO: FAKE_USE

; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=instruction-select 2>&1 | FileCheck %s --check-prefix=CHECK-ISEL
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -print-after=instruction-select 2>&1 -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-ISEL
; Names and types are restored and correctly encoded. Correct instruction selection is completed.
; CHECK-ISEL-DAG: %[[int32:.*]]:type = OpTypeInt 32, 0
; CHECK-ISEL-DAG: %[[struct:.*]]:type = OpTypeStruct %[[int32]]:type, %[[int32]]:type
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/SPIRV/structurizer/cf.cond-op.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - -verify-machineinstrs | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - -verify-machineinstrs | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}

;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - -verify-machineinstrs | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}

;
Expand Down
39 changes: 26 additions & 13 deletions llvm/test/CodeGen/SPIRV/structurizer/condition-linear.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - -verify-machineinstrs | FileCheck %s --match-full-lines
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}

; NOTE: Many BB have 2 reg2mem registers: one for the register usage moved
; to memory, and a second one just after caused by a PHI node.

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"
target triple = "spirv-unknown-vulkan-compute"

Expand All @@ -26,8 +29,8 @@ entry:
}


; CHECK-DAG: OpName %[[#reg_0:]] "cond.reg2mem"
; CHECK-DAG: OpName %[[#reg_1:]] "cond9.reg2mem"
; CHECK-DAG: OpName %[[#a:]] "a"
; CHECK-DAG: OpName %[[#b:]] "b"

define internal spir_func void @main() #0 {
; CHECK: OpSelectionMerge %[[#cond1_merge:]] None
Expand All @@ -39,21 +42,27 @@ entry:
br i1 true, label %cond1_true, label %cond1_false

; CHECK: %[[#cond1_true]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: %[[#tmp1:]] = OpLoad %[[#]] %[[#a]] Aligned 4
; CHECK: OpStore %[[#tmp2:]] %[[#tmp1]] Aligned 4
; CHECK: %[[#tmp3:]] = OpLoad %[[#]] %[[#tmp2]] Aligned 4
; CHECK: OpStore %[[#r2m:]] %[[#tmp3]] Aligned 4
; CHECK: OpBranch %[[#cond1_merge]]
cond1_true:
%2 = load i32, ptr %a, align 4
br label %cond1_merge

; CHECK: %[[#cond1_false]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: %[[#tmp1:]] = OpLoad %[[#]] %[[#b]] Aligned 4
; CHECK: OpStore %[[#tmp2:]] %[[#tmp1]] Aligned 4
; CHECK: %[[#tmp3:]] = OpLoad %[[#]] %[[#tmp2]] Aligned 4
; CHECK: OpStore %[[#r2m]] %[[#tmp3]] Aligned 4
; CHECK: OpBranch %[[#cond1_merge]]
cond1_false:
%3 = load i32, ptr %b, align 4
br label %cond1_merge

; CHECK: %[[#cond1_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#reg_0]]
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#r2m]] Aligned 4
; CHECK: %[[#cond:]] = OpINotEqual %[[#]] %[[#tmp]] %[[#]]
; CHECK: OpSelectionMerge %[[#cond2_merge:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#cond2_true:]] %[[#cond2_merge]]
Expand All @@ -69,32 +78,36 @@ cond2_true:
br label %cond2_merge

; CHECK: %[[#cond2_merge]] = OpLabel
; CHECK: OpFunctionCall
; CHECK: %[[#]] = OpFunctionCall %[[#]] %[[#]]
; CHECK: OpSelectionMerge %[[#cond3_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#cond3_true:]] %[[#cond3_false:]]
cond2_merge:
%call2 = call spir_func noundef i32 @fn() #4 [ "convergencectrl"(token %0) ]
br i1 true, label %cond3_true, label %cond3_false

; CHECK: %[[#cond3_true]] = OpLabel
; CHECK: OpFunctionCall
; CHECK: OpStore %[[#reg_1]] %[[#]]
; CHECK: %[[#tmp1:]] = OpFunctionCall %[[#]] %[[#]]
; CHECK: OpStore %[[#tmp2:]] %[[#tmp1]] Aligned 4
; CHECK: %[[#tmp3:]] = OpLoad %[[#]] %[[#tmp2]] Aligned 4
; CHECK: OpStore %[[#r2m2:]] %[[#tmp3]] Aligned 4
; CHECK: OpBranch %[[#cond3_merge]]
cond3_true:
%call5 = call spir_func noundef i32 @fn1() #4 [ "convergencectrl"(token %0) ]
br label %cond3_merge

; CHECK: %[[#cond3_false]] = OpLabel
; CHECK: OpFunctionCall
; CHECK: OpStore %[[#reg_1]] %[[#]]
; CHECK: %[[#tmp1:]] = OpFunctionCall %[[#]] %[[#]]
; CHECK: OpStore %[[#tmp2:]] %[[#tmp1]] Aligned 4
; CHECK: %[[#tmp3:]] = OpLoad %[[#]] %[[#tmp2]] Aligned 4
; CHECK: OpStore %[[#r2m2]] %[[#tmp3]] Aligned 4
; CHECK: OpBranch %[[#cond3_merge]]
cond3_false:
%call7 = call spir_func noundef i32 @fn2() #4 [ "convergencectrl"(token %0) ]
br label %cond3_merge

; CHECK: %[[#cond3_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#reg_1]]
; CHECK: %[[#cond:]] = OpINotEqual %[[#]] %[[#tmp]] %[[#]]
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#r2m2]] Aligned 4
; CHECK: %[[#cond:]] = OpINotEqual %[[#]] %[[#tmp]] %[[#]]
; CHECK: OpSelectionMerge %[[#cond4_merge:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#cond4_true:]] %[[#cond4_merge]]
cond3_merge:
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/SPIRV/transcoding/OpImageReadMS.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-SPIRV

; CHECK-SPIRV: %[[#]] = OpImageRead %[[#]] %[[#]] %[[#]] Sample %[[#]]

Expand Down
2 changes: 2 additions & 0 deletions llvm/test/MachineVerifier/SPIRV/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if not "SPIRV" in config.root.targets:
config.unsupported = True
34 changes: 34 additions & 0 deletions llvm/test/MachineVerifier/SPIRV/verifier-phi-duplicate-pred.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# RUN: llc -o - %s -mtriple=spirv-unknown-vulkan-compute -run-pass=none | FileCheck %s
# REQUIRES: spirv-registered-target

# This should cleanly pass the machine verifier.
# This test validates a subtle SPIR-V difference with PHI nodes:
# It is valid to have the same predecessor present twice in the instruction,
# as long as the associated value is the same.
---
# CHECK-LABEL: name: func0
# CHECK: %7:id = OpPhi %1, %5, %bb.1, %6, %bb.2
name: func0
tracksRegLiveness: true
noPhis: false
body: |
bb.0:
%0:type = OpTypeBool
%1:type = OpTypeInt 32, 0
%2:iid = OpFunctionParameter %1
%3:iid = OpFunctionParameter %1
%4:iid = OpIEqual %0, %2, %3
OpBranchConditional %4, %bb.1, %bb.2

bb.1:
%5:iid = OpLoad %1, %2
OpBranch %bb.3

bb.2:
%6:iid = OpLoad %1, %3
OpBranch %bb.3

bb.3:
%7:id = OpPhi %1, %5, %bb.1, %6, %bb.2, %5, %bb.1
...
---
Loading
Loading