[SPIR-V] Fix BB ordering & register lifetime (#111026)

The "topological" sorting was behaving incorrectly in some cases: 
the exit of a loop could have a lower rank than a node in the loop.
This causes issues when structurizing some patterns, and also codegen
issues as we could generate BBs in the incorrect order in regard to the
SPIR-V spec.

Fixing this ordering alone broke other parts of the structurizer, which
by luck worked. Had to fix those.

Added more test cases, especially to test basic patterns.

I also needed to tweak/disable some tests for 2 reasons:
 - SPIR-V now required reg2mem/mem2reg to run. Meaning dead stores
   are optimized away. Some tests require tweaks to avoid having the
   whole function removed.
 - Mem2Reg will generate variable & load/stores. This generates
   G_BITCAST in several cases. And there is currently something wrong
   we do with G_BITCAST which causes MIR verifier to complain.
   Until this is resolved, I disabled -verify-machineinstrs flag on
   those tests.

---------

Signed-off-by: Nathan Gauër <brioche@google.com>
This commit is contained in:
Nathan Gauër
2024-10-30 14:57:32 +01:00
committed by GitHub
parent 8d406d882d
commit cba70550cc
92 changed files with 1129 additions and 719 deletions

View File

@@ -130,6 +130,13 @@ public:
assert(false && "Unhandled terminator type.");
}
AllocaInst *CreateVariable(Function &F, Type *Type,
BasicBlock::iterator Position) {
const DataLayout &DL = F.getDataLayout();
return new AllocaInst(Type, DL.getAllocaAddrSpace(), nullptr, "reg",
Position);
}
// Run the pass on the given convergence region, ignoring the sub-regions.
// Returns true if the CFG changed, false otherwise.
bool runOnConvergenceRegionNoRecurse(LoopInfo &LI,
@@ -152,6 +159,9 @@ public:
auto NewExitTarget = BasicBlock::Create(F->getContext(), "new.exit", F);
IRBuilder<> Builder(NewExitTarget);
AllocaInst *Variable = CreateVariable(*F, Builder.getInt32Ty(),
F->begin()->getFirstInsertionPt());
// CodeGen output needs to be stable. Using the set as-is would order
// the targets differently depending on the allocation pattern.
// Sorting per basic-block ordering in the function.
@@ -176,18 +186,16 @@ public:
std::vector<std::pair<BasicBlock *, Value *>> ExitToVariable;
for (auto Exit : SortedExits) {
llvm::Value *Value = createExitVariable(Exit, TargetToValue);
IRBuilder<> B2(Exit);
B2.SetInsertPoint(Exit->getFirstInsertionPt());
B2.CreateStore(Value, Variable);
ExitToVariable.emplace_back(std::make_pair(Exit, Value));
}
// Gather the correct value depending on the exit we came from.
llvm::PHINode *node =
Builder.CreatePHI(Builder.getInt32Ty(), ExitToVariable.size());
for (auto [BB, Value] : ExitToVariable) {
node->addIncoming(Value, BB);
}
llvm::Value *Load = Builder.CreateLoad(Builder.getInt32Ty(), Variable);
// Creating the switch to jump to the correct exit target.
llvm::SwitchInst *Sw = Builder.CreateSwitch(node, SortedExitTargets[0],
llvm::SwitchInst *Sw = Builder.CreateSwitch(Load, SortedExitTargets[0],
SortedExitTargets.size() - 1);
for (size_t i = 1; i < SortedExitTargets.size(); i++) {
BasicBlock *BB = SortedExitTargets[i];

View File

@@ -87,7 +87,7 @@ BasicBlock *getExitFor(const ConvergenceRegion *CR) {
// Returns the merge block designated by I if I is a merge instruction, nullptr
// otherwise.
BasicBlock *getDesignatedMergeBlock(Instruction *I) {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
IntrinsicInst *II = dyn_cast_or_null<IntrinsicInst>(I);
if (II == nullptr)
return nullptr;
@@ -102,7 +102,7 @@ BasicBlock *getDesignatedMergeBlock(Instruction *I) {
// Returns the continue block designated by I if I is an OpLoopMerge, nullptr
// otherwise.
BasicBlock *getDesignatedContinueBlock(Instruction *I) {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
IntrinsicInst *II = dyn_cast_or_null<IntrinsicInst>(I);
if (II == nullptr)
return nullptr;
@@ -284,18 +284,6 @@ void replaceBranchTargets(BasicBlock *BB, BasicBlock *OldTarget,
assert(false && "Unhandled terminator type.");
}
// Replaces basic bloc operands |OldSrc| or OpPhi instructions in |BB| by
// |NewSrc|. This function does not simplify the OpPhi instruction once
// transformed.
void replacePhiTargets(BasicBlock *BB, BasicBlock *OldSrc, BasicBlock *NewSrc) {
for (PHINode &Phi : BB->phis()) {
int index = Phi.getBasicBlockIndex(OldSrc);
if (index == -1)
continue;
Phi.setIncomingBlock(index, NewSrc);
}
}
} // anonymous namespace
// Given a reducible CFG, produces a structurized CFG in the SPIR-V sense,
@@ -423,7 +411,7 @@ class SPIRVStructurizer : public FunctionPass {
}
// Splits the given edges by recreating proxy nodes so that the destination
// OpPhi instruction can still be viable.
// has unique incoming edges from this region.
//
// clang-format off
//
@@ -436,66 +424,58 @@ class SPIRVStructurizer : public FunctionPass {
// A -> D -> C
// B -> D -> C
//
// But if C had a phi node, adding such proxy-block breaks it. In such case, we must add 1 new block per
// exit, and patchup the phi node:
// This is fine (assuming C has no PHI nodes), but requires handling the merge instruction here.
// By adding a proxy node, we create a regular divergent shape which can easily be regularized later on.
// A -> D -> D1 -> C
// B -> D -> D2 -> C
//
// A, B, D belongs to the construct. D is the exit. D1 and D2 are empty, just used as
// source operands for C's phi node.
// A, B, D belongs to the construct. D is the exit. D1 and D2 are empty.
//
// clang-format on
std::vector<Edge>
createAliasBlocksForComplexEdges(std::vector<Edge> Edges) {
std::unordered_map<BasicBlock *, BasicBlock *> Seen;
std::unordered_set<BasicBlock *> Seen;
std::vector<Edge> Output;
Output.reserve(Edges.size());
for (auto &[Src, Dst] : Edges) {
auto [iterator, inserted] = Seen.insert({Src, Dst});
if (inserted) {
Output.emplace_back(Src, Dst);
continue;
auto [Iterator, Inserted] = Seen.insert(Src);
if (!Inserted) {
// Src already a source node. Cannot have 2 edges from A to B.
// Creating alias source block.
BasicBlock *NewSrc = BasicBlock::Create(
F.getContext(), Src->getName() + ".new.src", &F);
replaceBranchTargets(Src, Dst, NewSrc);
IRBuilder<> Builder(NewSrc);
Builder.CreateBr(Dst);
Src = NewSrc;
}
// The exact same edge was already seen. Ignoring.
if (iterator->second == Dst)
continue;
// The same Src block branches to 2 distinct blocks. This will be an
// issue for the generated OpPhi. Creating alias block.
BasicBlock *NewSrc =
BasicBlock::Create(F.getContext(), "new.exit.src", &F);
replaceBranchTargets(Src, Dst, NewSrc);
replacePhiTargets(Dst, Src, NewSrc);
IRBuilder<> Builder(NewSrc);
Builder.CreateBr(Dst);
Seen.emplace(NewSrc, Dst);
Output.emplace_back(NewSrc, Dst);
Output.emplace_back(Src, Dst);
}
return Output;
}
AllocaInst *CreateVariable(Function &F, Type *Type,
BasicBlock::iterator Position) {
const DataLayout &DL = F.getDataLayout();
return new AllocaInst(Type, DL.getAllocaAddrSpace(), nullptr, "reg",
Position);
}
// Given a construct defined by |Header|, and a list of exiting edges
// |Edges|, creates a new single exit node, fixing up those edges.
BasicBlock *createSingleExitNode(BasicBlock *Header,
std::vector<Edge> &Edges) {
auto NewExit = BasicBlock::Create(F.getContext(), "new.exit", &F);
IRBuilder<> ExitBuilder(NewExit);
std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges(Edges);
std::vector<BasicBlock *> Dsts;
std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex;
// Given 2 edges: Src1 -> Dst, Src2 -> Dst:
// If Dst has an PHI node, and Src1 and Src2 are both operands, both Src1
// and Src2 cannot be hidden by NewExit. Create 2 new nodes: Alias1,
// Alias2 to which NewExit will branch before going to Dst. Then, patchup
// Dst PHI node to look for Alias1 and Alias2.
std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges(Edges);
auto NewExit = BasicBlock::Create(F.getContext(),
Header->getName() + ".new.exit", &F);
IRBuilder<> ExitBuilder(NewExit);
for (auto &[Src, Dst] : FixedEdges) {
if (DstToIndex.count(Dst) != 0)
continue;
@@ -506,33 +486,34 @@ class SPIRVStructurizer : public FunctionPass {
if (Dsts.size() == 1) {
for (auto &[Src, Dst] : FixedEdges) {
replaceBranchTargets(Src, Dst, NewExit);
replacePhiTargets(Dst, Src, NewExit);
}
ExitBuilder.CreateBr(Dsts[0]);
return NewExit;
}
PHINode *PhiNode =
ExitBuilder.CreatePHI(ExitBuilder.getInt32Ty(), FixedEdges.size());
AllocaInst *Variable = CreateVariable(F, ExitBuilder.getInt32Ty(),
F.begin()->getFirstInsertionPt());
for (auto &[Src, Dst] : FixedEdges) {
PhiNode->addIncoming(DstToIndex[Dst], Src);
IRBuilder<> B2(Src);
B2.SetInsertPoint(Src->getFirstInsertionPt());
B2.CreateStore(DstToIndex[Dst], Variable);
replaceBranchTargets(Src, Dst, NewExit);
replacePhiTargets(Dst, Src, NewExit);
}
llvm::Value *Load =
ExitBuilder.CreateLoad(ExitBuilder.getInt32Ty(), Variable);
// If we can avoid an OpSwitch, generate an OpBranch. Reason is some
// OpBranch are allowed to exist without a new OpSelectionMerge if one of
// the branch is the parent's merge node, while OpSwitches are not.
if (Dsts.size() == 2) {
Value *Condition = ExitBuilder.CreateCmp(CmpInst::ICMP_EQ,
DstToIndex[Dsts[0]], PhiNode);
Value *Condition =
ExitBuilder.CreateCmp(CmpInst::ICMP_EQ, DstToIndex[Dsts[0]], Load);
ExitBuilder.CreateCondBr(Condition, Dsts[0], Dsts[1]);
return NewExit;
}
SwitchInst *Sw =
ExitBuilder.CreateSwitch(PhiNode, Dsts[0], Dsts.size() - 1);
SwitchInst *Sw = ExitBuilder.CreateSwitch(Load, Dsts[0], Dsts.size() - 1);
for (auto It = Dsts.begin() + 1; It != Dsts.end(); ++It) {
Sw->addCase(DstToIndex[*It], *It);
}
@@ -576,7 +557,7 @@ class SPIRVStructurizer : public FunctionPass {
// Creates a new basic block in F with a single OpUnreachable instruction.
BasicBlock *CreateUnreachable(Function &F) {
BasicBlock *BB = BasicBlock::Create(F.getContext(), "new.exit", &F);
BasicBlock *BB = BasicBlock::Create(F.getContext(), "unreachable", &F);
IRBuilder<> Builder(BB);
Builder.CreateUnreachable();
return BB;
@@ -1027,17 +1008,8 @@ class SPIRVStructurizer : public FunctionPass {
return Modified;
}
bool IsRequiredForPhiNode(BasicBlock *BB) {
for (BasicBlock *Successor : successors(BB)) {
for (PHINode &Phi : Successor->phis()) {
if (Phi.getBasicBlockIndex(BB) != -1)
return true;
}
}
return false;
}
// Removes blocks not contributing to any structured CFG. This assumes there
// is no PHI nodes.
bool removeUselessBlocks(Function &F) {
std::vector<BasicBlock *> ToRemove;
@@ -1054,9 +1026,6 @@ class SPIRVStructurizer : public FunctionPass {
if (MergeBlocks.count(&BB) != 0 || ContinueBlocks.count(&BB) != 0)
continue;
if (IsRequiredForPhiNode(&BB))
continue;
if (BB.getUniqueSuccessor() == nullptr)
continue;
@@ -1127,6 +1096,18 @@ class SPIRVStructurizer : public FunctionPass {
continue;
Modified = true;
if (Merge == nullptr) {
Merge = *successors(Header).begin();
IRBuilder<> Builder(Header);
Builder.SetInsertPoint(Header->getTerminator());
auto MergeAddress = BlockAddress::get(Merge->getParent(), Merge);
SmallVector<Value *, 1> Args = {MergeAddress};
Builder.CreateIntrinsic(Intrinsic::spv_selection_merge, {}, {Args});
continue;
}
Instruction *SplitInstruction = Merge->getTerminator();
if (isMergeInstruction(SplitInstruction->getPrevNode()))
SplitInstruction = SplitInstruction->getPrevNode();

View File

@@ -29,6 +29,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar/Reg2Mem.h"
#include "llvm/Transforms/Utils.h"
#include <optional>
@@ -169,13 +170,21 @@ void SPIRVPassConfig::addIRPasses() {
// - loops have a single back-edge.
addPass(createLoopSimplifyPass());
// 2. Merge the convergence region exit nodes into one. After this step,
// 2. Removes registers whose lifetime spans across basic blocks. Also
// removes phi nodes. This will greatly simplify the next steps.
addPass(createRegToMemWrapperPass());
// 3. Merge the convergence region exit nodes into one. After this step,
// regions are single-entry, single-exit. This will help determine the
// correct merge block.
addPass(createSPIRVMergeRegionExitTargetsPass());
// 3. Structurize.
// 4. Structurize.
addPass(createSPIRVStructurizerPass());
// 5. Reduce the amount of variables required by pushing some operations
// back to virtual registers.
addPass(createPromoteMemoryToRegisterPass());
}
addPass(createSPIRVRegularizerPass());

View File

@@ -460,53 +460,98 @@ PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) {
return Output;
}
size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Rank) {
if (Visited.count(BB) != 0)
return Rank;
bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
for (BasicBlock *P : predecessors(BB)) {
// Ignore back-edges.
if (DT.dominates(BB, P))
continue;
Loop *L = LI.getLoopFor(BB);
const bool isLoopHeader = LI.isLoopHeader(BB);
// One of the predecessor hasn't been visited. Not ready yet.
if (BlockToOrder.count(P) == 0)
return false;
if (BlockToOrder.count(BB) == 0) {
OrderInfo Info = {Rank, Visited.size()};
// If the block is a loop exit, the loop must be finished before
// we can continue.
Loop *L = LI.getLoopFor(P);
if (L == nullptr || L->contains(BB))
continue;
// SPIR-V requires a single back-edge. And the backend first
// step transforms loops into the simplified format. If we have
// more than 1 back-edge, something is wrong.
assert(L->getNumBackEdges() <= 1);
// If the loop has no latch, loop's rank won't matter, so we can
// proceed.
BasicBlock *Latch = L->getLoopLatch();
assert(Latch);
if (Latch == nullptr)
continue;
// The latch is not ready yet, let's wait.
if (BlockToOrder.count(Latch) == 0)
return false;
}
return true;
}
size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
size_t result = 0;
for (BasicBlock *P : predecessors(BB)) {
// Ignore back-edges.
if (DT.dominates(BB, P))
continue;
auto Iterator = BlockToOrder.end();
Loop *L = LI.getLoopFor(P);
BasicBlock *Latch = L ? L->getLoopLatch() : nullptr;
// If the predecessor is either outside a loop, or part of
// the same loop, simply take its rank + 1.
if (L == nullptr || L->contains(BB) || Latch == nullptr) {
Iterator = BlockToOrder.find(P);
} else {
// Otherwise, take the loop's rank (highest rank in the loop) as base.
// Since loops have a single latch, highest rank is easy to find.
// If the loop has no latch, then it doesn't matter.
Iterator = BlockToOrder.find(Latch);
}
assert(Iterator != BlockToOrder.end());
result = std::max(result, Iterator->second.Rank + 1);
}
return result;
}
size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
ToVisit.push(BB);
Queued.insert(BB);
while (ToVisit.size() != 0) {
BasicBlock *BB = ToVisit.front();
ToVisit.pop();
if (!CanBeVisited(BB)) {
ToVisit.push(BB);
continue;
}
size_t Rank = GetNodeRank(BB);
OrderInfo Info = {Rank, BlockToOrder.size()};
BlockToOrder.emplace(BB, Info);
} else {
BlockToOrder[BB].Rank = std::max(BlockToOrder[BB].Rank, Rank);
}
for (BasicBlock *Predecessor : predecessors(BB)) {
if (isLoopHeader && L->contains(Predecessor)) {
continue;
}
if (BlockToOrder.count(Predecessor) == 0) {
return Rank;
for (BasicBlock *S : successors(BB)) {
if (Queued.count(S) != 0)
continue;
ToVisit.push(S);
Queued.insert(S);
}
}
Visited.insert(BB);
SmallVector<BasicBlock *, 2> OtherSuccessors;
SmallVector<BasicBlock *, 2> LoopSuccessors;
for (BasicBlock *Successor : successors(BB)) {
// Ignoring back-edges.
if (DT.dominates(Successor, BB))
continue;
if (isLoopHeader && L->contains(Successor)) {
LoopSuccessors.push_back(Successor);
} else
OtherSuccessors.push_back(Successor);
}
for (BasicBlock *BB : LoopSuccessors)
Rank = std::max(Rank, visit(BB, Rank + 1));
size_t OutputRank = Rank;
for (BasicBlock *Item : OtherSuccessors)
OutputRank = std::max(OutputRank, visit(Item, Rank + 1));
return OutputRank;
return 0;
}
PartialOrderingVisitor::PartialOrderingVisitor(Function &F) {

View File

@@ -18,6 +18,7 @@
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/TypedPointerType.h"
#include <queue>
#include <string>
#include <unordered_set>
@@ -62,7 +63,9 @@ class SPIRVSubtarget;
class PartialOrderingVisitor {
DomTreeBuilder::BBDomTree DT;
LoopInfo LI;
std::unordered_set<BasicBlock *> Visited = {};
std::unordered_set<BasicBlock *> Queued = {};
std::queue<BasicBlock *> ToVisit = {};
struct OrderInfo {
size_t Rank;
@@ -80,6 +83,9 @@ class PartialOrderingVisitor {
// Visits |BB| with the current rank being |Rank|.
size_t visit(BasicBlock *BB, size_t Rank);
size_t GetNodeRank(BasicBlock *BB) const;
bool CanBeVisited(BasicBlock *BB) const;
public:
// Build the visitor to operate on the function F.
PartialOrderingVisitor(Function &F);

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: OpDecorate [[IntBufferVar:%[0-9]+]] DescriptorSet 16
@@ -18,13 +19,13 @@
; CHECK: {{%[0-9]+}} = OpFunction {{%[0-9]+}} DontInline {{%[0-9]+}}
; CHECK-NEXT: OpLabel
define void @RWBufferLoad() #0 {
; CHECK-NEXT: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
; CHECK: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
%buffer0 = call target("spirv.Image", i32, 5, 2, 0, 0, 2, 24)
@llvm.spv.handle.fromBinding.tspirv.Image_f32_5_2_0_0_2_24(
i32 16, i32 7, i32 1, i32 0, i1 false)
; Make sure we use the same variable with multiple loads.
; CHECK-NEXT: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
; CHECK: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
%buffer1 = call target("spirv.Image", i32, 5, 2, 0, 0, 2, 24)
@llvm.spv.handle.fromBinding.tspirv.Image_f32_5_2_0_0_2_24(
i32 16, i32 7, i32 1, i32 0, i1 false)
@@ -36,7 +37,7 @@ define void @RWBufferLoad() #0 {
define void @UseDifferentGlobalVar() #0 {
; Make sure we use a different variable from the first function. They have
; different types.
; CHECK-NEXT: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeFloat]] [[FloatBufferVar]]
; CHECK: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeFloat]] [[FloatBufferVar]]
%buffer0 = call target("spirv.Image", float, 5, 2, 0, 0, 2, 3)
@llvm.spv.handle.fromBinding.tspirv.Image_f32_5_2_0_0_2_3(
i32 16, i32 7, i32 1, i32 0, i1 false)
@@ -48,7 +49,7 @@ define void @UseDifferentGlobalVar() #0 {
define void @ReuseGlobalVarFromFirstFunction() #0 {
; Make sure we use the same variable as the first function. They should be the
; same in case one function calls the other.
; CHECK-NEXT: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
; CHECK: [[buffer:%[0-9]+]] = OpLoad [[RWBufferTypeInt]] [[IntBufferVar]]
%buffer1 = call target("spirv.Image", i32, 5, 2, 0, 0, 2, 24)
@llvm.spv.handle.fromBinding.tspirv.Image_f32_5_2_0_0_2_24(
i32 16, i32 7, i32 1, i32 0, i1 false)

View File

@@ -1,7 +1,7 @@
; All OpVariable instructions in a function must be the first instructions in the first block
; RUN: llc -O0 -mtriple=spirv-unknown-linux %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-linux %s -o - -filetype=obj | spirv-val %}
; RUN: llc -O0 -mtriple=spirv32-unknown-linux %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-linux %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV: OpFunction
; CHECK-SPIRV-NEXT: OpLabel

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
; CHECK-NOT: OpCapability ImageBasic

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-vulkan-library %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-library %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: [[Float:%[0-9]+]] = OpTypeFloat 32

View File

@@ -1,4 +1,3 @@
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; 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=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}

View File

@@ -1,6 +1,4 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -verify-machineinstrs -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 %}

View File

@@ -1,5 +1,5 @@
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; REQUIRES: spirv-tools
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
; This file generated from the following command:

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
; This file generated from the following command:

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,5 +1,6 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-HLSL
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-OCL
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-HLSL
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-OCL
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Make sure spirv operation function calls for all are generated.

View File

@@ -1,5 +1,6 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-HLSL
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-OCL
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-HLSL
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-OCL
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Make sure spirv operation function calls for any are generated.

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpMemoryModel Logical GLSL450

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#int_16:]] = OpTypeInt 16 0

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Make sure SPIRV operation function calls for lerp are generated as FMix

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: %[[#extinst:]] = OpExtInstImport "GLSL.std.450"
@@ -6,35 +7,22 @@
; CHECK: %[[#float:]] = OpTypeFloat 32
; CHECK: %[[#v4float:]] = OpTypeVector %[[#float]] 4
; CHECK: %[[#float_0_30103001:]] = OpConstant %[[#float]] 0.30103000998497009
; CHECK: %[[#_ptr_Function_v4float:]] = OpTypePointer Function %[[#v4float]]
; CHECK: %[[#_ptr_Function_float:]] = OpTypePointer Function %[[#float]]
define void @main() {
define void @main(float %f, <4 x float> %f4) {
entry:
; CHECK: %[[#f:]] = OpVariable %[[#_ptr_Function_float]] Function
; CHECK: %[[#logf:]] = OpVariable %[[#_ptr_Function_float]] Function
; CHECK: %[[#f4:]] = OpVariable %[[#_ptr_Function_v4float]] Function
; CHECK: %[[#logf4:]] = OpVariable %[[#_ptr_Function_v4float]] Function
%f = alloca float, align 4
; CHECK-DAG: %[[#f:]] = OpFunctionParameter %[[#float]]
; CHECK-DAG: %[[#f4:]] = OpFunctionParameter %[[#v4float]]
%logf = alloca float, align 4
%f4 = alloca <4 x float>, align 16
%logf4 = alloca <4 x float>, align 16
; CHECK: %[[#load:]] = OpLoad %[[#float]] %[[#f]] Aligned 4
; CHECK: %[[#log2:]] = OpExtInst %[[#float]] %[[#extinst]] Log2 %[[#load]]
; CHECK: %[[#res:]] = OpFMul %[[#float]] %[[#log2]] %[[#float_0_30103001]]
; CHECK: OpStore %[[#logf]] %[[#res]] Aligned 4
%0 = load float, ptr %f, align 4
%elt.log10 = call float @llvm.log10.f32(float %0)
store float %elt.log10, ptr %logf, align 4
; CHECK: %[[#load:]] = OpLoad %[[#v4float]] %[[#f4]] Aligned 16
; CHECK: %[[#log2:]] = OpExtInst %[[#v4float]] %[[#extinst]] Log2 %[[#load]]
; CHECK: %[[#log2:]] = OpExtInst %[[#float]] %[[#extinst]] Log2 %[[#f]]
; CHECK: %[[#res:]] = OpFMul %[[#float]] %[[#log2]] %[[#float_0_30103001]]
%elt.log10 = call float @llvm.log10.f32(float %f)
; CHECK: %[[#log2:]] = OpExtInst %[[#v4float]] %[[#extinst]] Log2 %[[#f4]]
; CHECK: %[[#res:]] = OpVectorTimesScalar %[[#v4float]] %[[#log2]] %[[#float_0_30103001]]
; CHECK: OpStore %[[#logf4]] %[[#res]] Aligned 16
%1 = load <4 x float>, ptr %f4, align 16
%elt.log101 = call <4 x float> @llvm.log10.v4f32(<4 x float> %1)
store <4 x float> %elt.log101, ptr %logf4, align 16
%elt.log101 = call <4 x float> @llvm.log10.v4f32(<4 x float> %f4)
ret void
}

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,3 +1,4 @@
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; CHECK-DAG: %[[#float_64:]] = OpTypeFloat 64
; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpMemoryModel Logical GLSL450

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Make sure lowering is correctly generating spirv code.

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,3 +1,4 @@
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: OpExtInstImport "GLSL.std.450"

View File

@@ -1,12 +1,10 @@
; TODO(pull/110270): verifier, fix G_BITCAST error "bitcast must change type"
; RUN: llc -verify-machineinstrs -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 -verify-machineinstrs -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 %}
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK: %[[#F32:]] = OpTypeFloat 32
; CHECK: %[[#F64:]] = OpTypeFloat 64

View File

@@ -0,0 +1,52 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
target triple = "spirv-unknown-vulkan1.3-compute"
; Function Attrs: convergent noinline norecurse nounwind optnone
define spir_func noundef i32 @_Z7processv() #0 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpSelectionMerge %[[#merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#left:]] %[[#right:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%1 = alloca i32, align 4
br i1 true, label %left, label %right
; CHECK: %[[#left]] = OpLabel
; CHECK: OpBranch %[[#merge]]
left:
store i32 0, ptr %1
br label %end
; CHECK: %[[#right]] = OpLabel
; CHECK: OpBranch %[[#merge]]
right:
store i32 0, ptr %1
br label %end
; CHECK: %[[#merge]] = OpLabel
; CHECK: OpReturnValue %[[#]]
end:
ret i32 0
}
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.entry() #1
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.loop() #1
attributes #0 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { convergent norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #3 = { convergent }
!llvm.module.flags = !{!0, !1, !2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}

View File

@@ -0,0 +1,47 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | 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"
target triple = "spirv-unknown-vulkan1.3-compute"
; Function Attrs: convergent noinline norecurse nounwind optnone
define spir_func noundef i32 @_Z7processv() #0 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpSelectionMerge %[[#merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#left:]] %[[#merge]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%1 = alloca i32, align 4
br i1 true, label %left, label %end
; CHECK: %[[#left]] = OpLabel
; CHECK: OpBranch %[[#merge]]
left:
store i32 0, ptr %1
br label %end
; CHECK: %[[#merge]] = OpLabel
; CHECK: OpReturnValue %[[#]]
end:
ret i32 0
}
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.entry() #1
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.loop() #1
attributes #0 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { convergent norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #3 = { convergent }
!llvm.module.flags = !{!0, !1, !2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}

View File

@@ -0,0 +1,59 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | 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"
target triple = "spirv-unknown-vulkan1.3-compute"
; Function Attrs: convergent noinline norecurse nounwind optnone
define spir_func noundef i32 @_Z7processv() #0 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpBranch %[[#header:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%1 = alloca i32, align 4
br label %header
; CHECK: %[[#header]] = OpLabel
; CHECK: OpLoopMerge %[[#merge:]] %[[#continue:]] None
; CHECK: OpBranchConditional %[[#]] %[[#body:]] %[[#merge]]
header:
%2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
br i1 true, label %body, label %merge
; CHECK: %[[#body]] = OpLabel
; CHECK: OpBranch %[[#continue]]
body:
store i32 0, ptr %1
br label %continue
continue:
br label %header
; CHECK: %[[#continue]] = OpLabel
; CHECK: OpBranch %[[#header]]
; CHECK: %[[#merge]] = OpLabel
; CHECK: OpReturnValue %[[#]]
merge:
ret i32 0
}
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.entry() #1
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.loop() #1
attributes #0 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { convergent norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #3 = { convergent }
!llvm.module.flags = !{!0, !1, !2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}

View File

@@ -0,0 +1,58 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | 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"
target triple = "spirv-unknown-vulkan1.3-compute"
; Function Attrs: convergent noinline norecurse nounwind optnone
define spir_func noundef i32 @_Z7processv() #0 {
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#]] 0
; CHECK-DAG: %[[#int_1:]] = OpConstant %[[#]] 1
; CHECK: %[[#entry:]] = OpLabel
; CHECK: %[[#var:]] = OpVariable %[[#]] Function
; CHECK: OpSelectionMerge %[[#merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#left:]] %[[#right:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
br i1 true, label %left, label %right
; CHECK: %[[#left]] = OpLabel
; CHECK-NEXT: OpStore %[[#var]] %[[#int_0]]
; CHECK-NEXT: OpBranch %[[#merge]]
left:
br label %end
; CHECK: %[[#right]] = OpLabel
; CHECK-NEXT: OpStore %[[#var]] %[[#int_1]]
; CHECK-NEXT: OpBranch %[[#merge]]
right:
br label %end
; CHECK: %[[#merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#var]]
; CHECK: OpReturnValue %[[#tmp]]
end:
%1 = phi i32 [ 0, %left ], [ 1, %right ]
ret i32 %1
}
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.entry() #1
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare token @llvm.experimental.convergence.loop() #1
attributes #0 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { convergent norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #3 = { convergent }
!llvm.module.flags = !{!0, !1, !2}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}

View File

@@ -8,16 +8,17 @@ target triple = "spirv-unknown-vulkan1.3-compute"
; CHECK-DAG: OpName %[[#fn:]] "_Z2fnv"
; CHECK-DAG: OpName %[[#fn1:]] "_Z3fn1v"
; CHECK-DAG: OpName %[[#fn2:]] "_Z3fn2v"
; CHECK-DAG: OpName %[[#val:]] "val"
; CHECK-DAG: OpName %[[#a:]] "a"
; CHECK-DAG: OpName %[[#b:]] "b"
; CHECK-DAG: OpName %[[#c:]] "c"
; CHECK-DAG: OpName %[[#r2m_a:]] ".reg2mem3"
; CHECK-DAG: OpName %[[#r2m_b:]] ".reg2mem1"
; CHECK-DAG: OpName %[[#r2m_c:]] ".reg2mem"
; CHECK-DAG: %[[#int_ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#bool_ty:]] = OpTypeBool
; CHECK-DAG: %[[#int_pfty:]] = OpTypePointer Function %[[#int_ty]]
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#int_ty]] 0
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#]] 0
; CHECK-DAG: %[[#int_1:]] = OpConstant %[[#]] 1
; CHECK-DAG: %[[#true:]] = OpConstantTrue
; CHECK-DAG: %[[#false:]] = OpConstantFalse
declare token @llvm.experimental.convergence.entry() #1
@@ -44,100 +45,86 @@ entry:
; CHECK: %[[#process]] = OpFunction %[[#int_ty]]
define spir_func noundef i32 @_Z7processv() #0 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK-DAG: %[[#r2m_a]] = OpVariable %[[#]] Function
; CHECK: OpSelectionMerge %[[#a_merge:]]
; CHECK: OpBranchConditional %[[#]] %[[#a_true:]] %[[#a_false:]]
entry:
; CHECK: %[[#entry:]] = OpLabel
%0 = call token @llvm.experimental.convergence.entry()
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%val = alloca i32, align 4
store i32 0, ptr %a, align 4
store i32 1, ptr %b, align 4
store i32 2, ptr %c, align 4
store i32 0, ptr %val, align 4
; CHECK-DAG: %[[#a]] = OpVariable %[[#int_pfty]] Function
; CHECK-DAG: %[[#b]] = OpVariable %[[#int_pfty]] Function
; CHECK-DAG: %[[#c]] = OpVariable %[[#int_pfty]] Function
; CHECK-DAG: %[[#val]] = OpVariable %[[#int_pfty]] Function
%1 = load i32, ptr %a, align 4
%tobool = icmp ne i32 %1, 0
br i1 %tobool, label %cond.true, label %cond.false
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#a]]
; CHECK: %[[#cond:]] = OpINotEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpSelectionMerge %[[#cond_end:]]
; CHECK: OpBranchConditional %[[#cond]] %[[#cond_true:]] %[[#cond_false:]]
%var = alloca i32
br i1 true, label %a_true, label %a_false
cond.true: ; preds = %entry
%2 = load i32, ptr %b, align 4
br label %cond.end
; CHECK: %[[#cond_true]] = OpLabel
; CHECK: OpBranch %[[#cond_end]]
; CHECK: %[[#a_true]] = OpLabel
; CHECK: OpStore %[[#r2m_a]] %[[#true]]
; CHECK: OpBranch %[[#a_merge]]
a_true:
br label %a_merge
cond.false: ; preds = %entry
%3 = load i32, ptr %c, align 4
br label %cond.end
; CHECK: %[[#cond_false]] = OpLabel
; CHECK: %[[#load_c:]] = OpLoad %[[#]] %[[#c]]
; CHECK: OpBranch %[[#cond_end]]
; CHECK: %[[#a_false]] = OpLabel
; CHECK: OpStore %[[#r2m_a]] %[[#false]]
; CHECK: OpBranch %[[#a_merge]]
a_false:
br label %a_merge
cond.end: ; preds = %cond.false, %cond.true
%cond = phi i32 [ %2, %cond.true ], [ %3, %cond.false ]
%tobool1 = icmp ne i32 %cond, 0
br i1 %tobool1, label %if.then, label %if.end
; CHECK: %[[#cond_end]] = OpLabel
; CHECK: %[[#tmp:]] = OpPhi %[[#int_ty]] %[[#load_b:]] %[[#cond_true]] %[[#load_c]] %[[#cond_false]]
; CHECK: OpSelectionMerge %[[#if_end:]]
; CHECK: OpBranchConditional %[[#]] %[[#if_then:]] %[[#if_end]]
; CHECK: %[[#a_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#r2m_a]]
; CHECK: OpSelectionMerge %[[#b_merge:]]
; CHECK: OpBranchConditional %[[#]] %[[#b_true:]] %[[#b_merge]]
a_merge:
%1 = phi i1 [ true, %a_true ], [ false, %a_false ]
br i1 %1, label %b_true, label %b_merge
if.then: ; preds = %cond.end
%4 = load i32, ptr %val, align 4
%inc = add nsw i32 %4, 1
store i32 %inc, ptr %val, align 4
br label %if.end
; CHECK: %[[#if_then]] = OpLabel
; CHECK: OpBranch %[[#if_end]]
; CHECK: %[[#b_true]] = OpLabel
; CHECK: OpBranch %[[#b_merge]]
b_true:
store i32 0, ptr %var ; Prevents whole branch optimization.
br label %b_merge
if.end: ; preds = %if.then, %cond.end
%call2 = call spir_func noundef i32 @_Z2fnv() #4 [ "convergencectrl"(token %0) ]
%tobool3 = icmp ne i32 %call2, 0
br i1 %tobool3, label %cond.true4, label %cond.false6
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpSelectionMerge %[[#cond_end8:]]
; CHECK: OpBranchConditional %[[#]] %[[#cond_true4:]] %[[#cond_false6:]]
; CHECK: %[[#b_merge]] = OpLabel
; CHECK: OpFunctionCall
; CHECK: OpSelectionMerge %[[#c_merge:]]
; CHECK: OpBranchConditional %[[#]] %[[#c_true:]] %[[#c_false:]]
b_merge:
%f1 = call spir_func noundef i32 @_Z2fnv() #4 [ "convergencectrl"(token %0) ]
br i1 true, label %c_true, label %c_false
cond.true4: ; preds = %if.end
%call5 = call spir_func noundef i32 @_Z3fn1v() #4 [ "convergencectrl"(token %0) ]
br label %cond.end8
; CHECK: %[[#cond_true4]] = OpLabel
; CHECK: OpBranch %[[#cond_end8]]
; CHECK: %[[#c_true]] = OpLabel
; CHECK: %[[#]] = OpFunctionCall
; CHECK: OpStore %[[#r2m_b]] %[[#]]
; CHECK: OpBranch %[[#c_merge]]
c_true:
%f2 = call spir_func noundef i32 @_Z3fn1v() #4 [ "convergencectrl"(token %0) ]
br label %c_merge
cond.false6: ; preds = %if.end
%call7 = call spir_func noundef i32 @_Z3fn2v() #4 [ "convergencectrl"(token %0) ]
br label %cond.end8
; CHECK: %[[#cond_false6]] = OpLabel
; CHECK: OpBranch %[[#cond_end8]]
; CHECK: %[[#c_false]] = OpLabel
; CHECK: %[[#]] = OpFunctionCall
; CHECK: OpStore %[[#r2m_b]] %[[#]]
; CHECK: OpBranch %[[#c_merge]]
c_false:
%f3 = call spir_func noundef i32 @_Z3fn2v() #4 [ "convergencectrl"(token %0) ]
br label %c_merge
cond.end8: ; preds = %cond.false6, %cond.true4
%cond9 = phi i32 [ %call5, %cond.true4 ], [ %call7, %cond.false6 ]
%tobool10 = icmp ne i32 %cond9, 0
br i1 %tobool10, label %if.then11, label %if.end13
; CHECK: %[[#cond_end8]] = OpLabel
; CHECK: OpSelectionMerge %[[#if_end13:]]
; CHECK: OpBranchConditional %[[#]] %[[#if_then11:]] %[[#if_end13]]
; CHECK: %[[#c_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#r2m_b]]
; CHECK: OpStore %[[#r2m_c]] %[[#tmp:]]
; CHECK: OpSelectionMerge %[[#d_merge:]]
; CHECK: OpBranchConditional %[[#]] %[[#d_true:]] %[[#d_merge]]
c_merge:
%5 = phi i32 [ %f2, %c_true ], [ %f3, %c_false ]
br i1 true, label %d_true, label %d_merge
if.then11: ; preds = %cond.end8
%5 = load i32, ptr %val, align 4
%inc12 = add nsw i32 %5, 1
store i32 %inc12, ptr %val, align 4
br label %if.end13
; CHECK: %[[#if_then11]] = OpLabel
; CHECK: OpBranch %[[#if_end13]]
; CHECK: %[[#d_true]] = OpLabel
; CHECK: OpBranch %[[#d_merge]]
d_true:
store i32 0, ptr %var ; Prevents whole branch optimization.
br label %d_merge
if.end13: ; preds = %if.then11, %cond.end8
%6 = load i32, ptr %val, align 4
ret i32 %6
; CHECK: %[[#if_end13]] = OpLabel
; CHECK: OpReturnValue
; CHECK: %[[#d_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#r2m_c]]
; CHECK: OpReturnValue %[[#tmp]]
d_merge:
ret i32 %5
}
; Function Attrs: convergent noinline norecurse nounwind optnone

View File

@@ -1,5 +1,4 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=2
; int foo() { return true; }
;

View File

@@ -1,4 +1,3 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=10
; RUN: %if spirv-tools %{ llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-as --preserve-numeric-ids - -o - | spirv-val %}
;
; Source HLSL:

View File

@@ -1,5 +1,4 @@
; RUN: %if spirv-tools %{ llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-as --preserve-numeric-ids - -o - | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=142
;
; Source HLSL:
;

View File

@@ -1,5 +1,4 @@
; RUN: %if spirv-tools %{ llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-as --preserve-numeric-ids - -o - | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=4
;
; Source HLSL:
;

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=19
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=2563170
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=9
;
; int process() {
@@ -139,10 +138,10 @@
; CHECK: OpBranchConditional %[[#]] %[[#bb130:]] %[[#bb125:]]
; CHECK: %[[#bb130:]] = OpLabel
; CHECK: OpBranch %[[#bb126:]]
; CHECK: %[[#bb125:]] = OpLabel
; CHECK: OpReturnValue %[[#]]
; CHECK: %[[#bb126:]] = OpLabel
; CHECK: OpBranch %[[#bb124:]]
; CHECK: %[[#bb125:]] = OpLabel
; CHECK: OpReturnValue %[[#]]
; CHECK: OpFunctionEnd
; CHECK: %[[#func_83:]] = OpFunction %[[#void:]] DontInline %[[#]]
; CHECK: %[[#bb131:]] = OpLabel

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=3
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=6
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=3
;

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=2
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=1
;
; int fn() { return true; }

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=3
;
; int fn() { return true; }

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=0
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=308
;
; int foo() { return 200; }

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=5
;
; int process() {

View File

@@ -1,6 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | spirv-sim --function=_Z7processv --wave=1 --expects=5
;
; int foo() { return 200; }

View File

@@ -41,46 +41,44 @@
; }
; CHECK: %[[#func_16:]] = OpFunction %[[#uint:]] DontInline %[[#]]
; CHECK: %[[#bb37:]] = OpLabel
; CHECK: %[[#bb44:]] = OpLabel
; CHECK: OpReturnValue %[[#]]
; CHECK: OpFunctionEnd
; CHECK: %[[#func_17:]] = OpFunction %[[#void:]] DontInline %[[#]]
; CHECK: %[[#bb38:]] = OpLabel
; CHECK: OpBranch %[[#bb39:]]
; CHECK: %[[#bb39:]] = OpLabel
; CHECK: OpLoopMerge %[[#bb40:]] %[[#bb41:]] None
; CHECK: OpBranchConditional %[[#]] %[[#bb42:]] %[[#bb40:]]
; CHECK: %[[#bb42:]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb43:]]
; CHECK: %[[#bb43:]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb41:]]
; CHECK: %[[#bb40:]] = OpLabel
; CHECK: OpSelectionMerge %[[#bb44:]] None
; CHECK: OpSwitch %[[#]] %[[#bb44:]] 1 %[[#bb44:]] 2 %[[#bb44:]]
; CHECK: %[[#bb41:]] = OpLabel
; CHECK: OpBranch %[[#bb39:]]
; CHECK: %[[#bb44:]] = OpLabel
; CHECK: OpBranch %[[#bb45:]]
; CHECK: %[[#func_19:]] = OpFunction %[[#void:]] DontInline %[[#]]
; CHECK: %[[#bb45:]] = OpLabel
; CHECK: OpBranch %[[#bb46:]]
; CHECK: %[[#bb46:]] = OpLabel
; CHECK: OpBranch %[[#bb47:]]
; CHECK: %[[#bb47:]] = OpLabel
; CHECK: OpSelectionMerge %[[#bb48:]] None
; CHECK: OpBranchConditional %[[#]] %[[#bb49:]] %[[#bb48:]]
; CHECK: OpLoopMerge %[[#bb47:]] %[[#bb48:]] None
; CHECK: OpBranchConditional %[[#]] %[[#bb49:]] %[[#bb47:]]
; CHECK: %[[#bb49:]] = OpLabel
; CHECK: OpBranch %[[#bb48:]]
; CHECK: %[[#bb48:]] = OpLabel
; CHECK: OpBranch %[[#bb50:]]
; CHECK: OpBranchConditional %[[#]] %[[#bb47:]] %[[#bb50:]]
; CHECK: %[[#bb50:]] = OpLabel
; CHECK: OpReturn
; CHECK: OpFunctionEnd
; CHECK: %[[#func_35:]] = OpFunction %[[#void:]] None %[[#]]
; CHECK: OpBranchConditional %[[#]] %[[#bb47:]] %[[#bb48:]]
; CHECK: %[[#bb48:]] = OpLabel
; CHECK: OpBranch %[[#bb46:]]
; CHECK: %[[#bb47:]] = OpLabel
; CHECK: OpSelectionMerge %[[#bb51:]] None
; CHECK: OpSwitch %[[#]] %[[#bb51:]] 1 %[[#bb51:]] 2 %[[#bb51:]]
; CHECK: %[[#bb51:]] = OpLabel
; CHECK: OpBranch %[[#bb52:]]
; CHECK: %[[#bb52:]] = OpLabel
; CHECK: OpBranch %[[#bb53:]]
; CHECK: %[[#bb53:]] = OpLabel
; CHECK: OpBranch %[[#bb54:]]
; CHECK: %[[#bb54:]] = OpLabel
; CHECK: OpSelectionMerge %[[#bb55:]] None
; CHECK: OpBranchConditional %[[#]] %[[#bb56:]] %[[#bb55:]]
; CHECK: %[[#bb56:]] = OpLabel
; CHECK: OpBranch %[[#bb55:]]
; CHECK: %[[#bb55:]] = OpLabel
; CHECK: OpBranch %[[#bb57:]]
; CHECK: %[[#bb57:]] = OpLabel
; CHECK: OpReturn
; CHECK: OpFunctionEnd
; CHECK: %[[#func_40:]] = OpFunction %[[#void:]] None %[[#]]
; CHECK: %[[#bb58:]] = OpLabel
; CHECK: OpReturn
; CHECK: OpFunctionEnd
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-vulkan1.3-compute"

View File

@@ -1,5 +1,5 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
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"
@@ -25,90 +25,92 @@ entry:
ret i32 1
}
; CHECK-DAG: OpName %[[#reg_0:]] "cond.reg2mem"
; CHECK-DAG: OpName %[[#reg_1:]] "cond9.reg2mem"
define internal spir_func void @main() #0 {
; CHECK: %[[#cond:]] = OpINotEqual %[[#bool_ty:]] %[[#a:]] %[[#b:]]
; CHECK: OpSelectionMerge %[[#cond_end:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#cond_true:]] %[[#cond_false:]]
; CHECK: OpSelectionMerge %[[#cond1_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#cond1_true:]] %[[#cond1_false:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%a = alloca i32, align 4
%b = alloca i32, align 4
%c = alloca i32, align 4
%val = alloca i32, align 4
store i32 0, ptr %val, align 4
%1 = load i32, ptr %a, align 4
%tobool = icmp ne i32 %1, 0
br i1 %tobool, label %cond.true, label %cond.false
br i1 true, label %cond1_true, label %cond1_false
; CHECK: %[[#cond_true]] = OpLabel
; CHECK: OpBranch %[[#cond_end]]
cond.true:
%2 = load i32, ptr %b, align 4
br label %cond.end
; CHECK: %[[#cond1_true]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: OpBranch %[[#cond1_merge]]
cond1_true:
%2 = load i32, ptr %a, align 4
br label %cond1_merge
; CHECK: %[[#cond_false]] = OpLabel
; CHECK: OpBranch %[[#cond_end]]
cond.false:
%3 = load i32, ptr %c, align 4
br label %cond.end
; CHECK: %[[#cond1_false]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: OpBranch %[[#cond1_merge]]
cond1_false:
%3 = load i32, ptr %b, align 4
br label %cond1_merge
; CHECK: %[[#cond_end]] = OpLabel
; CHECK: %[[#tmp:]] = OpPhi %[[#int_ty:]] %[[#load_cond_true:]] %[[#cond_true]] %[[#load_cond_false:]] %[[#cond_false:]]
; CHECK: %[[#cond:]] = OpINotEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0:]]
; CHECK: OpSelectionMerge %[[#if_end:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#if_then:]] %[[#if_end]]
cond.end:
%cond = phi i32 [ %2, %cond.true ], [ %3, %cond.false ]
; CHECK: %[[#cond1_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#reg_0]]
; CHECK: %[[#cond:]] = OpINotEqual %[[#]] %[[#tmp]] %[[#]]
; CHECK: OpSelectionMerge %[[#cond2_merge:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#cond2_true:]] %[[#cond2_merge]]
cond1_merge:
%cond = phi i32 [ %2, %cond1_true ], [ %3, %cond1_false ]
%tobool1 = icmp ne i32 %cond, 0
br i1 %tobool1, label %if.then, label %if.end
br i1 %tobool1, label %cond2_true, label %cond2_merge
; CHECK: %[[#if_then]] = OpLabel
; CHECK: OpBranch %[[#if_end]]
if.then:
%4 = load i32, ptr %val, align 4
%inc = add nsw i32 %4, 1
store i32 %inc, ptr %val, align 4
br label %if.end
; CHECK: %[[#cond2_true]] = OpLabel
; CHECK: OpBranch %[[#cond2_merge]]
cond2_true:
store i32 0, ptr %a
br label %cond2_merge
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpSelectionMerge %[[#cond_end8:]] None
; CHECK: OpBranchConditional %[[#tmp:]] %[[#cond4_true:]] %[[#cond_false6:]]
if.end:
; CHECK: %[[#cond2_merge]] = OpLabel
; 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) ]
%tobool3 = icmp ne i32 %call2, 0
br i1 %tobool3, label %cond.true4, label %cond.false6
br i1 true, label %cond3_true, label %cond3_false
; CHECK: %[[#cond3_true]] = OpLabel
; CHECK: OpFunctionCall
; CHECK: OpStore %[[#reg_1]] %[[#]]
; 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: 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: OpSelectionMerge %[[#cond4_merge:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#cond4_true:]] %[[#cond4_merge]]
cond3_merge:
%cond9 = phi i32 [ %call5, %cond3_true ], [ %call7, %cond3_false ]
%tobool10 = icmp ne i32 %cond9, 0
br i1 %tobool10, label %cond4_true, label %cond4_merge
; CHECK: %[[#cond4_true]] = OpLabel
; CHECK: OpBranch %[[#cond_end8]]
cond.true4:
%call5 = call spir_func noundef i32 @fn1() #4 [ "convergencectrl"(token %0) ]
br label %cond.end8
; CHECK: OpBranch %[[#cond4_merge]]
cond4_true:
store i32 0, ptr %a
br label %cond4_merge
; CHECK: %[[#cond_false6]] = OpLabel
; CHECK: OpBranch %[[#cond_end8]]
cond.false6:
%call7 = call spir_func noundef i32 @fn2() #4 [ "convergencectrl"(token %0) ]
br label %cond.end8
; CHECK: %[[#cond_end8]] = OpLabel
; CHECK: OpSelectionMerge %[[#if_end13:]] None
; CHECK: OpBranchConditional %[[#tmp:]] %[[#if_then11:]] %[[#if_end13]]
cond.end8:
%cond9 = phi i32 [ %call5, %cond.true4 ], [ %call7, %cond.false6 ]
%tobool10 = icmp ne i32 %cond9, 0
br i1 %tobool10, label %if.then11, label %if.end13
; CHECK: %[[#if_then11]] = OpLabel
; CHECK: OpBranch %[[#if_end13]]
if.then11:
%5 = load i32, ptr %val, align 4
%inc12 = add nsw i32 %5, 1
store i32 %inc12, ptr %val, align 4
br label %if.end13
; CHECK: %[[#if_end13]] = OpLabel
; CHECK: %[[#cond4_merge]] = OpLabel
; CHECK: OpReturn
if.end13:
cond4_merge:
ret void
}

View File

@@ -1,5 +1,5 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan1.3-compute"
@@ -12,100 +12,98 @@ entry:
define internal spir_func void @main() #2 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpBranch %[[#do_body:]]
; CHECK: OpBranch %[[#do_header:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%val = alloca i32, align 4
%i = alloca i32, align 4
store i32 0, ptr %val, align 4
store i32 0, ptr %i, align 4
br label %do.body
%var = alloca i32, align 4
br label %do_header
; Here a the loop header had to be split in two:
; - 1 header for the loop
; - 1 header for the condition.
; In SPIR-V, a loop header cannot directly
; CHECK: %[[#do_header:]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end:]] %[[#do_cond:]] None
; CHECK: OpBranch %[[#do_body:]]
; CHECK: OpLoopMerge %[[#do_merge:]] %[[#do_latch:]] None
; CHECK: OpBranch %[[#new_header:]]
; CHECK: %[[#do_body]] = OpLabel
; CHECK: OpSelectionMerge %[[#if_then:]] None
; CHECK: OpBranchConditional %[[#cond:]] %[[#if_then]] %[[#if_end:]]
do.body:
; CHECK: %[[#new_header]] = OpLabel
; CHECK: OpSelectionMerge %[[#if_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#if_then:]] %[[#if_end:]]
do_header:
%1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
%2 = load i32, ptr %i, align 4
%inc = add nsw i32 %2, 1
store i32 %inc, ptr %i, align 4
%3 = load i32, ptr %i, align 4
%cmp = icmp sgt i32 %3, 5
br i1 %cmp, label %if.then, label %if.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#if_then]]
if.end:
%4 = load i32, ptr %i, align 4
store i32 %4, ptr %val, align 4
br label %do.cond
store i32 0, ptr %var
br i1 true, label %if.then, label %if.end
; CHECK: %[[#if_then]] = OpLabel
; CHECK: OpBranch %[[#do_cond]]
; CHECK: OpBranch %[[#if_merge]]
if.then:
br label %do.cond
store i32 0, ptr %var
br label %do_latch
; CHECK: %[[#do_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_header]] %[[#do_end]]
do.cond:
%5 = load i32, ptr %i, align 4
%cmp1 = icmp slt i32 %5, 10
br i1 %cmp1, label %do.body, label %do.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#if_merge]]
if.end:
store i32 0, ptr %var
br label %do_latch
; CHECK: %[[#do_end]] = OpLabel
; CHECK: OpBranch %[[#do_body2:]]
; CHECK: %[[#if_merge]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do_latch]] %[[#do_merge]]
; CHECK: %[[#do_latch]] = OpLabel
; CHECK: OpBranch %[[#do_header]]
do_latch:
store i32 0, ptr %var
br i1 true, label %do_header, label %do.end
; CHECK: %[[#do_merge]] = OpLabel
; CHECK: OpBranch %[[#do2_header:]]
do.end:
br label %do.body2
store i32 0, ptr %var
br label %do2_header
; CHECK: %[[#do_body2]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end11:]] %[[#do_cond9:]] None
; CHECK: OpBranch %[[#do_body4:]]
do.body2:
; CHECK: %[[#do2_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do2_merge:]] %[[#do2_continue:]] None
; CHECK: OpBranch %[[#do3_header:]]
do2_header:
%6 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
%7 = load i32, ptr %i, align 4
%inc3 = add nsw i32 %7, 1
store i32 %inc3, ptr %i, align 4
br label %do.body4
store i32 0, ptr %var
br label %do3_header
; CHECK: %[[#do_body4]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end8:]] %[[#do_cond6:]] None
; CHECK: OpBranch %[[#do_cond6]]
do.body4:
; CHECK: %[[#do3_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do3_merge:]] %[[#do3_continue:]] None
; CHECK: OpBranch %[[#do3_body:]]
do3_header:
%8 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %6) ]
%9 = load i32, ptr %val, align 4
%inc5 = add nsw i32 %9, 1
store i32 %inc5, ptr %val, align 4
br label %do.cond6
store i32 0, ptr %var
br label %do3_continue
; CHECK: %[[#do_cond6]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_body4]] %[[#do_end8]]
do.cond6:
%10 = load i32, ptr %i, align 4
%cmp7 = icmp slt i32 %10, 10
br i1 %cmp7, label %do.body4, label %do.end8
; CHECK: %[[#do3_body]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do3_continue]] %[[#do3_merge]]
; CHECK: %[[#do_end8]] = OpLabel
; CHECK: OpBranch %[[#do_cond9]]
do.end8:
%11 = load i32, ptr %i, align 4
%dec = add nsw i32 %11, -1
store i32 %dec, ptr %i, align 4
br label %do.cond9
; CHECK: %[[#do3_continue]] = OpLabel
; CHECK: OpBranch %[[#do3_header]]
do3_continue:
store i32 0, ptr %var
br i1 true, label %do3_header, label %do3_merge
; CHECK: %[[#do_cond9]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_body2]] %[[#do_end11]]
do.cond9:
%12 = load i32, ptr %val, align 4
%cmp10 = icmp slt i32 %12, 10
br i1 %cmp10, label %do.body2, label %do.end11
; CHECK: %[[#do3_merge]] = OpLabel
; CHECK: OpBranch %[[#do2_new_latch:]]
do3_merge:
store i32 0, ptr %var
br label %do2_continue
; CHECK: %[[#do_end11]] = OpLabel
; CHECK: OpReturn
do.end11:
; CHECK: %[[#do2_new_latch]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do2_continue]] %[[#do2_merge]]
; CHECK: %[[#do2_continue]] = OpLabel
; CHECK: OpBranch %[[#do2_header]]
do2_continue:
store i32 0, ptr %var
br i1 true, label %do2_header, label %do2_merge
; CHECK: %[[#do2_merge]] = OpLabel
; CHECK: OpReturn
do2_merge:
ret void
}

View File

@@ -1,5 +1,5 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan1.3-compute"
@@ -8,84 +8,72 @@ define internal spir_func void @main() #0 {
; CHECK: %[[#entry:]] = OpLabel
entry:
%0 = call token @llvm.experimental.convergence.entry()
%val = alloca i32, align 4
%i = alloca i32, align 4
%j = alloca i32, align 4
%k = alloca i32, align 4
store i32 0, ptr %val, align 4
store i32 0, ptr %i, align 4
store i32 0, ptr %j, align 4
store i32 0, ptr %k, align 4
br label %do.body
%var = alloca i32, align 4
br label %do1_header
; CHECK: %[[#do_1_header:]] = OpLabel
; CHECK: OpLoopMerge %[[#end:]] %[[#do_1_latch:]] None
; CHECK: OpBranch %[[#do_2_header:]]
do.body:
; CHECK: %[[#do1_header:]] = OpLabel
; CHECK: OpLoopMerge %[[#do1_merge:]] %[[#do1_continue:]] None
; CHECK: OpBranch %[[#do2_header:]]
do1_header:
%1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
%2 = load i32, ptr %val, align 4
%3 = load i32, ptr %i, align 4
%add = add nsw i32 %2, %3
store i32 %add, ptr %val, align 4
br label %do.body1
store i32 0, ptr %var
br label %do2_header
; CHECK: %[[#do_2_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do_2_end:]] %[[#do_2_latch:]] None
; CHECK: OpBranch %[[#do_2_body:]]
do.body1:
; CHECK: %[[#do2_header:]] = OpLabel
; CHECK: OpLoopMerge %[[#do2_merge:]] %[[#do2_continue:]] None
; CHECK: OpBranch %[[#do3_header:]]
do2_header:
%4 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %1) ]
br label %do.body2
store i32 0, ptr %var
br label %do3_header
; CHECK: %[[#do_2_body]] = OpLabel
; CHECK: OpLoopMerge %[[#do_3_end:]] %[[#do_3_header:]] None
; CHECK: OpBranch %[[#do_3_header]]
do.body2:
; CHECK: %[[#do3_header:]] = OpLabel
; CHECK: OpLoopMerge %[[#do3_merge:]] %[[#do3_continue:]] None
; CHECK: OpBranch %[[#do3_cond:]]
do3_header:
%5 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %4) ]
%6 = load i32, ptr %k, align 4
%inc = add nsw i32 %6, 1
store i32 %inc, ptr %k, align 4
br label %do.cond
store i32 0, ptr %var
br label %do3_continue
; CHECK: %[[#do_3_header]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_2_body]] %[[#do_3_end]]
do.cond:
%7 = load i32, ptr %k, align 4
%cmp = icmp slt i32 %7, 30
br i1 %cmp, label %do.body2, label %do.end
; CHECK: %[[#do3_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do3_continue]] %[[#do3_merge]]
; CHECK: %[[#do3_continue]] = OpLabel
; CHECK: OpBranch %[[#do3_header]]
do3_continue:
store i32 0, ptr %var
br i1 true, label %do3_header, label %do3_merge
; CHECK: %[[#do_3_end]] = OpLabel
; CHECK: OpBranch %[[#do_2_latch]]
do.end:
%8 = load i32, ptr %j, align 4
%inc3 = add nsw i32 %8, 1
store i32 %inc3, ptr %j, align 4
br label %do.cond4
; CHECK: %[[#do3_merge]] = OpLabel
; CHECK: OpBranch %[[#do2_cond:]]
do3_merge:
store i32 0, ptr %var
br label %do2_continue
; CHECK: %[[#do_2_latch]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_2_header]] %[[#do_2_end]]
do.cond4:
%9 = load i32, ptr %j, align 4
%cmp5 = icmp slt i32 %9, 20
br i1 %cmp5, label %do.body1, label %do.end6
; CHECK: %[[#do2_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do2_continue]] %[[#do2_merge]]
; CHECK: %[[#do2_continue]] = OpLabel
; CHECK: OpBranch %[[#do2_header]]
do2_continue:
store i32 0, ptr %var
br i1 true, label %do2_header, label %do2_merge
; CHECK: %[[#do_2_end]] = OpLabel
; CHECK: OpBranch %[[#do_1_latch]]
do.end6:
%10 = load i32, ptr %i, align 4
%inc7 = add nsw i32 %10, 1
store i32 %inc7, ptr %i, align 4
br label %do.cond8
; CHECK: %[[#do2_merge]] = OpLabel
; CHECK: OpBranch %[[#do1_cond:]]
do2_merge:
store i32 0, ptr %var
br label %do1_continue
; CHECK: %[[#do_1_latch]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_1_header]] %[[#end]]
do.cond8:
%11 = load i32, ptr %i, align 4
%cmp9 = icmp slt i32 %11, 10
br i1 %cmp9, label %do.body, label %do.end10
; CHECK: %[[#do1_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do1_continue]] %[[#do1_merge]]
; CHECK: %[[#do1_continue]] = OpLabel
; CHECK: OpBranch %[[#do1_header]]
do1_continue:
store i32 0, ptr %var
br i1 true, label %do1_header, label %do1_merge
; CHECK: %[[#end]] = OpLabel
; CHECK: OpReturn
do.end10:
; CHECK: %[[#do1_merge]] = OpLabel
; CHECK: OpReturn
do1_merge:
ret void
}

View File

@@ -15,71 +15,75 @@ entry:
define internal spir_func void @main() #2 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpBranch %[[#do_body:]]
; CHECK: OpBranch %[[#do1_header:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%val = alloca i32, align 4
%i = alloca i32, align 4
store i32 0, ptr %val, align 4
store i32 0, ptr %i, align 4
br label %do.body
%var = alloca i32, align 4
br label %do1_header
; CHECK: %[[#do_body]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end:]] %[[#do_cond:]] None
; CHECK: OpBranch %[[#do_cond]]
do.body:
; CHECK: %[[#do1_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do1_merge:]] %[[#do1_continue:]] None
; CHECK: OpBranch %[[#do1_cond:]]
do1_header:
%1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
%2 = load i32, ptr %i, align 4
store i32 %2, ptr %val, align 4
br label %do.cond
store i32 0, ptr %var
br label %do1_continue
; CHECK: %[[#do_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_body]] %[[#do_end]]
do.cond:
%3 = load i32, ptr %i, align 4
%cmp = icmp slt i32 %3, 10
br i1 %cmp, label %do.body, label %do.end
; CHECK: %[[#do1_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do1_continue]] %[[#do1_merge]]
; CHECK: %[[#do1_continue]] = OpLabel
; CHECK: OpBranch %[[#do1_header]]
do1_continue:
store i32 0, ptr %var
br i1 true, label %do1_header, label %do1_merge
; CHECK: %[[#do_end]] = OpLabel
; CHECK: OpBranch %[[#do_body1:]]
do.end:
br label %do.body1
; CHECK: %[[#do1_merge]] = OpLabel
; CHECK: OpBranch %[[#do2_header:]]
do1_merge:
store i32 0, ptr %var
br label %do2_header
; CHECK: %[[#do_body1]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end3:]] %[[#do_cond2:]] None
; CHECK: OpBranch %[[#do_cond2]]
do.body1:
; CHECK: %[[#do2_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do2_merge:]] %[[#do2_continue:]] None
; CHECK: OpBranch %[[#do2_cond:]]
do2_header:
%4 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
store i32 0, ptr %val, align 4
br label %do.cond2
store i32 0, ptr %var
br label %do2_continue
; CHECK: %[[#do_cond2]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_body1]] %[[#do_end3]]
do.cond2:
br i1 true, label %do.body1, label %do.end3
; CHECK: %[[#do2_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do2_continue]] %[[#do2_merge]]
; CHECK: %[[#do2_continue]] = OpLabel
; CHECK: OpBranch %[[#do2_header]]
do2_continue:
store i32 0, ptr %var
br i1 true, label %do2_header, label %do2_merge
; CHECK: %[[#do_end3]] = OpLabel
; CHECK: OpBranch %[[#do_body4:]]
do.end3:
br label %do.body4
; CHECK: %[[#do2_merge]] = OpLabel
; CHECK: OpBranch %[[#do3_header:]]
do2_merge:
store i32 0, ptr %var
br label %do3_header
; CHECK: %[[#do_body4]] = OpLabel
; CHECK: OpLoopMerge %[[#do_end7:]] %[[#do_cond5:]] None
; CHECK: OpBranch %[[#do_cond5]]
do.body4:
; CHECK: %[[#do3_header]] = OpLabel
; CHECK: OpLoopMerge %[[#do3_merge:]] %[[#do3_continue:]] None
; CHECK: OpBranch %[[#do3_cond:]]
do3_header:
%5 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
br label %do.cond5
store i32 0, ptr %var
br label %do3_continue
; CHECK: %[[#do_cond5]] = OpLabel
; CHECK: OpBranchConditional %[[#cond:]] %[[#do_body4]] %[[#do_end7]]
do.cond5:
%6 = load i32, ptr %val, align 4
%cmp6 = icmp slt i32 %6, 20
br i1 %cmp6, label %do.body4, label %do.end7
; CHECK: %[[#do3_cond]] = OpLabel
; CHECK: OpBranchConditional %[[#]] %[[#do3_continue]] %[[#do3_merge]]
; CHECK: %[[#do3_continue]] = OpLabel
; CHECK: OpBranch %[[#do3_header]]
do3_continue:
store i32 0, ptr %var
br i1 true, label %do3_header, label %do3_merge
; CHECK: %[[#do_end7]] = OpLabel
; CHECK: OpReturn
do.end7:
; CHECK: %[[#do3_merge]] = OpLabel
; CHECK: OpReturn
do3_merge:
ret void
}

View File

@@ -1,84 +1,77 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - --asm-verbose=0 | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - --asm-verbose=0 | FileCheck %s --match-full-lines
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-vulkan1.3-compute"
; CHECK-DAG: OpName %[[#fn:]] "fn"
; CHECK-DAG: OpName %[[#main:]] "main"
; CHECK-DAG: OpName %[[#var_a:]] "a"
; CHECK-DAG: OpName %[[#var_b:]] "b"
; CHECK-DAG: %[[#bool:]] = OpTypeBool
; CHECK-DAG: %[[#true:]] = OpConstantTrue %[[#bool]]
; CHECK: %[[#fn]] = OpFunction %[[#param:]] DontInline %[[#ftype:]]
define spir_func noundef i32 @fn() #0 {
entry:
%0 = call token @llvm.experimental.convergence.entry()
ret i32 1
}
; CHECK: %[[#main]] = OpFunction %[[#param:]] DontInline %[[#ftype:]]
define internal spir_func void @main() #3 {
; CHECK-DAG: OpName %[[#switch_0:]] "reg1"
; CHECK-DAG: OpName %[[#switch_1:]] "reg"
; CHECK: %[[#entry:]] = OpLabel
; CHECK-DAG: %[[#var_a]] = OpVariable %[[#type:]] Function
; CHECK-DAG: %[[#var_b]] = OpVariable %[[#type:]] Function
; CHECK: %[[#tmp:]] = OpLoad %[[#type:]] %[[#var_a]] Aligned 4
; CHECK: %[[#cond:]] = OpINotEqual %[[#bool]] %[[#tmp]] %[[#const:]]
; CHECK: OpSelectionMerge %[[#if_end:]] None
; CHECK: OpBranchConditional %[[#true]] %[[#cond1:]] %[[#dead:]]
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#]] 0
; CHECK-DAG: %[[#int_1:]] = OpConstant %[[#]] 1
; CHECK: %[[#cond1]] = OpLabel
; CHECK: OpSelectionMerge %[[#new_exit:]] None
; CHECK: OpBranchConditional %[[#cond]] %[[#new_exit]] %[[#lor_lhs_false:]]
; CHECK: %[[#entry:]] = OpLabel
; CHECK-DAG: %[[#switch_0]] = OpVariable %[[#]] Function
; CHECK-DAG: %[[#switch_1]] = OpVariable %[[#]] Function
; CHECK: OpSelectionMerge %[[#merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#new_header:]] %[[#unreachable:]]
; CHECK: %[[#dead]] = OpLabel
; CHECK-NEXT: OpUnreachable
; CHECK: %[[#new_header]] = OpLabel
; CHECK: OpSelectionMerge %[[#new_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#taint_true_merge:]] %[[#br_false:]]
; CHECK: %[[#lor_lhs_false]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#type:]] %[[#var_b]] Aligned 4
; CHECK: %[[#cond:]] = OpINotEqual %[[#bool]] %[[#tmp]] %[[#value:]]
; CHECK: OpBranchConditional %[[#cond]] %[[#new_exit]] %[[#alias_exit:]]
; CHECK: %[[#unreachable]] = OpLabel
; CHECK-NEXT: OpUnreachable
; CHECK: %[[#alias_exit]] = OpLabel
; CHECK: OpBranch %[[#new_exit]]
; CHECK: %[[#taint_true_merge]] = OpLabel
; CHECK: OpStore %[[#switch_0]] %[[#int_1]]
; CHECK: OpBranch %[[#new_merge]]
; CHECK: %[[#new_exit]] = OpLabel
; CHECK: %[[#tmp:]] = OpPhi %[[#type:]] %[[#A:]] %[[#cond1]] %[[#A:]] %[[#lor_lhs_false]] %[[#B:]] %[[#alias_exit]]
; CHECK: %[[#cond:]] = OpIEqual %[[#bool]] %[[#A]] %[[#tmp]]
; CHECK: OpBranchConditional %[[#cond]] %[[#if_then:]] %[[#if_end]]
; CHECK: %[[#br_false]] = OpLabel
; CHECK-DAG: OpStore %[[#switch_1]] %[[#int_0]]
; CHECK: OpSelectionMerge %[[#taint_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#taint_merge]] %[[#taint_false:]]
; CHECK: %[[#if_then]] = OpLabel
; CHECK: OpBranch %[[#if_end]]
; CHECK: %[[#taint_false]] = OpLabel
; CHECK: OpStore %[[#switch_1]] %[[#int_1]]
; CHECK: OpBranch %[[#taint_merge]]
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpReturn
; CHECK: %[[#taint_merge]] = OpLabel
; CHECK: OpStore %[[#switch_0]] %[[#int_0]]
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#switch_1]]
; CHECK: %[[#cond:]] = OpIEqual %[[#]] %[[#int_0]] %[[#tmp]]
; CHECK: OpBranchConditional %[[#cond]] %[[#taint_false_true:]] %[[#new_merge]]
; CHECK: %[[#taint_false_true]] = OpLabel
; CHECK: OpStore %[[#switch_0]] %[[#int_1]]
; CHECK: OpBranch %[[#new_merge]]
; CHECK: %[[#new_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#switch_0]]
; CHECK: %[[#cond:]] = OpIEqual %[[#]] %[[#int_0]] %[[#tmp]]
; CHECK: OpBranchConditional %[[#cond]] %[[#merge]] %[[#br_true:]]
; CHECK: %[[#br_true]] = OpLabel
; CHECK: OpBranch %[[#merge]]
; CHECK: %[[#merge]] = OpLabel
; CHECK: OpReturn
entry:
%0 = call token @llvm.experimental.convergence.entry()
%a = alloca i32, align 4
%b = alloca i32, align 4
%val = alloca i32, align 4
store i32 0, ptr %val, align 4
%1 = load i32, ptr %a, align 4
%tobool = icmp ne i32 %1, 0
br i1 %tobool, label %if.then, label %lor.lhs.false
%var = alloca i32, align 4
br i1 true, label %br_true, label %br_false
lor.lhs.false:
%2 = load i32, ptr %b, align 4
%tobool1 = icmp ne i32 %2, 0
br i1 %tobool1, label %if.then, label %if.end
br_false:
store i32 0, ptr %var, align 4
br i1 true, label %br_true, label %merge
if.then:
%8 = load i32, ptr %val, align 4
%inc = add nsw i32 %8, 1
store i32 %inc, ptr %val, align 4
br label %if.end
br_true:
store i32 0, ptr %var, align 4
br label %merge
if.end:
merge:
ret void
}

View File

@@ -0,0 +1,104 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; The goal of this test is to voluntarily create 2 overlapping convergence
; structures: the loop, and the inner condition.
; Here, the condition header also branches to 2 internal nodes, which are not
; directly a merge/exits.
; This will require a proper header-split.
; In addition, splitting the header makes the continue the merge of the inner
; condition, so we need to properly split the continue block to create a
; valid inner merge, in the correct order.
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-vulkan1.3-compute"
; CHECK-DAG: OpName %[[#switch_0:]] "reg1"
; CHECK-DAG: OpName %[[#variable:]] "var"
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#]] 0
; CHECK-DAG: %[[#int_1:]] = OpConstant %[[#]] 1
; CHECK-DAG: %[[#int_2:]] = OpConstant %[[#]] 2
; CHECK-DAG: %[[#int_3:]] = OpConstant %[[#]] 3
; CHECK-DAG: %[[#int_4:]] = OpConstant %[[#]] 4
define internal spir_func void @main() #1 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: %[[#switch_0]] = OpVariable %[[#]] Function
; CHECK: %[[#variable]] = OpVariable %[[#]] Function
; CHECK: OpBranch %[[#header:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%var = alloca i32, align 4
br label %header
; CHECK: %[[#header]] = OpLabel
; CHECK: OpLoopMerge %[[#merge:]] %[[#continue:]] None
; CHECK: OpBranch %[[#split_header:]]
; CHECK: %[[#split_header]] = OpLabel
; CHECK: OpSelectionMerge %[[#inner_merge:]] None
; CHECK: OpBranchConditional %[[#]] %[[#left:]] %[[#right:]]
header:
%2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
br i1 true, label %left, label %right
; CHECK: %[[#left]] = OpLabel
; CHECK-DAG: OpStore %[[#switch_0]] %[[#int_0]]
; CHECK-DAG: OpStore %[[#variable]] %[[#int_1]]
; CHECK: OpBranchConditional %[[#]] %[[#inner_merge]] %[[#left_next:]]
left:
store i32 1, ptr %var
br i1 true, label %merge, label %left_next
; CHECK: %[[#right]] = OpLabel
; CHECK-DAG: OpStore %[[#switch_0]] %[[#int_0]]
; CHECK-DAG: OpStore %[[#variable]] %[[#int_2]]
; CHECK: OpBranchConditional %[[#]] %[[#inner_merge]] %[[#right_next:]]
right:
store i32 2, ptr %var
br i1 true, label %merge, label %right_next
; CHECK: %[[#left_next]] = OpLabel
; CHECK-DAG: OpStore %[[#switch_0]] %[[#int_1]]
; CHECK-DAG: OpStore %[[#variable]] %[[#int_3]]
; CHECK: OpBranch %[[#inner_merge]]
left_next:
store i32 3, ptr %var
br label %continue
; CHECK: %[[#right_next]] = OpLabel
; CHECK-DAG: OpStore %[[#switch_0]] %[[#int_1]]
; CHECK-DAG: OpStore %[[#variable]] %[[#int_4]]
; CHECK: OpBranch %[[#inner_merge]]
right_next:
store i32 4, ptr %var
br label %continue
; CHECK: %[[#inner_merge]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#switch_0]]
; CHECK: %[[#cond:]] = OpIEqual %[[#]] %[[#int_0]] %[[#tmp]]
; CHECK: OpBranchConditional %[[#cond]] %[[#merge]] %[[#continue]]
; CHECK: %[[#continue]] = OpLabel
; CHECK: OpBranch %[[#header]]
continue:
br label %header
; CHECK: %[[#merge]] = OpLabel
; CHECK: OpReturn
merge:
ret void
}
declare token @llvm.experimental.convergence.entry() #0
declare token @llvm.experimental.convergence.loop() #0
attributes #0 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #1 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
!llvm.module.flags = !{!0, !1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}

View File

@@ -1,23 +1,23 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan-compute"
define internal spir_func void @main() #0 {
; CHECK: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: %[[#int_ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#int_fpty:]] = OpTypePointer Function %[[#int_ty]]
; CHECK-DAG: OpName %[[#idx:]] "idx"
; CHECK-DAG: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: %[[#int_ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#int_ipty:]] = OpTypePointer Input %[[#int_ty]]
; CHECK-DAG: %[[#bool_ty:]] = OpTypeBool
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#int_ty]] 0
; CHECK-DAG: %[[#int_10:]] = OpConstant %[[#int_ty]] 10
; CHECK-DAG: %[[#builtin]] = OpVariable %[[#int_ipty]] Input
; CHECK-DAG: %[[#bool_ty:]] = OpTypeBool
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#int_ty]] 0
; CHECK-DAG: %[[#int_10:]] = OpConstant %[[#int_ty]] 10
; CHECK-DAG: %[[#builtin]] = OpVariable %[[#int_ipty]] Input
; CHECK: %[[#entry:]] = OpLabel
; CHECK: %[[#idx:]] = OpVariable %[[#int_fpty]] Function
; CHECK: OpStore %[[#idx]] %[[#int_0]] Aligned 4
; CHECK: %[[#idx]] = OpVariable %[[#]] Function
; ACHECK: OpStore %[[#idx]] %[[#int_0]] Aligned 4
; CHECK: OpBranch %[[#while_cond:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
@@ -37,12 +37,12 @@ while.cond:
%cmp = icmp ne i32 %2, 10
br i1 %cmp, label %while.body, label %while.end
; CHECK: %[[#while_body]] = OpLabel
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK-NEXT: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK-NEXT: %[[#cmp1:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpBranchConditional %[[#cmp1]] %[[#new_end]] %[[#if_end]]
; CHECK: %[[#while_body]] = OpLabel
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#builtin]] Aligned 1
; CHECK: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK: %[[#cmp1:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpBranchConditional %[[#cmp1]] %[[#new_end]] %[[#if_end]]
while.body:
%3 = call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %1) ]
store i32 %3, ptr %idx, align 4
@@ -50,14 +50,14 @@ while.body:
%cmp1 = icmp eq i32 %4, 0
br i1 %cmp1, label %if.then, label %if.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
; CHECK: %[[#new_end]] = OpLabel
; CHECK: OpBranch %[[#while_end:]]
if.then:
br label %while.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
if.end:
br label %while.cond

View File

@@ -1,21 +1,20 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan-compute"
define internal spir_func void @main() #0 {
; CHECK: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: OpName %[[#idx:]] "idx"
; CHECK-DAG: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: %[[#int_ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#pint_ty:]] = OpTypePointer Function %[[#int_ty]]
; CHECK-DAG: %[[#bool_ty:]] = OpTypeBool
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#int_ty]] 0
; CHECK-DAG: %[[#int_10:]] = OpConstant %[[#int_ty]] 10
; CHECK: %[[#entry:]] = OpLabel
; CHECK: %[[#idx:]] = OpVariable %[[#pint_ty]] Function
; CHECK: %[[#idx]] = OpVariable %[[#]] Function
; CHECK: OpStore %[[#idx]] %[[#int_0]] Aligned 4
; CHECK: OpBranch %[[#while_cond:]]
entry:
@@ -48,17 +47,18 @@ while.body:
%cmp1 = icmp eq i32 %4, 0
br i1 %cmp1, label %if.then, label %if.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
; CHECK: %[[#if_then]] = OpLabel
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK-NEXT: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK: OpBranch %[[#new_end]]
if.then:
%5 = call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %1) ]
store i32 %5, ptr %idx, align 4
br label %while.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
if.end:
br label %while.cond

View File

@@ -1,14 +1,15 @@
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan-compute"
define internal spir_func void @main() #0 {
; CHECK: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: OpName %[[#idx:]] "idx"
; CHECK-DAG: OpName %[[#reg_0:]] "reg"
; CHECK-DAG: OpDecorate %[[#builtin:]] BuiltIn SubgroupLocalInvocationId
; CHECK-DAG: %[[#int_ty:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#pint_ty:]] = OpTypePointer Function %[[#int_ty]]
; CHECK-DAG: %[[#bool_ty:]] = OpTypeBool
; CHECK-DAG: %[[#int_0:]] = OpConstant %[[#int_ty]] 0
; CHECK-DAG: %[[#int_1:]] = OpConstant %[[#int_ty]] 1
@@ -16,7 +17,7 @@ define internal spir_func void @main() #0 {
; CHECK-DAG: %[[#int_10:]] = OpConstant %[[#int_ty]] 10
; CHECK: %[[#entry:]] = OpLabel
; CHECK: %[[#idx:]] = OpVariable %[[#pint_ty]] Function
; CHECK: %[[#idx]] = OpVariable %[[#]] Function
; CHECK: OpStore %[[#idx]] %[[#int_0]] Aligned 4
; CHECK: OpBranch %[[#while_cond:]]
entry:
@@ -26,6 +27,7 @@ entry:
br label %while.cond
; CHECK: %[[#while_cond]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK: %[[#cmp:]] = OpINotEqual %[[#bool_ty]] %[[#tmp]] %[[#int_10]]
; CHECK: OpLoopMerge %[[#new_end:]] %[[#if_end2:]] None
@@ -37,10 +39,11 @@ while.cond:
br i1 %cmp, label %while.body, label %while.end
; CHECK: %[[#while_body]] = OpLabel
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK-NEXT: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK-NEXT: %[[#cmp1:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpStore %[[#reg_0]] %[[#]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#]] %[[#builtin]] Aligned 1
; CHECK: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK: %[[#cmp1:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpBranchConditional %[[#cmp1]] %[[#new_end]] %[[#if_end:]]
while.body:
%3 = call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %1) ]
@@ -50,10 +53,11 @@ while.body:
br i1 %cmp1, label %if.then, label %if.end
; CHECK: %[[#if_end]] = OpLabel
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK-NEXT: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK-NEXT: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK-NEXT: %[[#cmp2:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpStore %[[#reg_0]] %[[#]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#builtin]] Aligned 1
; CHECK: OpStore %[[#idx]] %[[#tmp]] Aligned 4
; CHECK: %[[#tmp:]] = OpLoad %[[#int_ty]] %[[#idx]] Aligned 4
; CHECK: %[[#cmp2:]] = OpIEqual %[[#bool_ty]] %[[#tmp]] %[[#int_0]]
; CHECK: OpBranchConditional %[[#cmp2]] %[[#new_end]] %[[#if_end2]]
if.end:
%5 = call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %1) ]
@@ -62,14 +66,15 @@ if.end:
%cmp2 = icmp eq i32 %6, 0
br i1 %cmp2, label %if.then2, label %if.end2
; CHECK: %[[#if_end2]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
; TODO: this OpSwitch is useless. Improve the "remove useless branches" step of the structurizer to
; cleanup those.
; CHECK: %[[#new_end]] = OpLabel
; CHECK: %[[#route:]] = OpPhi %[[#int_ty]] %[[#int_0]] %[[#while_cond]] %[[#int_1]] %[[#while_body]] %[[#int_2]] %[[#if_end]]
; CHECK: %[[#route:]] = OpLoad %[[#]] %[[#reg_0]] Aligned 4
; CHECK: OpSwitch %[[#route]] %[[#while_end:]] 1 %[[#while_end:]] 2 %[[#while_end:]]
; CHECK: %[[#if_end2]] = OpLabel
; CHECK: OpBranch %[[#while_cond]]
if.end2:
br label %while.cond

View File

@@ -0,0 +1,45 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; 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"
target triple = "spirv-unknown-vulkan1.3-compute"
define internal spir_func void @main() #1 {
; CHECK: %[[#entry:]] = OpLabel
; CHECK: OpBranch %[[#do_body:]]
entry:
%0 = call token @llvm.experimental.convergence.entry()
%a = alloca i32, align 4
br label %loop_body
loop_body:
br i1 true, label %left, label %right
left:
br i1 true, label %loop_exit, label %loop_continue
right:
br i1 true, label %loop_exit, label %loop_continue
loop_continue:
br label %loop_body
loop_exit:
%r = phi i32 [ 0, %left ], [ 1, %right ]
store i32 %r, ptr %a, align 4
ret void
}
declare token @llvm.experimental.convergence.entry() #0
declare token @llvm.experimental.convergence.loop() #0
attributes #0 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
attributes #1 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
!llvm.module.flags = !{!0, !1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 4, !"dx.disable_optimizations", i32 1}

View File

@@ -1,6 +1,9 @@
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s --match-full-lines
; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: OpName %[[#reg_0:]] "reg2"
; CHECK-DAG: OpName %[[#reg_1:]] "reg1"
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-vulkan1.3-compute"
@@ -37,36 +40,40 @@ while.body:
]
; CHECK: %[[#case_1]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: OpBranch %[[#switch_end]]
sw.bb:
store i32 1, ptr %a, align 4
br label %while.end
; CHECK: %[[#case_2]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: OpBranch %[[#switch_end]]
sw.bb1:
store i32 3, ptr %a, align 4
br label %while.end
; CHECK: %[[#case_5]] = OpLabel
; CHECK: OpStore %[[#reg_0]] %[[#]]
; CHECK: OpBranch %[[#switch_end]]
sw.bb2:
store i32 5, ptr %a, align 4
br label %while.end
; CHECK: %[[#switch_end]] = OpLabel
; CHECK: %[[#phi:]] = OpPhi %[[#type:]] %[[#A:]] %[[#while_body]] %[[#B:]] %[[#case_5]] %[[#B:]] %[[#case_2]] %[[#B:]] %[[#case_1]]
; CHECK: %[[#tmp:]] = OpIEqual %[[#type:]] %[[#A]] %[[#phi]]
; CHECK: %[[#val:]] = OpLoad %[[#]] %[[#reg_0]]
; CHECK: %[[#tmp:]] = OpIEqual %[[#type:]] %[[#]] %[[#val]]
; CHECK: OpBranchConditional %[[#tmp]] %[[#sw_default:]] %[[#while_end]]
; CHECK: %[[#sw_default]] = OpLabel
; CHECK: OpStore %[[#A:]] %[[#B:]] Aligned 4
; CHECK: OpStore %[[#]] %[[#B:]] Aligned 4
; CHECK: OpBranch %[[#for_cond:]]
sw.default:
store i32 0, ptr %i, align 4
br label %for.cond
; CHECK: %[[#for_cond]] = OpLabel
; CHECK: OpStore %[[#reg_1]] %[[#]]
; CHECK: OpSelectionMerge %[[#for_merge:]] None
; CHECK-NEXT: OpBranchConditional %[[#cond:]] %[[#for_merge]] %[[#for_end:]]
for.cond:
@@ -76,13 +83,14 @@ for.cond:
br i1 %cmp, label %for.body, label %for.end
; CHECK: %[[#for_end]] = OpLabel
; CHECK: OpStore %[[#reg_1]] %[[#]]
; CHECK: OpBranch %[[#for_merge]]
for.end:
br label %while.end
; CHECK: %[[#for_merge]] = OpLabel
; CHECK: %[[#phi:]] = OpPhi %[[#type:]] %[[#A:]] %[[#for_cond]] %[[#B:]] %[[#for_end]]
; CHECK: %[[#tmp:]] = OpIEqual %[[#type:]] %[[#A]] %[[#phi]]
; CHECK: %[[#val:]] = OpLoad %[[#]] %[[#reg_1]]
; CHECK: %[[#tmp:]] = OpIEqual %[[#type:]] %[[#]] %[[#val]]
; CHECK: OpBranchConditional %[[#tmp]] %[[#for_body:]] %[[#while_end]]
; CHECK: %[[#for_body]] = OpLabel