[WebAssembly] Make CFG stackification independent of basic-block labels.

This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.

Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.

This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.

This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.

llvm-svn: 257505
This commit is contained in:
Dan Gohman 2016-01-12 19:14:46 +00:00
parent 1279881315
commit 1d68e80f26
11 changed files with 541 additions and 346 deletions

View File

@ -16,6 +16,8 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssembly.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
@ -33,7 +35,7 @@ using namespace llvm;
WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI)
: MCInstPrinter(MAI, MII, MRI) {}
: MCInstPrinter(MAI, MII, MRI), ControlFlowCounter(0) {}
void WebAssemblyInstPrinter::printRegName(raw_ostream &OS,
unsigned RegNo) const {
@ -59,6 +61,52 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
// Print any added annotation.
printAnnotation(OS, Annot);
if (CommentStream) {
// Observe any effects on the control flow stack, for use in annotating
// control flow label references.
switch (MI->getOpcode()) {
default:
break;
case WebAssembly::LOOP: {
// Grab the TopLabel value first so that labels print in numeric order.
uint64_t TopLabel = ControlFlowCounter++;
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
printAnnotation(OS, "label" + utostr(TopLabel) + ':');
ControlFlowStack.push_back(std::make_pair(TopLabel, true));
break;
}
case WebAssembly::BLOCK:
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
break;
case WebAssembly::END_LOOP:
ControlFlowStack.pop_back();
printAnnotation(
OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
break;
case WebAssembly::END_BLOCK:
printAnnotation(
OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
break;
}
// Annotate any control flow label references.
unsigned NumFixedOperands = Desc.NumOperands;
SmallSet<uint64_t, 8> Printed;
for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
const MCOperandInfo &Info = Desc.OpInfo[i];
if (!(i < NumFixedOperands
? (Info.OperandType == WebAssembly::OPERAND_BASIC_BLOCK)
: (Desc.TSFlags & WebAssemblyII::VariableOpImmediateIsLabel)))
continue;
uint64_t Depth = MI->getOperand(i).getImm();
if (!Printed.insert(Depth).second)
continue;
const auto &Pair = ControlFlowStack.rbegin()[Depth];
printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") +
" to label" + utostr(Pair.first));
}
}
}
static std::string toString(const APFloat &FP) {
@ -100,7 +148,7 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
} else if (Op.isImm()) {
assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
(MII.get(MI->getOpcode()).TSFlags &
WebAssemblyII::VariableOpIsImmediate)) &&
WebAssemblyII::VariableOpIsImmediate)) &&
"WebAssemblyII::VariableOpIsImmediate should be set for "
"variable_ops immediate ops");
if (MII.get(MI->getOpcode()).TSFlags &
@ -117,7 +165,7 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
} else {
assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
(MII.get(MI->getOpcode()).TSFlags &
WebAssemblyII::VariableOpIsImmediate)) &&
WebAssemblyII::VariableOpIsImmediate)) &&
"WebAssemblyII::VariableOpIsImmediate should be set for "
"variable_ops expr ops");
assert(Op.isExpr() && "unknown operand kind in printOperand");

View File

@ -23,6 +23,9 @@ namespace llvm {
class MCSubtargetInfo;
class WebAssemblyInstPrinter final : public MCInstPrinter {
uint64_t ControlFlowCounter;
SmallVector<std::pair<uint64_t, bool>, 0> ControlFlowStack;
public:
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI);

View File

@ -58,6 +58,9 @@ enum {
// For immediate values in the variable_ops range, this flag indicates
// whether the value represents a type.
VariableOpImmediateIsType = (1 << 1),
// For immediate values in the variable_ops range, this flag indicates
// whether the value represents a control-flow label.
VariableOpImmediateIsLabel = (1 << 2),
};
} // end namespace WebAssemblyII

View File

@ -208,10 +208,6 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
case WebAssembly::LOOP_END:
// This is a no-op which just exists to tell AsmPrinter.cpp that there's a
// fallthrough which nevertheless requires a label for the destination here.
break;
default: {
WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
MCInst TmpInst;

View File

@ -326,13 +326,21 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
InsertPos = Header->getFirstTerminator();
while (InsertPos != Header->begin() &&
prev(InsertPos)->definesRegister(WebAssembly::EXPR_STACK) &&
prev(InsertPos)->getOpcode() != WebAssembly::LOOP)
prev(InsertPos)->getOpcode() != WebAssembly::LOOP &&
prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK &&
prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP)
--InsertPos;
}
// Add the BLOCK.
BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK))
.addMBB(&MBB);
BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK));
// Mark the end of the block.
InsertPos = MBB.begin();
while (InsertPos != MBB.end() &&
InsertPos->getOpcode() == WebAssembly::END_LOOP)
++InsertPos;
BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK));
// Track the farthest-spanning scope that ends at this point.
int Number = MBB.getNumber();
@ -342,10 +350,11 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
}
/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF,
SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
const WebAssemblyInstrInfo &TII,
const MachineLoopInfo &MLI) {
static void PlaceLoopMarker(
MachineBasicBlock &MBB, MachineFunction &MF,
SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops,
const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) {
MachineLoop *Loop = MLI.getLoopFor(&MBB);
if (!Loop || Loop->getHeader() != &MBB)
return;
@ -362,14 +371,19 @@ static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF,
Iter = next(MachineFunction::iterator(Bottom));
}
MachineBasicBlock *AfterLoop = &*Iter;
BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP))
.addMBB(AfterLoop);
// Emit a special no-op telling the asm printer that we need a label to close
// the loop scope, even though the destination is only reachable by
// fallthrough.
if (!Bottom->back().isBarrier())
BuildMI(*Bottom, Bottom->end(), DebugLoc(), TII.get(WebAssembly::LOOP_END));
// Mark the beginning of the loop (after the end of any existing loop that
// ends here).
auto InsertPos = MBB.begin();
while (InsertPos != MBB.end() &&
InsertPos->getOpcode() == WebAssembly::END_LOOP)
++InsertPos;
BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP));
// Mark the end of the loop.
MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(),
TII.get(WebAssembly::END_LOOP));
LoopTops[End] = &MBB;
assert((!ScopeTops[AfterLoop->getNumber()] ||
ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
@ -378,6 +392,19 @@ static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF,
ScopeTops[AfterLoop->getNumber()] = &MBB;
}
static unsigned
GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
const MachineBasicBlock *MBB) {
unsigned Depth = 0;
for (auto X : reverse(Stack)) {
if (X == MBB)
break;
++Depth;
}
assert(Depth < Stack.size() && "Branch destination should be in scope");
return Depth;
}
/// Insert LOOP and BLOCK markers at appropriate places.
static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
const WebAssemblyInstrInfo &TII,
@ -389,25 +416,57 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
// we may insert at the end.
SmallVector<MachineBasicBlock *, 8> ScopeTops(MF.getNumBlockIDs() + 1);
// For eacn LOOP_END, the corresponding LOOP.
DenseMap<const MachineInstr *, const MachineBasicBlock *> LoopTops;
for (auto &MBB : MF) {
// Place the LOOP for MBB if MBB is the header of a loop.
PlaceLoopMarker(MBB, MF, ScopeTops, TII, MLI);
PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI);
// Place the BLOCK for MBB if MBB is branched to from above.
PlaceBlockMarker(MBB, MF, ScopeTops, TII, MLI, MDT);
}
}
#ifndef NDEBUG
static bool
IsOnStack(const SmallVectorImpl<std::pair<MachineBasicBlock *, bool>> &Stack,
const MachineBasicBlock *MBB) {
for (const auto &Pair : Stack)
if (Pair.first == MBB)
return true;
return false;
// Now rewrite references to basic blocks to be depth immediates.
SmallVector<const MachineBasicBlock *, 8> Stack;
for (auto &MBB : reverse(MF)) {
for (auto &MI : reverse(MBB)) {
switch (MI.getOpcode()) {
case WebAssembly::BLOCK:
assert(ScopeTops[Stack.back()->getNumber()] == &MBB &&
"Block should be balanced");
Stack.pop_back();
break;
case WebAssembly::LOOP:
assert(Stack.back() == &MBB && "Loop top should be balanced");
Stack.pop_back();
Stack.pop_back();
break;
case WebAssembly::END_BLOCK:
Stack.push_back(&MBB);
break;
case WebAssembly::END_LOOP:
Stack.push_back(&MBB);
Stack.push_back(LoopTops[&MI]);
break;
default:
if (MI.isTerminator()) {
// Rewrite MBB operands to be depth immediates.
SmallVector<MachineOperand, 4> Ops(MI.operands());
while (MI.getNumOperands() > 0)
MI.RemoveOperand(MI.getNumOperands() - 1);
for (auto MO : Ops) {
if (MO.isMBB())
MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB()));
MI.addOperand(MF, MO);
}
}
break;
}
}
}
assert(Stack.empty() && "Control flow should be balanced");
}
#endif
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "********** CFG Stackifying **********\n"
@ -427,43 +486,5 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
// Place the BLOCK and LOOP markers to indicate the beginnings of scopes.
PlaceMarkers(MF, MLI, TII, MDT);
#ifndef NDEBUG
// Verify that block and loop beginnings and endings are in LIFO order, and
// that all references to blocks are to blocks on the stack at the point of
// the reference.
SmallVector<std::pair<MachineBasicBlock *, bool>, 0> Stack;
for (auto &MBB : MF) {
while (!Stack.empty() && Stack.back().first == &MBB)
if (Stack.back().second) {
assert(Stack.size() >= 2);
Stack.pop_back();
Stack.pop_back();
} else {
assert(Stack.size() >= 1);
Stack.pop_back();
}
for (auto &MI : MBB)
switch (MI.getOpcode()) {
case WebAssembly::LOOP:
Stack.push_back(std::make_pair(&MBB, false));
Stack.push_back(std::make_pair(MI.getOperand(0).getMBB(), true));
break;
case WebAssembly::BLOCK:
Stack.push_back(std::make_pair(MI.getOperand(0).getMBB(), false));
break;
default:
// Verify that all referenced blocks are in scope. A reference to a
// block with a negative number is invalid, but can happen with inline
// asm, so we shouldn't assert on it, but instead let CodeGen properly
// fail on it.
for (const MachineOperand &MO : MI.explicit_operands())
if (MO.isMBB() && MO.getMBB()->getNumber() >= 0)
assert(IsOnStack(Stack, MO.getMBB()));
break;
}
}
assert(Stack.empty());
#endif
return true;
}

View File

@ -42,32 +42,32 @@ let Defs = [ARGUMENTS] in {
// jump tables, so in practice we don't ever use TABLESWITCH_I64 in wasm32 mode
// currently.
// Set TSFlags{0} to 1 to indicate that the variable_ops are immediates.
// Set TSFlags{2} to 1 to indicate that the immediates represent labels.
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
def TABLESWITCH_I32 : I<(outs), (ins I32:$index, bb_op:$default, variable_ops),
[(WebAssemblytableswitch I32:$index, bb:$default)],
"tableswitch\t$index, $default"> {
let TSFlags{0} = 1;
let TSFlags{2} = 1;
}
def TABLESWITCH_I64 : I<(outs), (ins I64:$index, bb_op:$default, variable_ops),
[(WebAssemblytableswitch I64:$index, bb:$default)],
"tableswitch\t$index, $default"> {
let TSFlags{0} = 1;
let TSFlags{2} = 1;
}
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
// Placemarkers to indicate the start of a block or loop scope. These
// Placemarkers to indicate the start or end of a block or loop scope. These
// use/clobber EXPR_STACK to prevent them from being moved into the middle of
// an expression tree.
let Uses = [EXPR_STACK], Defs = [EXPR_STACK] in {
def BLOCK : I<(outs), (ins bb_op:$dst), [], "block \t$dst">;
def LOOP : I<(outs), (ins bb_op:$dst), [], "loop \t$dst">;
def BLOCK : I<(outs), (ins), [], "block">;
def LOOP : I<(outs), (ins), [], "loop">;
def END_BLOCK : I<(outs), (ins), [], "end_block">;
def END_LOOP : I<(outs), (ins), [], "end_loop">;
} // Uses = [EXPR_STACK], Defs = [EXPR_STACK]
// No-op to indicate to the AsmPrinter that a loop ends here, so a
// basic block label is needed even if it wouldn't otherwise appear so.
let isTerminator = 1, hasCtrlDep = 1 in
def LOOP_END : I<(outs), (ins), []>;
multiclass RETURN<WebAssemblyRegClass vt> {
def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)],
"return \t$val">;

View File

@ -74,6 +74,9 @@ bool WebAssemblyInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
case WebAssembly::BR_IF:
if (HaveCond)
return true;
// If we're running after CFGStackify, we can't optimize further.
if (!MI.getOperand(1).isMBB())
return true;
Cond.push_back(MachineOperand::CreateImm(true));
Cond.push_back(MI.getOperand(0));
TBB = MI.getOperand(1).getMBB();
@ -82,12 +85,18 @@ bool WebAssemblyInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
case WebAssembly::BR_UNLESS:
if (HaveCond)
return true;
// If we're running after CFGStackify, we can't optimize further.
if (!MI.getOperand(1).isMBB())
return true;
Cond.push_back(MachineOperand::CreateImm(false));
Cond.push_back(MI.getOperand(0));
TBB = MI.getOperand(1).getMBB();
HaveCond = true;
break;
case WebAssembly::BR:
// If we're running after CFGStackify, we can't optimize further.
if (!MI.getOperand(0).isMBB())
return true;
if (!HaveCond)
TBB = MI.getOperand(0).getMBB();
else

View File

@ -66,6 +66,9 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
default:
MI->dump();
llvm_unreachable("unknown operand type");
case MachineOperand::MO_MachineBasicBlock:
MI->dump();
llvm_unreachable("MachineBasicBlock operand should have been rewritten");
case MachineOperand::MO_Register: {
// Ignore all implicit register operands.
if (MO.isImplicit())
@ -91,10 +94,6 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
llvm_unreachable("unknown floating point immediate type");
break;
}
case MachineOperand::MO_MachineBasicBlock:
MCOp = MCOperand::createExpr(
MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
break;
case MachineOperand::MO_GlobalAddress:
assert(MO.getTargetFlags() == 0 &&
"WebAssembly does not use target flags on GlobalAddresses");

View File

@ -18,7 +18,7 @@ declare void @something()
; CHECK-NEXT: br_if
; CHECK-NOT: br
; CHECK: call
; CHECK: br .LBB0_1{{$}}
; CHECK: br 0{{$}}
; CHECK: return{{$}}
; OPT-LABEL: test0:
; OPT: loop
@ -28,7 +28,7 @@ declare void @something()
; OPT-NEXT: br_if
; OPT-NOT: br
; OPT: call
; OPT: br .LBB0_1{{$}}
; OPT: br 0{{$}}
; OPT: return{{$}}
define void @test0(i32 %n) {
entry:
@ -59,7 +59,7 @@ back:
; CHECK-NEXT: br_if
; CHECK-NOT: br
; CHECK: call
; CHECK: br .LBB1_1{{$}}
; CHECK: br 0{{$}}
; CHECK: return{{$}}
; OPT-LABEL: test1:
; OPT: loop
@ -69,7 +69,7 @@ back:
; OPT-NEXT: br_if
; OPT-NOT: br
; OPT: call
; OPT: br .LBB1_1{{$}}
; OPT: br 0{{$}}
; OPT: return{{$}}
define void @test1(i32 %n) {
entry:
@ -94,17 +94,18 @@ back:
; CHECK-LABEL: test2:
; CHECK-NOT: local
; CHECK: block .LBB2_2{{$}}
; CHECK: br_if {{[^,]*}}, .LBB2_2{{$}}
; CHECK: block{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK: .LBB2_1:
; CHECK: br_if ${{[0-9]+}}, .LBB2_1{{$}}
; CHECK: br_if ${{[0-9]+}}, 0{{$}}
; CHECK: .LBB2_2:
; CHECK: return{{$}}
; OPT-LABEL: test2:
; OPT: block .LBB2_2{{$}}
; OPT: br_if {{[^,]*}}, .LBB2_2{{$}}
; OPT-NOT: local
; OPT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT: .LBB2_1:
; OPT: br_if ${{[0-9]+}}, .LBB2_1{{$}}
; OPT: br_if ${{[0-9]+}}, 0{{$}}
; OPT: .LBB2_2:
; OPT: return{{$}}
define void @test2(double* nocapture %p, i32 %n) {
@ -133,22 +134,27 @@ for.end:
}
; CHECK-LABEL: doublediamond:
; CHECK: block .LBB3_5{{$}}
; CHECK: block .LBB3_2{{$}}
; CHECK: br_if $0, .LBB3_2{{$}}
; CHECK: block .LBB3_4{{$}}
; CHECK: br_if $1, .LBB3_4{{$}}
; CHECK: br .LBB3_5{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: br_if ${{[^,]*}}, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_2:
; CHECK-NEXT: end_block{{$}}
; CHECK: block{{$}}
; CHECK: br_if ${{[^,]*}}, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_4:
; CHECK-NEXT: end_block{{$}}
; CHECK: .LBB3_5:
; CHECK-NEXT: end_block{{$}}
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: doublediamond:
; OPT: block .LBB3_5{{$}}
; OPT: block .LBB3_4{{$}}
; OPT: br_if {{[^,]*}}, .LBB3_4{{$}}
; OPT: block .LBB3_3{{$}}
; OPT: br_if {{[^,]*}}, .LBB3_3{{$}}
; OPT: br .LBB3_5{{$}}
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: br_if ${{[^,]*}}, 0{{$}}
; OPT: block{{$}}
; OPT: br_if ${{[^,]*}}, 0{{$}}
; OPT: br 1{{$}}
; OPT: .LBB3_4:
; OPT: .LBB3_5:
; OPT: return ${{[0-9]+}}{{$}}
@ -176,13 +182,13 @@ exit:
}
; CHECK-LABEL: triangle:
; CHECK: block .LBB4_2{{$}}
; CHECK: br_if $1, .LBB4_2{{$}}
; CHECK: block{{$}}
; CHECK: br_if $1, 0{{$}}
; CHECK: .LBB4_2:
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: triangle:
; OPT: block .LBB4_2{{$}}
; OPT: br_if $1, .LBB4_2{{$}}
; OPT: block{{$}}
; OPT: br_if $1, 0{{$}}
; OPT: .LBB4_2:
; OPT: return ${{[0-9]+}}{{$}}
define i32 @triangle(i32* %p, i32 %a) {
@ -199,18 +205,18 @@ exit:
}
; CHECK-LABEL: diamond:
; CHECK: block .LBB5_3{{$}}
; CHECK: block .LBB5_2{{$}}
; CHECK: br_if $1, .LBB5_2{{$}}
; CHECK: br .LBB5_3{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: br_if $1, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB5_2:
; CHECK: .LBB5_3:
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: diamond:
; OPT: block .LBB5_3{{$}}
; OPT: block .LBB5_2{{$}}
; OPT: br_if {{[^,]*}}, .LBB5_2{{$}}
; OPT: br .LBB5_3{{$}}
; OPT: block{{$}}
; OPT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT: br 1{{$}}
; OPT: .LBB5_2:
; OPT: .LBB5_3:
; OPT: return ${{[0-9]+}}{{$}}
@ -246,13 +252,13 @@ entry:
; CHECK-NOT: br
; CHECK: .LBB7_1:
; CHECK: i32.store $discard=, 0($0), $pop{{[0-9]+}}{{$}}
; CHECK: br .LBB7_1{{$}}
; CHECK: br 0{{$}}
; CHECK: .LBB7_2:
; OPT-LABEL: minimal_loop:
; OPT-NOT: br
; OPT: .LBB7_1:
; OPT: i32.store $discard=, 0($0), $pop{{[0-9]+}}{{$}}
; OPT: br .LBB7_1{{$}}
; OPT: br 0{{$}}
; OPT: .LBB7_2:
define i32 @minimal_loop(i32* %p) {
entry:
@ -266,16 +272,16 @@ loop:
; CHECK-LABEL: simple_loop:
; CHECK-NOT: br
; CHECK: .LBB8_1:
; CHECK: loop .LBB8_2{{$}}
; CHECK: br_if $pop{{[0-9]+}}, .LBB8_1{{$}}
; CHECK: .LBB8_2:
; CHECK: loop{{$}}
; CHECK: br_if $pop{{[0-9]+}}, 0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: simple_loop:
; OPT-NOT: br
; OPT: .LBB8_1:
; OPT: loop .LBB8_2{{$}}
; OPT: br_if {{[^,]*}}, .LBB8_1{{$}}
; OPT: .LBB8_2:
; OPT: loop{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT: return ${{[0-9]+}}{{$}}
define i32 @simple_loop(i32* %p, i32 %a) {
entry:
@ -291,18 +297,18 @@ exit:
}
; CHECK-LABEL: doubletriangle:
; CHECK: block .LBB9_4{{$}}
; CHECK: br_if $0, .LBB9_4{{$}}
; CHECK: block .LBB9_3{{$}}
; CHECK: br_if $1, .LBB9_3{{$}}
; CHECK: block{{$}}
; CHECK: br_if $0, 0{{$}}
; CHECK: block{{$}}
; CHECK: br_if $1, 0{{$}}
; CHECK: .LBB9_3:
; CHECK: .LBB9_4:
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: doubletriangle:
; OPT: block .LBB9_4{{$}}
; OPT: br_if $0, .LBB9_4{{$}}
; OPT: block .LBB9_3{{$}}
; OPT: br_if $1, .LBB9_3{{$}}
; OPT: block{{$}}
; OPT: br_if $0, 0{{$}}
; OPT: block{{$}}
; OPT: br_if $1, 0{{$}}
; OPT: .LBB9_3:
; OPT: .LBB9_4:
; OPT: return ${{[0-9]+}}{{$}}
@ -327,20 +333,20 @@ exit:
}
; CHECK-LABEL: ifelse_earlyexits:
; CHECK: block .LBB10_4{{$}}
; CHECK: block .LBB10_2{{$}}
; CHECK: br_if $0, .LBB10_2{{$}}
; CHECK: br .LBB10_4{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: br_if $0, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB10_2:
; CHECK: br_if $1, .LBB10_4{{$}}
; CHECK: br_if $1, 0{{$}}
; CHECK: .LBB10_4:
; CHECK: return ${{[0-9]+}}{{$}}
; OPT-LABEL: ifelse_earlyexits:
; OPT: block .LBB10_4{{$}}
; OPT: block .LBB10_3{{$}}
; OPT: br_if {{[^,]*}}, .LBB10_3{{$}}
; OPT: br_if $1, .LBB10_4{{$}}
; OPT: br .LBB10_4{{$}}
; OPT: block{{$}}
; OPT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT: br_if $1, 1{{$}}
; OPT: br 1{{$}}
; OPT: .LBB10_3:
; OPT: .LBB10_4:
; OPT: return ${{[0-9]+}}{{$}}
@ -366,34 +372,39 @@ exit:
; CHECK-LABEL: doublediamond_in_a_loop:
; CHECK: .LBB11_1:
; CHECK: loop .LBB11_7{{$}}
; CHECK: block .LBB11_6{{$}}
; CHECK: block .LBB11_3{{$}}
; CHECK: br_if $0, .LBB11_3{{$}}
; CHECK: br .LBB11_6{{$}}
; CHECK: loop{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: br_if $0, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_3:
; CHECK: block .LBB11_5{{$}}
; CHECK: br_if $1, .LBB11_5{{$}}
; CHECK: br .LBB11_6{{$}}
; CHECK: block{{$}}
; CHECK: br_if $1, 0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_5:
; CHECK: .LBB11_6:
; CHECK: br .LBB11_1{{$}}
; CHECK: br 0{{$}}
; CHECK: .LBB11_7:
; CHECK-NEXT: end_loop{{$}}
; OPT-LABEL: doublediamond_in_a_loop:
; OPT: .LBB11_1:
; OPT: loop .LBB11_7{{$}}
; OPT: block .LBB11_6{{$}}
; OPT: block .LBB11_5{{$}}
; OPT: br_if {{[^,]*}}, .LBB11_5{{$}}
; OPT: block .LBB11_4{{$}}
; OPT: br_if {{[^,]*}}, .LBB11_4{{$}}
; OPT: br .LBB11_6{{$}}
; OPT: loop{{$}}
; OPT: block{{$}}
; OPT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT: br 2{{$}}
; OPT: .LBB11_4:
; OPT: br .LBB11_6{{$}}
; OPT-NEXT: end_block{{$}}
; OPT: br 1{{$}}
; OPT: .LBB11_5:
; OPT-NEXT: end_block{{$}}
; OPT: .LBB11_6:
; OPT: br .LBB11_1{{$}}
; OPT-NEXT: end_block{{$}}
; OPT: br 0{{$}}
; OPT: .LBB11_7:
; OPT-NEXT: end_loop{{$}}
define i32 @doublediamond_in_a_loop(i32 %a, i32 %b, i32* %p) {
entry:
br label %header
@ -461,42 +472,48 @@ if.end:
; Test switch lowering and block placement.
; CHECK-LABEL: test4:
; CHECK-NEXT: .param i32{{$}}
; CHECK: block .LBB13_8{{$}}
; CHECK-NEXT: block .LBB13_7{{$}}
; CHECK-NEXT: block .LBB13_4{{$}}
; CHECK: br_if $pop{{[0-9]*}}, .LBB13_4{{$}}
; CHECK-NEXT: block .LBB13_3{{$}}
; CHECK: br_if $pop{{[0-9]*}}, .LBB13_3{{$}}
; CHECK: br_if $pop{{[0-9]*}}, .LBB13_7{{$}}
; CHECK-NEXT: .param i32{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: br_if $pop{{[0-9]*}}, 0{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: br_if $pop{{[0-9]*}}, 0{{$}}
; CHECK: br_if $pop{{[0-9]*}}, 2{{$}}
; CHECK-NEXT: .LBB13_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB13_4:
; CHECK: br_if $pop{{[0-9]*}}, .LBB13_8{{$}}
; CHECK: br_if $pop{{[0-9]*}}, .LBB13_7{{$}}
; CHECK: br_if $pop{{[0-9]*}}, 1{{$}}
; CHECK: br_if $pop{{[0-9]*}}, 0{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB13_7:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB13_8:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
; OPT-LABEL: test4:
; OPT-NEXT: .param i32{{$}}
; OPT: block .LBB13_8{{$}}
; OPT-NEXT: block .LBB13_7{{$}}
; OPT-NEXT: block .LBB13_4{{$}}
; OPT: br_if $pop{{[0-9]*}}, .LBB13_4{{$}}
; OPT-NEXT: block .LBB13_3{{$}}
; OPT: br_if $pop{{[0-9]*}}, .LBB13_3{{$}}
; OPT: br_if $pop{{[0-9]*}}, .LBB13_7{{$}}
; OPT-NEXT: .param i32{{$}}
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: br_if $pop{{[0-9]*}}, 0{{$}}
; OPT-NEXT: block{{$}}
; OPT: br_if $pop{{[0-9]*}}, 0{{$}}
; OPT: br_if $pop{{[0-9]*}}, 2{{$}}
; OPT-NEXT: .LBB13_3:
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB13_4:
; OPT: br_if $pop{{[0-9]*}}, .LBB13_8{{$}}
; OPT: br_if $pop{{[0-9]*}}, .LBB13_7{{$}}
; OPT: br_if $pop{{[0-9]*}}, 1{{$}}
; OPT: br_if $pop{{[0-9]*}}, 0{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB13_7:
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB13_8:
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: return{{$}}
define void @test4(i32 %t) {
entry:
@ -525,21 +542,21 @@ default:
; CHECK-LABEL: test5:
; CHECK: .LBB14_1:
; CHECK-NEXT: block .LBB14_4{{$}}
; CHECK-NEXT: loop .LBB14_3{{$}}
; CHECK: br_if {{[^,]*}}, .LBB14_4{{$}}
; CHECK: br_if {{[^,]*}}, .LBB14_1{{$}}
; CHECK-NEXT: .LBB14_3:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK: return{{$}}
; CHECK-NEXT: .LBB14_4:
; CHECK: return{{$}}
; OPT-LABEL: test5:
; OPT: .LBB14_1:
; OPT-NEXT: block .LBB14_4{{$}}
; OPT-NEXT: loop .LBB14_3{{$}}
; OPT: br_if {{[^,]*}}, .LBB14_4{{$}}
; OPT: br_if {{[^,]*}}, .LBB14_1{{$}}
; OPT-NEXT: .LBB14_3:
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT: br_if {{[^,]*}}, 2{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT: return{{$}}
; OPT-NEXT: .LBB14_4:
; OPT: return{{$}}
@ -570,40 +587,44 @@ return:
; CHECK-LABEL: test6:
; CHECK: .LBB15_1:
; CHECK-NEXT: block .LBB15_6{{$}}
; CHECK-NEXT: block .LBB15_5{{$}}
; CHECK-NEXT: loop .LBB15_4{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB15_6{{$}}
; CHECK: br_if {{[^,]*}}, 3{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB15_5{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB15_1{{$}}
; CHECK-NEXT: .LBB15_4:
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; CHECK-NEXT: .LBB15_5:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: .LBB15_6:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test6:
; OPT: .LBB15_1:
; OPT-NEXT: block .LBB15_6{{$}}
; OPT-NEXT: block .LBB15_5{{$}}
; OPT-NEXT: loop .LBB15_4{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB15_6{{$}}
; OPT: br_if {{[^,]*}}, 3{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB15_5{{$}}
; OPT: br_if {{[^,]*}}, 2{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB15_1{{$}}
; OPT-NEXT: .LBB15_4:
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NOT: block
; OPT: return{{$}}
; OPT-NEXT: .LBB15_5:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: .LBB15_6:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: return{{$}}
define void @test6(i1 %p, i1 %q) {
@ -640,35 +661,37 @@ second:
; CHECK-LABEL: test7:
; CHECK: .LBB16_1:
; CHECK-NEXT: loop .LBB16_5{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: block .LBB16_4{{$}}
; CHECK: br_if {{[^,]*}}, .LBB16_4{{$}}
; CHECK: block{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB16_1{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NOT: block
; CHECK: unreachable
; CHECK_NEXT: .LBB16_4:
; CHECK-NEXT: .LBB16_4:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB16_1{{$}}
; CHECK-NEXT: .LBB16_5:
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NOT: block
; CHECK: unreachable
; OPT-LABEL: test7:
; OPT: .LBB16_1:
; OPT-NEXT: loop .LBB16_5{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: block .LBB16_4{{$}}
; OPT: block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB16_4{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB16_1{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NOT: block
; OPT: unreachable
; OPT_NEXT: .LBB16_4:
; OPT-NEXT: .LBB16_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB16_1{{$}}
; OPT-NEXT: .LBB16_5:
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NOT: block
; OPT: unreachable
define void @test7(i1 %tobool2, i1 %tobool9) {
@ -701,29 +724,31 @@ u1:
; CHECK-LABEL: test8:
; CHECK: .LBB17_1:
; CHECK-NEXT: loop .LBB17_4{{$}}
; CHECK-NEXT: block .LBB17_3{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB17_3{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB17_1{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NEXT: .LBB17_3:
; CHECK-NEXT: loop .LBB17_4{{$}}
; CHECK-NEXT: br_if {{[^,]*}}, .LBB17_3{{$}}
; CHECK-NEXT: br .LBB17_1{{$}}
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: br 2{{$}}
; CHECK-NEXT: .LBB17_4:
; OPT-LABEL: test8:
; OPT: .LBB17_1:
; OPT-NEXT: loop .LBB17_4{{$}}
; OPT-NEXT: block .LBB17_3{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB17_3{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB17_1{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NEXT: .LBB17_3:
; OPT-NEXT: loop .LBB17_4{{$}}
; OPT-NEXT: br_if {{[^,]*}}, .LBB17_3{{$}}
; OPT-NEXT: br .LBB17_1{{$}}
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: br 2{{$}}
; OPT-NEXT: .LBB17_4:
define i32 @test8() {
bb:
@ -747,43 +772,45 @@ bb3:
; CHECK-LABEL: test9:
; CHECK: .LBB18_1:
; CHECK-NEXT: loop .LBB18_5{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB18_5{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NEXT: .LBB18_2:
; CHECK-NEXT: loop .LBB18_5{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: block .LBB18_4{{$}}
; CHECK: block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB18_4{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB18_2{{$}}
; CHECK-NEXT: br .LBB18_1{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NEXT: br 3{{$}}
; CHECK-NEXT: .LBB18_4:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB18_2{{$}}
; CHECK-NEXT: br .LBB18_1{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: br 2{{$}}
; CHECK-NEXT: .LBB18_5:
; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test9:
; OPT: .LBB18_1:
; OPT-NEXT: loop .LBB18_5{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB18_5{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NEXT: .LBB18_2:
; OPT-NEXT: loop .LBB18_5{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: block .LBB18_4{{$}}
; OPT: block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB18_4{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB18_2{{$}}
; OPT-NEXT: br .LBB18_1{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NEXT: br 3{{$}}
; OPT-NEXT: .LBB18_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB18_2{{$}}
; OPT-NEXT: br .LBB18_1{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: br 2{{$}}
; OPT-NEXT: .LBB18_5:
; OPT-NOT: block
; OPT: return{{$}}
@ -823,45 +850,51 @@ end:
; CHECK-LABEL: test10:
; CHECK: .LBB19_1:
; CHECK-NEXT: loop .LBB19_7{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB19_1{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: .LBB19_2:
; CHECK-NEXT: block .LBB19_6{{$}}
; CHECK-NEXT: loop .LBB19_5{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: .LBB19_3:
; CHECK-NEXT: loop .LBB19_5{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB19_1{{$}}
; CHECK: br_if {{[^,]*}}, 5{{$}}
; CHECK-NOT: block
; CHECK: tableswitch {{[^,]*}}, .LBB19_3, .LBB19_3, .LBB19_5, .LBB19_1, .LBB19_2, .LBB19_6{{$}}
; CHECK: tableswitch {{[^,]*}}, 0, 0, 1, 5, 2, 4{{$}}
; CHECK-NEXT: .LBB19_5:
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB19_6:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br .LBB19_1{{$}}
; CHECK: br 0{{$}}
; CHECK-NEXT: .LBB19_7:
; OPT-LABEL: test10:
; OPT: .LBB19_1:
; OPT-NEXT: loop .LBB19_7{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB19_1{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NEXT: .LBB19_2:
; OPT-NEXT: block .LBB19_6{{$}}
; OPT-NEXT: loop .LBB19_5{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: .LBB19_3:
; OPT-NEXT: loop .LBB19_5{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB19_1{{$}}
; OPT: br_if {{[^,]*}}, 5{{$}}
; OPT-NOT: block
; OPT: tableswitch {{[^,]*}}, .LBB19_3, .LBB19_3, .LBB19_5, .LBB19_1, .LBB19_2, .LBB19_6{{$}}
; OPT: tableswitch {{[^,]*}}, 0, 0, 1, 5, 2, 4{{$}}
; OPT-NEXT: .LBB19_5:
; OPT-NEXT: end_loop{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB19_6:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br .LBB19_1{{$}}
; OPT: br 0{{$}}
; OPT-NEXT: .LBB19_7:
define void @test10() {
bb0:
@ -901,58 +934,67 @@ bb6:
; Test a CFG DAG with interesting merging.
; CHECK-LABEL: test11:
; CHECK: block .LBB20_8{{$}}
; CHECK-NEXT: block .LBB20_7{{$}}
; CHECK-NEXT: block .LBB20_6{{$}}
; CHECK-NEXT: block .LBB20_4{{$}}
; CHECK-NEXT: br_if {{[^,]*}}, .LBB20_4{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: br_if {{[^,]*}}, 0{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NOT: block
; CHECK: block .LBB20_3{{$}}
; CHECK: br_if {{[^,]*}}, .LBB20_3{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB20_6{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK-NEXT: .LBB20_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; CHECK-NEXT: .LBB20_4:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB20_8{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB20_7{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NEXT: .LBB20_6:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; CHECK-NEXT: .LBB20_7:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; CHECK-NEXT: .LBB20_8:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test11:
; OPT: block .LBB20_8{{$}}
; OPT-NEXT: block .LBB20_4{{$}}
; OPT-NEXT: br_if $0, .LBB20_4{{$}}
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: br_if $0, 0{{$}}
; OPT-NEXT: block{{$}}
; OPT-NOT: block
; OPT: block .LBB20_3{{$}}
; OPT: br_if $0, .LBB20_3{{$}}
; OPT: br_if $0, 0{{$}}
; OPT-NOT: block
; OPT: br_if $0, .LBB20_8{{$}}
; OPT: br_if $0, 2{{$}}
; OPT-NEXT: .LBB20_3:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: return{{$}}
; OPT-NEXT: .LBB20_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: block .LBB20_6{{$}}
; OPT: block{{$}}
; OPT-NOT: block
; OPT: br_if $pop9, .LBB20_6{{$}}
; OPT: br_if $pop9, 0{{$}}
; OPT-NOT: block
; OPT: return{{$}}
; OPT-NEXT: .LBB20_6:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br_if $0, .LBB20_8{{$}}
; OPT: br_if $0, 0{{$}}
; OPT-NOT: block
; OPT: return{{$}}
; OPT-NEXT: .LBB20_8:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: return{{$}}
define void @test11() {
@ -987,51 +1029,57 @@ bb8:
; CHECK-LABEL: test12:
; CHECK: .LBB21_1:
; CHECK-NEXT: loop .LBB21_8{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NOT: block
; CHECK: block .LBB21_7{{$}}
; CHECK-NEXT: block .LBB21_6{{$}}
; CHECK-NEXT: block .LBB21_4{{$}}
; CHECK: br_if {{[^,]*}}, .LBB21_4{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: br_if {{[^,]*}}, 0{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB21_7{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB21_7{{$}}
; CHECK-NEXT: br .LBB21_6{{$}}
; CHECK: br_if {{[^,]*}}, 2{{$}}
; CHECK-NEXT: br 1{{$}}
; CHECK-NEXT: .LBB21_4:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB21_7{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NOT: block
; CHECK: br_if {{[^,]*}}, .LBB21_7{{$}}
; CHECK: br_if {{[^,]*}}, 1{{$}}
; CHECK-NEXT: .LBB21_6:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB21_7:
; CHECK-NEXT: end_block{{$}}
; CHECK-NOT: block
; CHECK: br .LBB21_1{{$}}
; CHECK: br 0{{$}}
; CHECK-NEXT: .LBB21_8:
; OPT-LABEL: test12:
; OPT: .LBB21_1:
; OPT-NEXT: loop .LBB21_8{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NOT: block
; OPT: block .LBB21_7{{$}}
; OPT-NEXT: block .LBB21_6{{$}}
; OPT-NEXT: block .LBB21_4{{$}}
; OPT: br_if {{[^,]*}}, .LBB21_4{{$}}
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: br_if {{[^,]*}}, 0{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB21_7{{$}}
; OPT: br_if {{[^,]*}}, 2{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB21_7{{$}}
; OPT-NEXT: br .LBB21_6{{$}}
; OPT: br_if {{[^,]*}}, 2{{$}}
; OPT-NEXT: br 1{{$}}
; OPT-NEXT: .LBB21_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB21_7{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NOT: block
; OPT: br_if {{[^,]*}}, .LBB21_7{{$}}
; OPT: br_if {{[^,]*}}, 1{{$}}
; OPT-NEXT: .LBB21_6:
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB21_7:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: br .LBB21_1{{$}}
; OPT: br 0{{$}}
; OPT-NEXT: .LBB21_8:
define void @test12(i8* %arg) {
bb:
@ -1061,30 +1109,34 @@ bb7:
; optnone to disable optimizations to test this case.
; CHECK-LABEL: test13:
; CHECK-NEXT: .local i32{{$}}
; CHECK: block .LBB22_2{{$}}
; CHECK: br_if $pop4, .LBB22_2{{$}}
; CHECK-NEXT: local i32{{$}}
; CHECK: block{{$}}
; CHECK: br_if $pop4, 0{{$}}
; CHECK-NEXT: return{{$}}
; CHECK-NEXT: .LBB22_2:
; CHECK: block .LBB22_4{{$}}
; CHECK-NEXT: br_if $0, .LBB22_4{{$}}
; CHECK-NEXT: end_block{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: br_if $0, 0{{$}}
; CHECK: .LBB22_4:
; CHECK: block .LBB22_5{{$}}
; CHECK: br_if $pop6, .LBB22_5{{$}}
; CHECK-NEXT: .LBB22_5:
; CHECK-NEXT: end_block{{$}}
; CHECK: block{{$}}
; CHECK: br_if $pop6, 0{{$}}
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: unreachable{{$}}
; OPT-LABEL: test13:
; OPT-NEXT: .local i32{{$}}
; OPT: block .LBB22_2{{$}}
; OPT: br_if $pop4, .LBB22_2{{$}}
; OPT-NEXT: local i32{{$}}
; OPT: block{{$}}
; OPT: br_if $pop4, 0{{$}}
; OPT-NEXT: return{{$}}
; OPT-NEXT: .LBB22_2:
; OPT: block .LBB22_4{{$}}
; OPT-NEXT: br_if $0, .LBB22_4{{$}}
; OPT-NEXT: end_block{{$}}
; OPT: block{{$}}
; OPT-NEXT: br_if $0, 0{{$}}
; OPT: .LBB22_4:
; OPT: block .LBB22_5{{$}}
; OPT: br_if $pop6, .LBB22_5{{$}}
; OPT-NEXT: .LBB22_5:
; OPT-NEXT: end_block{{$}}
; OPT: block{{$}}
; OPT: br_if $pop6, 0{{$}}
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: unreachable{{$}}
define void @test13() noinline optnone {
bb:
@ -1101,3 +1153,65 @@ bb4:
bb5:
ret void
}
; Test a case with a single-block loop that has another loop
; as a successor. The end_loop for the first loop should go
; before the loop for the second.
; CHECK-LABEL: test14:
; CHECK-NEXT: local i32{{$}}
; CHECK-NEXT: i32.const $0=, 0{{$}}
; CHECK-NEXT: .LBB23_1:{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: br_if $0, 0{{$}}
; CHECK-NEXT: .LBB23_2:{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: br_if $0, 0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: return{{$}}
define void @test14() {
bb:
br label %bb1
bb1:
%tmp = bitcast i1 undef to i1
br i1 %tmp, label %bb3, label %bb1
bb3:
br label %bb4
bb4:
br i1 undef, label %bb7, label %bb48
bb7:
br i1 undef, label %bb12, label %bb12
bb12:
br i1 undef, label %bb17, label %bb17
bb17:
br i1 undef, label %bb22, label %bb22
bb22:
br i1 undef, label %bb27, label %bb27
bb27:
br i1 undef, label %bb30, label %bb30
bb30:
br i1 undef, label %bb35, label %bb35
bb35:
br i1 undef, label %bb38, label %bb38
bb38:
br i1 undef, label %bb48, label %bb48
bb48:
%tmp49 = bitcast i1 undef to i1
br i1 %tmp49, label %bb3, label %bb50
bb50:
ret void
}

View File

@ -55,7 +55,7 @@ define i32 @yes1(i32* %q) {
; CHECK-NEXT: .local i32, i32{{$}}
; CHECK-NEXT: i32.const $5=, 2{{$}}
; CHECK-NEXT: i32.const $4=, 1{{$}}
; CHECK-NEXT: block .LBB4_2{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: i32.lt_s $push0=, $0, $4{{$}}
; CHECK-NEXT: i32.lt_s $push1=, $1, $5{{$}}
; CHECK-NEXT: i32.xor $push4=, $pop0, $pop1{{$}}
@ -64,10 +64,11 @@ define i32 @yes1(i32* %q) {
; CHECK-NEXT: i32.xor $push5=, $pop2, $pop3{{$}}
; CHECK-NEXT: i32.xor $push6=, $pop4, $pop5{{$}}
; CHECK-NEXT: i32.ne $push7=, $pop6, $4{{$}}
; CHECK-NEXT: br_if $pop7, .LBB4_2{{$}}
; CHECK-NEXT: br_if $pop7, 0{{$}}
; CHECK-NEXT: i32.const $push8=, 0{{$}}
; CHECK-NEXT: return $pop8{{$}}
; CHECK-NEXT: .LBB4_2:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return $4{{$}}
define i32 @stack_uses(i32 %x, i32 %y, i32 %z, i32 %w) {
entry:
@ -89,16 +90,17 @@ false:
; be trivially stackified.
; CHECK-LABEL: multiple_uses:
; CHECK-NEXT: .param i32, i32, i32{{$}}
; CHECK-NEXT: .local i32{{$}}
; CHECK-NEXT: .param i32, i32, i32{{$}}
; CHECK-NEXT: .local i32{{$}}
; CHECK-NEXT: i32.load $3=, 0($2){{$}}
; CHECK-NEXT: block .LBB5_3{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: i32.ge_u $push0=, $3, $1{{$}}
; CHECK-NEXT: br_if $pop0, .LBB5_3{{$}}
; CHECK-NEXT: br_if $pop0, 0{{$}}
; CHECK-NEXT: i32.lt_u $push1=, $3, $0{{$}}
; CHECK-NEXT: br_if $pop1, .LBB5_3{{$}}
; CHECK-NEXT: br_if $pop1, 0{{$}}
; CHECK-NEXT: i32.store $discard=, 0($2), $3{{$}}
; CHECK-NEXT: .LBB5_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
define void @multiple_uses(i32* %arg0, i32* %arg1, i32* %arg2) nounwind {
bb:

View File

@ -14,14 +14,14 @@ declare void @foo4()
declare void @foo5()
; CHECK-LABEL: bar32:
; CHECK: block .LBB0_8{{$}}
; CHECK: block .LBB0_7{{$}}
; CHECK: block .LBB0_6{{$}}
; CHECK: block .LBB0_5{{$}}
; CHECK: block .LBB0_4{{$}}
; CHECK: block .LBB0_3{{$}}
; CHECK: block .LBB0_2{{$}}
; CHECK: tableswitch {{[^,]*}}, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_5, .LBB0_6, .LBB0_7{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: tableswitch {{[^,]*}}, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5{{$}}
; CHECK: .LBB0_2:
; CHECK: call foo0@FUNCTION{{$}}
; CHECK: .LBB0_3:
@ -94,14 +94,14 @@ sw.epilog: ; preds = %entry, %sw.bb.5, %s
}
; CHECK-LABEL: bar64:
; CHECK: block .LBB1_8{{$}}
; CHECK: block .LBB1_7{{$}}
; CHECK: block .LBB1_6{{$}}
; CHECK: block .LBB1_5{{$}}
; CHECK: block .LBB1_4{{$}}
; CHECK: block .LBB1_3{{$}}
; CHECK: block .LBB1_2{{$}}
; CHECK: tableswitch {{[^,]*}}, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_5, .LBB1_6, .LBB1_7{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: tableswitch {{[^,]*}}, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5{{$}}
; CHECK: .LBB1_2:
; CHECK: call foo0@FUNCTION{{$}}
; CHECK: .LBB1_3: