Index: lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h =================================================================== --- lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h +++ lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h @@ -39,6 +39,8 @@ 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); Index: lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp =================================================================== --- lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -200,6 +200,26 @@ 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: Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -49,7 +49,9 @@ /// 64-bit floating-point immediates. OPERAND_FP64IMM, /// p2align immediate for load and store address alignment. - OPERAND_P2ALIGN + OPERAND_P2ALIGN, + /// signature immediate for block/loop. + OPERAND_SIGNATURE }; /// WebAssembly-specific directive identifiers. @@ -59,7 +61,7 @@ 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 @@ -134,6 +136,21 @@ /// The operand number of the stored value in a store instruction. static const unsigned StoreValueOperandNo = 4; +/// 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 Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -39,8 +39,8 @@ virtual void emitEndFunc() = 0; /// .functype virtual void emitIndirectFunctionType(StringRef name, - SmallVectorImpl &SignatureVTs, - size_t NumResults) { + SmallVectorImpl &Params, + SmallVectorImpl &Results) { llvm_unreachable("emitIndirectFunctionType not implemented"); } /// .indidx @@ -59,8 +59,8 @@ void emitLocal(ArrayRef Types) override; void emitEndFunc() override; void emitIndirectFunctionType(StringRef name, - SmallVectorImpl &SignatureVTs, - size_t NumResults) override; + SmallVectorImpl &Params, + SmallVectorImpl &Results) override; void emitIndIdx(const MCExpr *Value) override; }; Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -65,14 +65,17 @@ void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; } void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType( - StringRef name, SmallVectorImpl &SignatureVTs, size_t NumResults) { + StringRef name, SmallVectorImpl &Params, SmallVectorImpl &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) { Index: lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -126,45 +126,16 @@ //===----------------------------------------------------------------------===// // WebAssemblyAsmPrinter Implementation. //===----------------------------------------------------------------------===// -static void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM, - Type *Ty, SmallVectorImpl &ValueVTs) { - const DataLayout &DL(F.getParent()->getDataLayout()); - const WebAssemblyTargetLowering &TLI = - *TM.getSubtarget(F).getTargetLowering(); - SmallVector 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 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 Results; + SmallVector Params; + ComputeSignatureVTs(F, TM, Params, Results); + getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params, + Results); } } } Index: lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -308,12 +308,14 @@ } /// Insert a BLOCK marker for branches to MBB (if needed). -static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF, - SmallVectorImpl &ScopeTops, - const WebAssemblyInstrInfo &TII, - const MachineLoopInfo &MLI, - MachineDominatorTree &MDT, - WebAssemblyFunctionInfo &MFI) { +static void PlaceBlockMarker( + MachineBasicBlock &MBB, MachineFunction &MF, + SmallVectorImpl &ScopeTops, + DenseMap &BlockTops, + const WebAssemblyInstrInfo &TII, + const MachineLoopInfo &MLI, + MachineDominatorTree &MDT, + WebAssemblyFunctionInfo &MFI) { // First compute the nearest common dominator of all forward non-fallthrough // predecessors so that we minimize the time that the BLOCK is on the stack, // which reduces overall stack height. @@ -378,14 +380,18 @@ } // 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) ++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(); @@ -398,7 +404,7 @@ static void PlaceLoopMarker( MachineBasicBlock &MBB, MachineFunction &MF, SmallVectorImpl &ScopeTops, - DenseMap &LoopTops, + DenseMap &LoopTops, const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) { MachineLoop *Loop = MLI.getLoopFor(&MBB); if (!Loop || Loop->getHeader() != &MBB) @@ -423,12 +429,14 @@ 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()) && @@ -450,6 +458,52 @@ return Depth; } +static void FixEndOfFunctionEnds( + MachineFunction &MF, + const WebAssemblyFunctionInfo &MFI, + DenseMap &BlockTops, + DenseMap &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 (MachineFunction::reverse_iterator MBBI = MF.rbegin(); + MBBI != MF.rend(); ++MBBI) { + for (MachineBasicBlock::reverse_iterator MII = MBBI->rbegin(); + MII != MBBI->rend(); ++MII) { + MachineInstr &MI = *MII; + 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, @@ -462,15 +516,18 @@ // we may insert at the end. SmallVector ScopeTops(MF.getNumBlockIDs() + 1); - // For eacn LOOP_END, the corresponding LOOP. - DenseMap LoopTops; + // For each END_LOOP, the corresponding LOOP. + DenseMap LoopTops; + + // For each END_BLOCK, the corresponding BLOCK. + DenseMap 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, TII, MLI, MDT, MFI); + PlaceBlockMarker(MBB, MF, ScopeTops, BlockTops, TII, MLI, MDT, MFI); } // Now rewrite references to basic blocks to be depth immediates. @@ -493,7 +550,7 @@ break; case WebAssembly::END_LOOP: Stack.push_back(&MBB); - Stack.push_back(LoopTops[&MI]); + Stack.push_back(LoopTops[&MI]->getParent()); break; default: if (MI.isTerminator()) { @@ -512,6 +569,10 @@ } } assert(Stack.empty() && "Control flow should be balanced"); + + // Some browsers have choosen to impose additional and non-essential + // type-checking errors. Do additional work to satisfy them. + FixEndOfFunctionEnds(MF, MFI, BlockTops, LoopTops); } bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { Index: lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -481,12 +481,12 @@ SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { - MachineFunction &MF = DAG.getMachineFunction(); - auto *MFI = MF.getInfo(); - if (!CallingConvSupported(CallConv)) fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions"); + MachineFunction &MF = DAG.getMachineFunction(); + auto *MFI = MF.getInfo(); + // 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 @@ MFI->addParam(PtrVT); } + // Record the number and types of results. + SmallVector Params; + SmallVector Results; + ComputeSignatureVTs(*MF.getFunction(), DAG.getTarget(), Params, Results); + for (MVT VT : Results) + MFI->addResult(VT); + return Chain; } Index: lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -62,8 +62,8 @@ // 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), [], "block">; -def LOOP : I<(outs), (ins), [], "loop">; +def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig">; +def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig">; def END_BLOCK : I<(outs), (ins), [], "end_block">; def END_LOOP : I<(outs), (ins), [], "end_loop">; } // Uses = [EXPR_STACK], Defs = [EXPR_STACK] Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -83,6 +83,12 @@ } } // OperandType = "OPERAND_P2ALIGN" +let OperandType = "OPERAND_SIGNATURE" in { +def Signature : Operand { + let PrintMethod = "printWebAssemblySignatureOperand"; +} +} // OperandType = "OPERAND_SIGNATURE" + } // OperandNamespace = "WebAssembly" //===----------------------------------------------------------------------===// Index: lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h @@ -27,6 +27,7 @@ MachineFunction &MF; std::vector Params; + std::vector Results; /// A mapping from CodeGen vreg index to WebAssembly register number. std::vector WARegs; @@ -51,6 +52,9 @@ void addParam(MVT VT) { Params.push_back(VT); } const std::vector &getParams() const { return Params; } + void addResult(MVT VT) { Results.push_back(VT); } + const std::vector &getResults() const { return Results; } + unsigned getVarargBufferVreg() const { assert(VarargVreg != -1U && "Vararg vreg hasn't been set"); return VarargVreg; @@ -88,6 +92,13 @@ } }; +void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM, + Type *Ty, SmallVectorImpl &ValueVTs); + +void ComputeSignatureVTs(const Function &F, const TargetMachine &TM, + SmallVectorImpl &Params, + SmallVectorImpl &Results); + } // end namespace llvm #endif Index: lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp +++ lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp @@ -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 @@ unsigned Reg = UnusedReg; WARegs.resize(MF.getRegInfo().getNumVirtRegs(), Reg); } + +void llvm::ComputeLegalValueVTs(const Function &F, const TargetMachine &TM, + Type *Ty, SmallVectorImpl &ValueVTs) { + const DataLayout &DL(F.getParent()->getDataLayout()); + const WebAssemblyTargetLowering &TLI = + *TM.getSubtarget(F).getTargetLowering(); + SmallVector 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 &Params, + SmallVectorImpl &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); +} Index: test/CodeGen/WebAssembly/cfg-stackify.ll =================================================================== --- test/CodeGen/WebAssembly/cfg-stackify.ll +++ test/CodeGen/WebAssembly/cfg-stackify.ll @@ -105,7 +105,7 @@ ; CHECK-LABEL: test2: ; CHECK-NOT: local -; CHECK: block{{$}} +; CHECK: block {{$}} ; CHECK: br_if 0, {{[^,]+}}{{$}} ; CHECK: .LBB2_{{[0-9]+}}: ; CHECK: loop @@ -116,7 +116,7 @@ ; 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 @@ } ; 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 @@ ; 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 @@ } ; 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 @@ } ; 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 @@ ; 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 @@ ; CHECK-LABEL: minimal_loop: ; CHECK-NOT: br ; CHECK: .LBB7_1: +; CHECK: loop i32 ; CHECK: i32.store $drop=, 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 $drop=, 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 @@ ; 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 @@ ; 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 @@ } ; 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 @@ } ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; CHECK-LABEL: test5: ; CHECK: .LBB14_1: -; CHECK-NEXT: block{{$}} -; CHECK-NEXT: loop{{$}} +; CHECK-NEXT: block {{$}} +; CHECK-NEXT: loop {{$}} ; CHECK: br_if 2, {{[^,]+}}{{$}} ; CHECK: br_if 0, {{[^,]+}}{{$}} ; CHECK-NEXT: end_loop{{$}} @@ -584,8 +586,8 @@ ; CHECK: return{{$}} ; OPT-LABEL: test5: ; OPT: .LBB14_1: -; OPT-NEXT: block{{$}} -; OPT-NEXT: loop{{$}} +; OPT-NEXT: block {{$}} +; OPT-NEXT: loop {{$}} ; OPT: br_if 2, {{[^,]+}}{{$}} ; OPT: br_if 0, {{[^,]+}}{{$}} ; OPT-NEXT: end_loop{{$}} @@ -619,9 +621,9 @@ ; 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 3, {{[^,]+}}{{$}} ; CHECK-NOT: block @@ -640,9 +642,9 @@ ; 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 3, {{[^,]+}}{{$}} ; OPT-NOT: block @@ -693,9 +695,9 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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,13 +798,13 @@ ; CHECK-LABEL: test9: ; CHECK: .LBB18_1: -; CHECK-NEXT: loop{{$}} +; 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 @@ -818,13 +820,13 @@ ; CHECK: return{{$}} ; OPT-LABEL: test9: ; OPT: .LBB18_1: -; OPT-NEXT: loop{{$}} +; 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 @@ -874,15 +876,15 @@ ; 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 5, {{[^,]+}}{{$}} ; CHECK-NOT: block @@ -898,15 +900,15 @@ ; 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 5, {{[^,]+}}{{$}} ; OPT-NOT: block @@ -958,13 +960,13 @@ ; 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 @@ -992,11 +994,11 @@ ; 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 @@ -1008,7 +1010,7 @@ ; 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 @@ -1055,10 +1057,10 @@ ; CHECK-LABEL: test12: ; CHECK: .LBB21_1: -; CHECK-NEXT: loop{{$}} +; 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, {{[^,]+}}{{$}} @@ -1080,10 +1082,10 @@ ; CHECK-NEXT: return{{$}} ; OPT-LABEL: test12: ; OPT: .LBB21_1: -; OPT-NEXT: loop{{$}} +; 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, {{[^,]+}}{{$}} @@ -1131,10 +1133,10 @@ ; 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{{$}} @@ -1148,10 +1150,10 @@ ; 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{{$}} @@ -1185,12 +1187,12 @@ ; 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{{$}} @@ -1249,8 +1251,8 @@ ; CHECK-NEXT: block ; CHECK: br_if 0, $pop{{.*}}{{$}} ; CHECK: .LBB24_2: -; CHECK-NEXT: block{{$}} -; CHECK-NEXT: loop{{$}} +; CHECK-NEXT: block {{$}} +; CHECK-NEXT: loop {{$}} ; CHECK: br_if 1, $pop{{.*}}{{$}} ; CHECK: br_if 0, ${{.*}}{{$}} ; CHECK-NEXT: br 2{{$}} Index: test/CodeGen/WebAssembly/reg-stackify.ll =================================================================== --- test/CodeGen/WebAssembly/reg-stackify.ll +++ test/CodeGen/WebAssembly/reg-stackify.ll @@ -84,7 +84,7 @@ ; 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 @@ ; 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{{$}} Index: test/CodeGen/WebAssembly/switch.ll =================================================================== --- test/CodeGen/WebAssembly/switch.ll +++ test/CodeGen/WebAssembly/switch.ll @@ -14,13 +14,13 @@ 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 @@ } ; 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{{$}}