[WebAssemby] Implement block signatures.

Per spec changes, this implements block signatures, and adds just enough
logic to produce correct block signatures at the ends of functions.

Differential Revision: https://reviews.llvm.org/D25144

llvm-svn: 283503
This commit is contained in:
Dan Gohman 2016-10-06 22:29:32 +00:00
parent 3a643e8d46
commit 2726b88c03
15 changed files with 317 additions and 177 deletions

View File

@ -195,6 +195,26 @@ WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
O << ":p2align=" << Imm;
}
void
WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
int64_t Imm = MI->getOperand(OpNo).getImm();
switch (Imm) {
case WebAssembly::Void: break;
case WebAssembly::I32: O << "i32"; break;
case WebAssembly::I64: O << "i64"; break;
case WebAssembly::F32: O << "f32"; break;
case WebAssembly::F64: O << "f64"; break;
case WebAssembly::I8x16: O << "i8x16"; break;
case WebAssembly::I16x8: O << "i16x8"; break;
case WebAssembly::I32x4: O << "i32x4"; break;
case WebAssembly::I64x2: O << "i32x4"; break;
case WebAssembly::F32x4: O << "f32x4"; break;
case WebAssembly::F64x2: O << "f64x2"; break;
}
}
const char *llvm::WebAssembly::TypeToString(MVT Ty) {
switch (Ty.SimpleTy) {
case MVT::i32:

View File

@ -39,6 +39,8 @@ public:
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);

View File

@ -53,7 +53,9 @@ enum OperandType {
/// 64-bit floating-point immediates.
OPERAND_F64IMM,
/// p2align immediate for load and store address alignment.
OPERAND_P2ALIGN
OPERAND_P2ALIGN,
/// signature immediate for block/loop.
OPERAND_SIGNATURE
};
/// WebAssembly-specific directive identifiers.
@ -63,7 +65,7 @@ enum Directive {
DotResult = UINT64_MAX - 1, ///< .result
DotLocal = UINT64_MAX - 2, ///< .local
DotEndFunc = UINT64_MAX - 3, ///< .endfunc
DotIndIdx = UINT64_MAX - 4, /// < .indidx
DotIndIdx = UINT64_MAX - 4, ///< .indidx
};
} // end namespace WebAssembly
@ -141,6 +143,21 @@ static const unsigned StoreAddressOperandNo = 1;
static const unsigned LoadP2AlignOperandNo = 3;
static const unsigned StoreP2AlignOperandNo = 2;
/// This is used to indicate block signatures.
enum ExprType {
Void = 0,
I32 = 1,
I64 = 2,
F32 = 3,
F64 = 4,
I8x16 = 5,
I16x8 = 6,
I32x4 = 7,
I64x2 = 8,
F32x4 = 9,
F64x2 = 10
};
} // end namespace WebAssembly
} // end namespace llvm

View File

@ -65,14 +65,17 @@ void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
StringRef name, SmallVectorImpl<MVT> &SignatureVTs, size_t NumResults) {
StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
OS << "\t.functype\t" << name;
if (NumResults == 0)
if (Results.empty())
OS << ", void";
for (auto Ty : SignatureVTs) {
OS << ", " << WebAssembly::TypeToString(Ty);
else {
assert(Results.size() == 1);
OS << ", " << WebAssembly::TypeToString(Results.front());
}
OS << "\n";
for (auto Ty : Params)
OS << ", " << WebAssembly::TypeToString(Ty);
OS << '\n';
}
void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {

View File

@ -39,8 +39,8 @@ public:
virtual void emitEndFunc() = 0;
/// .functype
virtual void emitIndirectFunctionType(StringRef name,
SmallVectorImpl<MVT> &SignatureVTs,
size_t NumResults) {
SmallVectorImpl<MVT> &Params,
SmallVectorImpl<MVT> &Results) {
llvm_unreachable("emitIndirectFunctionType not implemented");
}
/// .indidx
@ -59,8 +59,8 @@ public:
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
void emitIndirectFunctionType(StringRef name,
SmallVectorImpl<MVT> &SignatureVTs,
size_t NumResults) override;
SmallVectorImpl<MVT> &Params,
SmallVectorImpl<MVT> &Results) override;
void emitIndIdx(const MCExpr *Value) override;
};

View File

@ -121,45 +121,16 @@ WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
//===----------------------------------------------------------------------===//
// WebAssemblyAsmPrinter Implementation.
//===----------------------------------------------------------------------===//
static void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
const DataLayout &DL(F.getParent()->getDataLayout());
const WebAssemblyTargetLowering &TLI =
*TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
SmallVector<EVT, 4> VTs;
ComputeValueVTs(TLI, DL, Ty, VTs);
for (EVT VT : VTs) {
unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT);
MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT);
for (unsigned i = 0; i != NumRegs; ++i)
ValueVTs.push_back(RegisterVT);
}
}
void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
for (const auto &F : M) {
// Emit function type info for all undefined functions
if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
SmallVector<MVT, 4> SignatureVTs;
ComputeLegalValueVTs(F, TM, F.getReturnType(), SignatureVTs);
size_t NumResults = SignatureVTs.size();
if (SignatureVTs.size() > 1) {
// WebAssembly currently can't lower returns of multiple values without
// demoting to sret (see WebAssemblyTargetLowering::CanLowerReturn). So
// replace multiple return values with a pointer parameter.
SignatureVTs.clear();
SignatureVTs.push_back(
MVT::getIntegerVT(M.getDataLayout().getPointerSizeInBits()));
NumResults = 0;
}
for (auto &Arg : F.args()) {
ComputeLegalValueVTs(F, TM, Arg.getType(), SignatureVTs);
}
getTargetStreamer()->emitIndirectFunctionType(F.getName(), SignatureVTs,
NumResults);
SmallVector<MVT, 4> Results;
SmallVector<MVT, 4> Params;
ComputeSignatureVTs(F, TM, Params, Results);
getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params,
Results);
}
}
}

View File

@ -309,7 +309,8 @@ static bool IsChild(const MachineInstr &MI,
static void PlaceBlockMarker(
MachineBasicBlock &MBB, MachineFunction &MF,
SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops,
DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
const WebAssemblyInstrInfo &TII,
const MachineLoopInfo &MLI,
MachineDominatorTree &MDT,
@ -372,15 +373,19 @@ static void PlaceBlockMarker(
}
// Add the BLOCK.
BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK));
MachineInstr *Begin = BuildMI(*Header, InsertPos, DebugLoc(),
TII.get(WebAssembly::BLOCK))
.addImm(WebAssembly::Void);
// Mark the end of the block.
InsertPos = MBB.begin();
while (InsertPos != MBB.end() &&
InsertPos->getOpcode() == WebAssembly::END_LOOP &&
LoopTops[&*InsertPos]->getNumber() >= Header->getNumber())
LoopTops[&*InsertPos]->getParent()->getNumber() >= Header->getNumber())
++InsertPos;
BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK));
MachineInstr *End = BuildMI(MBB, InsertPos, DebugLoc(),
TII.get(WebAssembly::END_BLOCK));
BlockTops[End] = Begin;
// Track the farthest-spanning scope that ends at this point.
int Number = MBB.getNumber();
@ -393,7 +398,7 @@ static void PlaceBlockMarker(
static void PlaceLoopMarker(
MachineBasicBlock &MBB, MachineFunction &MF,
SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops,
DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) {
MachineLoop *Loop = MLI.getLoopFor(&MBB);
if (!Loop || Loop->getHeader() != &MBB)
@ -418,12 +423,14 @@ static void PlaceLoopMarker(
while (InsertPos != MBB.end() &&
InsertPos->getOpcode() == WebAssembly::END_LOOP)
++InsertPos;
BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP));
MachineInstr *Begin = BuildMI(MBB, InsertPos, DebugLoc(),
TII.get(WebAssembly::LOOP))
.addImm(WebAssembly::Void);
// Mark the end of the loop.
MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(),
TII.get(WebAssembly::END_LOOP));
LoopTops[End] = &MBB;
LoopTops[End] = Begin;
assert((!ScopeTops[AfterLoop->getNumber()] ||
ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
@ -445,6 +452,56 @@ GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
return Depth;
}
/// In normal assembly languages, when the end of a function is unreachable,
/// because the function ends in an infinite loop or a noreturn call or similar,
/// it isn't necessary to worry about the function return type at the end of
/// the function, because it's never reached. However, in WebAssembly, blocks
/// that end at the function end need to have a return type signature that
/// matches the function signature, even though it's unreachable. This function
/// checks for such cases and fixes up the signatures.
static void FixEndsAtEndOfFunction(
MachineFunction &MF,
const WebAssemblyFunctionInfo &MFI,
DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
DenseMap<const MachineInstr *, MachineInstr *> &LoopTops) {
assert(MFI.getResults().size() <= 1);
if (MFI.getResults().empty())
return;
WebAssembly::ExprType retType;
switch (MFI.getResults().front().SimpleTy) {
case MVT::i32: retType = WebAssembly::I32; break;
case MVT::i64: retType = WebAssembly::I64; break;
case MVT::f32: retType = WebAssembly::F32; break;
case MVT::f64: retType = WebAssembly::F64; break;
case MVT::v16i8: retType = WebAssembly::I8x16; break;
case MVT::v8i16: retType = WebAssembly::I16x8; break;
case MVT::v4i32: retType = WebAssembly::I32x4; break;
case MVT::v2i64: retType = WebAssembly::I64x2; break;
case MVT::v4f32: retType = WebAssembly::F32x4; break;
case MVT::v2f64: retType = WebAssembly::F64x2; break;
default: llvm_unreachable("unexpected return type");
}
for (MachineBasicBlock &MBB : reverse(MF)) {
for (MachineInstr &MI : reverse(MBB)) {
if (MI.isPosition() || MI.isDebugValue())
continue;
if (MI.getOpcode() == WebAssembly::END_BLOCK) {
BlockTops[&MI]->getOperand(0).setImm(int32_t(retType));
continue;
}
if (MI.getOpcode() == WebAssembly::END_LOOP) {
LoopTops[&MI]->getOperand(0).setImm(int32_t(retType));
continue;
}
// Something other than an `end`. We're done.
return;
}
}
}
/// Insert LOOP and BLOCK markers at appropriate places.
static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
const WebAssemblyInstrInfo &TII,
@ -457,15 +514,18 @@ 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 each LOOP_END, the corresponding LOOP.
DenseMap<const MachineInstr *, MachineInstr *> LoopTops;
// For each END_BLOCK, the corresponding BLOCK.
DenseMap<const MachineInstr *, MachineInstr *> BlockTops;
for (auto &MBB : MF) {
// Place the LOOP for MBB if MBB is the header of a loop.
PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI);
// Place the BLOCK for MBB if MBB is branched to from above.
PlaceBlockMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI, MDT, MFI);
PlaceBlockMarker(MBB, MF, ScopeTops, BlockTops, LoopTops, TII, MLI, MDT, MFI);
}
// Now rewrite references to basic blocks to be depth immediates.
@ -486,7 +546,7 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
Stack.push_back(&MBB);
break;
case WebAssembly::END_LOOP:
Stack.push_back(LoopTops[&MI]);
Stack.push_back(LoopTops[&MI]->getParent());
break;
default:
if (MI.isTerminator()) {
@ -505,6 +565,10 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
}
}
assert(Stack.empty() && "Control flow should be balanced");
// Fix up block/loop signatures at the end of the function to conform to
// WebAssembly's rules.
FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);
}
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {

View File

@ -481,12 +481,12 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
if (!CallingConvSupported(CallConv))
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
MachineFunction &MF = DAG.getMachineFunction();
auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
// Set up the incoming ARGUMENTS value, which serves to represent the liveness
// of the incoming values before they're represented by virtual registers.
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
@ -526,6 +526,13 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
MFI->addParam(PtrVT);
}
// Record the number and types of results.
SmallVector<MVT, 4> Params;
SmallVector<MVT, 4> Results;
ComputeSignatureVTs(*MF.getFunction(), DAG.getTarget(), Params, Results);
for (MVT VT : Results)
MFI->addResult(VT);
return Chain;
}

View File

@ -61,8 +61,8 @@ def BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops),
// use/clobber VALUE_STACK to prevent them from being moved into the middle of
// an expression tree.
let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
def BLOCK : I<(outs), (ins), [], "block", 0x01>;
def LOOP : I<(outs), (ins), [], "loop", 0x02>;
def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig", 0x01>;
def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x02>;
def END_BLOCK : I<(outs), (ins), [], "end_block">;
def END_LOOP : I<(outs), (ins), [], "end_loop">;
} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]

View File

@ -89,6 +89,12 @@ def P2Align : Operand<i32> {
}
} // OperandType = "OPERAND_P2ALIGN"
let OperandType = "OPERAND_SIGNATURE" in {
def Signature : Operand<i32> {
let PrintMethod = "printWebAssemblySignatureOperand";
}
} // OperandType = "OPERAND_SIGNATURE"
} // OperandNamespace = "WebAssembly"
//===----------------------------------------------------------------------===//

View File

@ -14,6 +14,9 @@
//===----------------------------------------------------------------------===//
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyISelLowering.h"
#include "WebAssemblySubtarget.h"
#include "llvm/CodeGen/Analysis.h"
using namespace llvm;
WebAssemblyFunctionInfo::~WebAssemblyFunctionInfo() {}
@ -23,3 +26,37 @@ void WebAssemblyFunctionInfo::initWARegs() {
unsigned Reg = UnusedReg;
WARegs.resize(MF.getRegInfo().getNumVirtRegs(), Reg);
}
void llvm::ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
const DataLayout &DL(F.getParent()->getDataLayout());
const WebAssemblyTargetLowering &TLI =
*TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
SmallVector<EVT, 4> VTs;
ComputeValueVTs(TLI, DL, Ty, VTs);
for (EVT VT : VTs) {
unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT);
MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT);
for (unsigned i = 0; i != NumRegs; ++i)
ValueVTs.push_back(RegisterVT);
}
}
void llvm::ComputeSignatureVTs(const Function &F, const TargetMachine &TM,
SmallVectorImpl<MVT> &Params,
SmallVectorImpl<MVT> &Results) {
ComputeLegalValueVTs(F, TM, F.getReturnType(), Results);
if (Results.size() > 1) {
// WebAssembly currently can't lower returns of multiple values without
// demoting to sret (see WebAssemblyTargetLowering::CanLowerReturn). So
// replace multiple return values with a pointer parameter.
Results.clear();
Params.push_back(
MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()));
}
for (auto &Arg : F.args())
ComputeLegalValueVTs(F, TM, Arg.getType(), Params);
}

View File

@ -27,6 +27,7 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
MachineFunction &MF;
std::vector<MVT> Params;
std::vector<MVT> Results;
/// A mapping from CodeGen vreg index to WebAssembly register number.
std::vector<unsigned> WARegs;
@ -51,6 +52,9 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
void addParam(MVT VT) { Params.push_back(VT); }
const std::vector<MVT> &getParams() const { return Params; }
void addResult(MVT VT) { Results.push_back(VT); }
const std::vector<MVT> &getResults() const { return Results; }
unsigned getVarargBufferVreg() const {
assert(VarargVreg != -1U && "Vararg vreg hasn't been set");
return VarargVreg;
@ -88,6 +92,13 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
}
};
void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
Type *Ty, SmallVectorImpl<MVT> &ValueVTs);
void ComputeSignatureVTs(const Function &F, const TargetMachine &TM,
SmallVectorImpl<MVT> &Params,
SmallVectorImpl<MVT> &Results);
} // end namespace llvm
#endif

View File

@ -105,7 +105,7 @@ back:
; CHECK-LABEL: test2:
; CHECK-NOT: local
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK: .LBB2_{{[0-9]+}}:
; CHECK: loop
@ -116,7 +116,7 @@ back:
; CHECK: return{{$}}
; OPT-LABEL: test2:
; OPT-NOT: local
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: .LBB2_{{[0-9]+}}:
; OPT: loop
@ -151,13 +151,13 @@ for.end:
}
; CHECK-LABEL: doublediamond:
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, ${{[^,]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_2:
; CHECK-NEXT: end_block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, ${{[^,]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB3_4:
@ -167,9 +167,9 @@ for.end:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: doublediamond:
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, ${{[^,]+}}{{$}}
; OPT: br_if 1, ${{[^,]+}}{{$}}
; OPT: br 2{{$}}
@ -204,12 +204,12 @@ exit:
}
; CHECK-LABEL: triangle:
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB4_2:
; CHECK: return
; OPT-LABEL: triangle:
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, $1{{$}}
; OPT: .LBB4_2:
; OPT: return
@ -227,8 +227,8 @@ exit:
}
; CHECK-LABEL: diamond:
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB5_2:
@ -236,8 +236,8 @@ exit:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: diamond:
; OPT: block{{$}}
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br 1{{$}}
; OPT: .LBB5_2:
@ -275,16 +275,18 @@ entry:
; CHECK-LABEL: minimal_loop:
; CHECK-NOT: br
; CHECK: .LBB7_1:
; CHECK: loop i32
; CHECK: i32.store 0($0), $pop{{[0-9]+}}{{$}}
; CHECK: br 0{{$}}
; CHECK: .LBB7_2:
; OPT-LABEL: minimal_loop:
; OPT-NOT: br
; OPT: .LBB7_1:
; OPT: loop i32
; OPT: i32.store 0($0), $pop{{[0-9]+}}{{$}}
; OPT: br 0{{$}}
; OPT: .LBB7_2:
define void @minimal_loop(i32* %p) {
define i32 @minimal_loop(i32* %p) {
entry:
store volatile i32 0, i32* %p
br label %loop
@ -296,7 +298,7 @@ loop:
; CHECK-LABEL: simple_loop:
; CHECK-NOT: br
; CHECK: .LBB8_1:
; CHECK: loop{{$}}
; CHECK: loop {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
@ -304,7 +306,7 @@ loop:
; OPT-LABEL: simple_loop:
; OPT-NOT: br
; OPT: .LBB8_1:
; OPT: loop{{$}}
; OPT: loop {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: end_loop{{$}}
; OPT: i32.const $push{{[0-9]+}}=, 0{{$}}
@ -323,17 +325,17 @@ exit:
}
; CHECK-LABEL: doubletriangle:
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: .LBB9_3:
; CHECK: .LBB9_4:
; CHECK: return
; OPT-LABEL: doubletriangle:
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, $0{{$}}
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, $1{{$}}
; OPT: .LBB9_3:
; OPT: .LBB9_4:
@ -359,8 +361,8 @@ exit:
}
; CHECK-LABEL: ifelse_earlyexits:
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB10_2:
@ -369,8 +371,8 @@ exit:
; CHECK: i32.const $push{{[0-9]+}}=, 0{{$}}
; CHECK-NEXT: return $pop{{[0-9]+}}{{$}}
; OPT-LABEL: ifelse_earlyexits:
; OPT: block{{$}}
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br_if 1, $1{{$}}
; OPT: br 1{{$}}
@ -400,13 +402,13 @@ exit:
; CHECK-LABEL: doublediamond_in_a_loop:
; CHECK: .LBB11_1:
; CHECK: loop{{$}}
; CHECK: block{{$}}
; CHECK: loop i32{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $0{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_3:
; CHECK: end_block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $1{{$}}
; CHECK: br 1{{$}}
; CHECK: .LBB11_5:
@ -415,10 +417,10 @@ exit:
; CHECK-NEXT: end_loop{{$}}
; OPT-LABEL: doublediamond_in_a_loop:
; OPT: .LBB11_1:
; OPT: loop{{$}}
; OPT: block{{$}}
; OPT: loop i32{{$}}
; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: br 2{{$}}
; OPT-NEXT: .LBB11_4:
@ -429,7 +431,7 @@ exit:
; OPT: br 0{{$}}
; OPT: .LBB11_6:
; OPT-NEXT: end_loop{{$}}
define void @doublediamond_in_a_loop(i32 %a, i32 %b, i32* %p) {
define i32 @doublediamond_in_a_loop(i32 %a, i32 %b, i32* %p) {
entry:
br label %header
header:
@ -513,14 +515,14 @@ if.end:
; CHECK-LABEL: test4:
; CHECK-NEXT: .param i32{{$}}
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK: br_if 1, $pop{{[0-9]+}}{{$}}
; CHECK: br 1{{$}}
; CHECK-NEXT: .LBB13_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop{{[0-9]+}}{{$}}
; CHECK: br_if 1, $pop{{[0-9]+}}{{$}}
; CHECK-NEXT: .LBB13_5:
@ -531,14 +533,14 @@ if.end:
; CHECK-NEXT: return{{$}}
; OPT-LABEL: test4:
; OPT-NEXT: .param i32{{$}}
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT: br_if 1, $pop{{[0-9]+}}{{$}}
; OPT: br 1{{$}}
; OPT-NEXT: .LBB13_3:
; OPT-NEXT: end_block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT: br_if 1, $pop{{[0-9]+}}{{$}}
; OPT-NEXT: .LBB13_5:
@ -574,8 +576,8 @@ default:
; CHECK-LABEL: test5:
; CHECK: .LBB14_1:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK: br_if 1, {{[^,]+}}{{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NEXT: end_loop{{$}}
@ -584,8 +586,8 @@ default:
; CHECK: return{{$}}
; OPT-LABEL: test5:
; OPT: .LBB14_1:
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: loop {{$}}
; OPT: br_if 1, {{[^,]+}}{{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: end_loop{{$}}
@ -619,9 +621,9 @@ return:
; CHECK-LABEL: test6:
; CHECK: .LBB15_1:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 2, {{[^,]+}}{{$}}
; CHECK-NOT: block
@ -640,9 +642,9 @@ return:
; CHECK: return{{$}}
; OPT-LABEL: test6:
; OPT: .LBB15_1:
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 2, {{[^,]+}}{{$}}
; OPT-NOT: block
@ -693,9 +695,9 @@ second:
; CHECK-LABEL: test7:
; CHECK: .LBB16_1:
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
@ -711,9 +713,9 @@ second:
; OPT-LABEL: test7:
; OPT: .LBB16_1:
; OPT-NEXT: block
; OPT-NEXT: loop{{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
@ -760,7 +762,7 @@ u1:
; CHECK-LABEL: test8:
; CHECK: .LBB17_1:
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop i32{{$}}
; CHECK-NEXT: i32.const $push{{[^,]+}}, 0{{$}}
; CHECK-NEXT: br_if 0, {{[^,]+}}{{$}}
; CHECK-NEXT: br 0{{$}}
@ -768,13 +770,13 @@ u1:
; CHECK-NEXT: end_loop{{$}}
; OPT-LABEL: test8:
; OPT: .LBB17_1:
; OPT-NEXT: loop{{$}}
; OPT-NEXT: loop i32{{$}}
; OPT-NEXT: i32.const $push{{[^,]+}}, 0{{$}}
; OPT-NEXT: br_if 0, {{[^,]+}}{{$}}
; OPT-NEXT: br 0{{$}}
; OPT-NEXT: .LBB17_2:
; OPT-NEXT: end_loop{{$}}
define void @test8() {
define i32 @test8() {
bb:
br label %bb1
@ -796,14 +798,14 @@ bb3:
; CHECK-LABEL: test9:
; CHECK: .LBB18_1:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
; CHECK-NEXT: .LBB18_2:
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK-NOT: block
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
@ -821,14 +823,14 @@ bb3:
; CHECK: return{{$}}
; OPT-LABEL: test9:
; OPT: .LBB18_1:
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
; OPT-NEXT: .LBB18_2:
; OPT-NEXT: loop{{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
@ -880,18 +882,18 @@ end:
; CHECK-LABEL: test10:
; CHECK: .LBB19_1:
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK: .LBB19_3:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: .LBB19_4:
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: br_if 3, {{[^,]+}}{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_table {{[^,]+}}, 1, 0, 4, 2, 3, 1{{$}}
; CHECK-NEXT: .LBB19_6:
; CHECK-NEXT: end_block{{$}}
@ -905,15 +907,15 @@ end:
; CHECK-NEXT: .LBB19_8:
; OPT-LABEL: test10:
; OPT: .LBB19_1:
; OPT-NEXT: loop{{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT: .LBB19_3:
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: .LBB19_4:
; OPT-NEXT: loop{{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: br_if 3, {{[^,]+}}{{$}}
; OPT: block
@ -966,13 +968,13 @@ bb6:
; Test a CFG DAG with interesting merging.
; CHECK-LABEL: test11:
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK-NEXT: i32.const
; CHECK-NEXT: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
@ -1000,11 +1002,11 @@ bb6:
; CHECK-NOT: block
; CHECK: return{{$}}
; OPT-LABEL: test11:
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT: block {{$}}
; OPT-NEXT: i32.const
; OPT-NEXT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
@ -1016,7 +1018,7 @@ bb6:
; OPT-NEXT: .LBB20_4:
; OPT-NEXT: end_block{{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT: block {{$}}
; OPT-NOT: block
; OPT: br_if 0, $pop{{[0-9]+}}{{$}}
; OPT-NOT: block
@ -1063,11 +1065,11 @@ bb8:
; CHECK-LABEL: test12:
; CHECK: .LBB21_1:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NOT: block
; CHECK: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, {{[^,]+}}{{$}}
; CHECK-NOT: block
; CHECK: br_if 1, {{[^,]+}}{{$}}
@ -1090,11 +1092,11 @@ bb8:
; CHECK-NEXT: return{{$}}
; OPT-LABEL: test12:
; OPT: .LBB21_1:
; OPT-NEXT: block{{$}}
; OPT-NEXT: loop{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: loop {{$}}
; OPT-NOT: block
; OPT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, {{[^,]+}}{{$}}
; OPT-NOT: block
; OPT: br_if 1, {{[^,]+}}{{$}}
@ -1143,10 +1145,10 @@ bb7:
; CHECK-LABEL: test13:
; CHECK-NEXT: .local i32{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK: br_if 0, $pop0{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: br_if 0, $pop3{{$}}
; CHECK: .LBB22_3:
; CHECK-NEXT: end_block{{$}}
@ -1160,10 +1162,10 @@ bb7:
; CHECK-NEXT: unreachable{{$}}
; OPT-LABEL: test13:
; OPT-NEXT: .local i32{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block{{$}}
; OPT-NEXT: block {{$}}
; OPT-NEXT: block {{$}}
; OPT: br_if 0, $pop0{{$}}
; OPT: block{{$}}
; OPT: block {{$}}
; OPT: br_if 0, $pop3{{$}}
; OPT: .LBB22_3:
; OPT-NEXT: end_block{{$}}
@ -1197,12 +1199,12 @@ bb5:
; CHECK-LABEL: test14:
; CHECK-NEXT: .LBB23_1:{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NEXT: i32.const $push0=, 0{{$}}
; CHECK-NEXT: br_if 0, $pop0{{$}}
; CHECK-NEXT: end_loop{{$}}
; CHECK-NEXT: .LBB23_3:{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: loop {{$}}
; CHECK-NEXT: i32.const $push1=, 0{{$}}
; CHECK-NEXT: br_if 0, $pop1{{$}}
; CHECK-NEXT: end_loop{{$}}
@ -1261,9 +1263,9 @@ bb50:
; CHECK-NEXT: block
; CHECK: br_if 0, $pop{{.*}}{{$}}
; CHECK: .LBB24_2:
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: loop{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: loop {{$}}
; CHECK: br_if 1, $pop{{.*}}{{$}}
; CHECK: br_if 0, ${{.*}}{{$}}
; CHECK-NEXT: br 2{{$}}

View File

@ -84,7 +84,7 @@ define i32 @no_sink_readonly_call(i32 %x, i32 %y, i32* %p) {
; CHECK-LABEL: stack_uses:
; CHECK: .param i32, i32, i32, i32{{$}}
; CHECK-NEXT: .result i32{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: i32.const $push[[L13:[0-9]+]]=, 1{{$}}
; CHECK-NEXT: i32.lt_s $push[[L0:[0-9]+]]=, $0, $pop[[L13]]{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 2{{$}}
@ -127,7 +127,7 @@ false:
; CHECK-LABEL: multiple_uses:
; CHECK: .param i32, i32, i32{{$}}
; CHECK-NEXT: .local i32{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: block {{$}}
; CHECK-NEXT: i32.load $push[[NUM0:[0-9]+]]=, 0($2){{$}}
; CHECK-NEXT: tee_local $push[[NUM1:[0-9]+]]=, $3=, $pop[[NUM0]]{{$}}
; CHECK-NEXT: i32.ge_u $push[[NUM2:[0-9]+]]=, $pop[[NUM1]], $1{{$}}

View File

@ -14,13 +14,13 @@ declare void @foo4()
declare void @foo5()
; CHECK-LABEL: bar32:
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}}
; CHECK: .LBB0_2:
; CHECK: call foo0@FUNCTION{{$}}
@ -94,13 +94,13 @@ sw.epilog: ; preds = %entry, %sw.bb.5, %s
}
; CHECK-LABEL: bar64:
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block{{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: block {{$}}
; CHECK: br_table {{[^,]+}}, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0{{$}}
; CHECK: .LBB1_2:
; CHECK: call foo0@FUNCTION{{$}}