561 changes: 561 additions & 0 deletions llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions llvm/lib/Target/WebAssembly/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tablegen(LLVM WebAssemblyGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM WebAssemblyGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM WebAssemblyGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM WebAssemblyGenAsmMatcher.inc -gen-asm-matcher)
add_public_tablegen_target(WebAssemblyCommonTableGen)

add_llvm_target(WebAssemblyCodeGen
Expand Down Expand Up @@ -51,6 +52,7 @@ add_llvm_target(WebAssemblyCodeGen
intrinsics_gen
)

add_subdirectory(AsmParser)
add_subdirectory(Disassembler)
add_subdirectory(InstPrinter)
add_subdirectory(MCTargetDesc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
break;
case WebAssembly::END_LOOP:
ControlFlowStack.pop_back();
// Have to guard against an empty stack, in case of mismatched pairs
// in assembly parsing.
if (!ControlFlowStack.empty()) ControlFlowStack.pop_back();
break;
case WebAssembly::END_BLOCK:
printAnnotation(
if (!ControlFlowStack.empty()) printAnnotation(
OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
break;
}
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/WebAssembly/LLVMBuild.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
;===------------------------------------------------------------------------===;

[common]
subdirectories = Disassembler InstPrinter MCTargetDesc TargetInfo
subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo

[component_0]
type = TargetGroup
name = WebAssembly
parent = Target
has_asmparser = 1
has_asmprinter = 1
has_disassembler = 1

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssembly.td
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ def : ProcessorModel<"bleeding-edge", NoSchedModel,
def WebAssembly : Target {
let InstructionSet = WebAssemblyInstrInfo;
}

def WebAssemblyAsmParser : AsmParser {
// The physical register names are not in the binary format or asm text
let ShouldEmitMatchRegisterName = 0;
}
14 changes: 10 additions & 4 deletions llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ def SP32 : WebAssemblyReg<"%SP32">;
def SP64 : WebAssemblyReg<"%SP64">;

// The register allocation framework requires register classes have at least
// one register, so we define a few for the floating point register classes
// since we otherwise don't need a physical register in those classes.
// one register, so we define a few for the integer / floating point register
// classes since we otherwise don't need a physical register in those classes.
// These are also used a "types" in the generated assembly matcher.
def I32_0 : WebAssemblyReg<"%i32.0">;
def I64_0 : WebAssemblyReg<"%i64.0">;
def F32_0 : WebAssemblyReg<"%f32.0">;
def F64_0 : WebAssemblyReg<"%f64.0">;

def V128_0: WebAssemblyReg<"%v128">;

def EXCEPT_REF_0 : WebAssemblyReg<"%except_ref.0">;

// The value stack "register". This is an opaque entity which serves to order
Expand All @@ -54,9 +59,10 @@ def ARGUMENTS : WebAssemblyReg<"ARGUMENTS">;
// Register classes
//===----------------------------------------------------------------------===//

def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32)>;
def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64)>;
def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32, I32_0)>;
def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64, I64_0)>;
def F32 : WebAssemblyRegClass<[f32], 32, (add F32_0)>;
def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
def V128 : WebAssemblyRegClass<[v4f32, v4i32, v16i8, v8i16], 128, (add V128_0)>;
def EXCEPT_REF : WebAssemblyRegClass<[ExceptRef], 0, (add EXCEPT_REF_0)>;

74 changes: 74 additions & 0 deletions llvm/test/MC/WebAssembly/basic-assembly.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown-elf < %s | FileCheck %s

.text
.type test0,@function
test0:
# Test all types:
.param i32, i64
.local f32, f64 #, i8x16, i16x8, i32x4, f32x4
# Explicit getlocal/setlocal:
get_local $push0=, 2
set_local 2, $pop0=
# Implicit locals & immediates:
i32.const $0=, -1
f64.const $3=, 0x1.999999999999ap1
# Indirect addressing:
get_local $push1=, 0
f64.store 0($pop1), $3
# Loops, conditionals, binary ops, calls etc:
block
i32.const $push2=, 1
get_local $push7=, 0
i32.ge_s $push0=, $pop2, $pop7
br_if 0, $pop0 # 0: down to label0
.LBB0_1:
loop # label1:
call $drop=, something1@FUNCTION
i64.const $push10=, 1234
i32.call $push8=, something2@FUNCTION, $pop10
i32.const $push11=, 0
call_indirect $pop11
i32.const $push5=, 1
i32.add $push4=, $pop8, $pop5
tee_local $push3=, 0, $pop4
get_local $push9=, 0
i32.lt_s $push1=, $pop3, $pop9
br_if 0, $pop1 # 0: up to label1
.LBB0_2:
end_loop
end_block # label0:
end_function


# CHECK: .text
# CHECK-LABEL: test0:
# CHECK-NEXT: .param i32, i64
# CHECK-NEXT: .local f32, f64
# CHECK-NEXT: get_local $push0=, 2
# CHECK-NEXT: set_local 2, $pop0
# CHECK-NEXT: i32.const $0=, -1
# CHECK-NEXT: f64.const $3=, 0x1.999999999999ap1
# CHECK-NEXT: get_local $push1=, 0
# CHECK-NEXT: f64.store 0($pop1):p2align=0, $3
# CHECK-NEXT: block
# CHECK-NEXT: i32.const $push2=, 1
# CHECK-NEXT: get_local $push7=, 0
# CHECK-NEXT: i32.ge_s $push0=, $pop2, $pop7
# CHECK-NEXT: br_if 0, $pop0 # 0: down to label0
# CHECK-NEXT: .LBB0_1:
# CHECK-NEXT: loop # label1:
# CHECK-NEXT: call something1@FUNCTION
# CHECK-NEXT: i64.const $push10=, 1234
# CHECK-NEXT: i32.call $push8=, something2@FUNCTION
# CHECK-NEXT: i32.const $push11=, 0
# CHECK-NEXT: call_indirect
# CHECK-NEXT: i32.const $push5=, 1
# CHECK-NEXT: i32.add $push4=, $pop8, $pop5
# CHECK-NEXT: tee_local $push3=, 0, $pop4
# CHECK-NEXT: get_local $push9=, 0
# CHECK-NEXT: i32.lt_s $push1=, $pop3, $pop9
# CHECK-NEXT: br_if 0, $pop1 # 0: up to label1
# CHECK-NEXT: .LBB0_2:
# CHECK-NEXT: end_loop
# CHECK-NEXT: end_block # label0:
# CHECK-NEXT: end_function