Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[WebAssembly] Update SIMD binary arithmetic
Browse files Browse the repository at this point in the history
Add missing SIMD types (v2f64) and binary ops. Also adds
tablegen support for automatically prepending prefix byte to SIMD
opcodes.

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

Patch by Thomas Lively

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@339186 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dschuff committed Aug 7, 2018
1 parent ab3088f commit 4f88627
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 22 deletions.
2 changes: 2 additions & 0 deletions lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
Expand Up @@ -229,7 +229,9 @@ const char *llvm::WebAssembly::TypeToString(MVT Ty) {
case MVT::v16i8:
case MVT::v8i16:
case MVT::v4i32:
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
return "v128";
case MVT::ExceptRef:
return "except_ref";
Expand Down
8 changes: 6 additions & 2 deletions lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Expand Up @@ -50,7 +50,7 @@ MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
MVT::v4i32, MVT::v4f32})
MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64})
if (TRI->isTypeLegalForClass(*TRC, T))
return T;
LLVM_DEBUG(errs() << "Unknown type for register number: " << RegNo);
Expand Down Expand Up @@ -175,7 +175,9 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
case WebAssembly::ARGUMENT_v16i8:
case WebAssembly::ARGUMENT_v8i16:
case WebAssembly::ARGUMENT_v4i32:
case WebAssembly::ARGUMENT_v2i64:
case WebAssembly::ARGUMENT_v4f32:
case WebAssembly::ARGUMENT_v2f64:
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
Expand All @@ -186,7 +188,9 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
case WebAssembly::FALLTHROUGH_RETURN_v16i8:
case WebAssembly::FALLTHROUGH_RETURN_v8i16:
case WebAssembly::FALLTHROUGH_RETURN_v4i32:
case WebAssembly::FALLTHROUGH_RETURN_v4f32: {
case WebAssembly::FALLTHROUGH_RETURN_v2i64:
case WebAssembly::FALLTHROUGH_RETURN_v4f32:
case WebAssembly::FALLTHROUGH_RETURN_v2f64: {
// These instructions represent the implicit return at the end of a
// function body. The operand is always a pop.
assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
Expand Up @@ -256,7 +256,9 @@ static void FixEndsAtEndOfFunction(
case MVT::v16i8:
case MVT::v8i16:
case MVT::v4i32:
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
retType = WebAssembly::ExprType::V128;
break;
case MVT::ExceptRef: retType = WebAssembly::ExprType::ExceptRef; break;
Expand Down
3 changes: 2 additions & 1 deletion lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
Expand Up @@ -72,7 +72,9 @@ static unsigned GetNonPseudoCallIndirectOpcode(const MachineInstr &MI) {
case PCALL_INDIRECT_v16i8: return CALL_INDIRECT_v16i8;
case PCALL_INDIRECT_v8i16: return CALL_INDIRECT_v8i16;
case PCALL_INDIRECT_v4i32: return CALL_INDIRECT_v4i32;
case PCALL_INDIRECT_v2i64: return CALL_INDIRECT_v2i64;
case PCALL_INDIRECT_v4f32: return CALL_INDIRECT_v4f32;
case PCALL_INDIRECT_v2f64: return CALL_INDIRECT_v2f64;
default: return INSTRUCTION_LIST_END;
}
}
Expand Down Expand Up @@ -133,4 +135,3 @@ bool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) {

return Changed;
}

26 changes: 26 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyFastISel.cpp
Expand Up @@ -134,7 +134,9 @@ class WebAssemblyFastISel final : public FastISel {
case MVT::v16i8:
case MVT::v8i16:
case MVT::v4i32:
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
if (Subtarget->hasSIMD128())
return VT;
break;
Expand Down Expand Up @@ -678,10 +680,18 @@ bool WebAssemblyFastISel::fastLowerArguments() {
Opc = WebAssembly::ARGUMENT_v4i32;
RC = &WebAssembly::V128RegClass;
break;
case MVT::v2i64:
Opc = WebAssembly::ARGUMENT_v2i64;
RC = &WebAssembly::V128RegClass;
break;
case MVT::v4f32:
Opc = WebAssembly::ARGUMENT_v4f32;
RC = &WebAssembly::V128RegClass;
break;
case MVT::v2f64:
Opc = WebAssembly::ARGUMENT_v2f64;
RC = &WebAssembly::V128RegClass;
break;
case MVT::ExceptRef:
Opc = WebAssembly::ARGUMENT_EXCEPT_REF;
RC = &WebAssembly::EXCEPT_REFRegClass;
Expand Down Expand Up @@ -782,11 +792,21 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
ResultReg = createResultReg(&WebAssembly::V128RegClass);
break;
case MVT::v2i64:
Opc =
IsDirect ? WebAssembly::CALL_v2i64 : WebAssembly::PCALL_INDIRECT_v2i64;
ResultReg = createResultReg(&WebAssembly::V128RegClass);
break;
case MVT::v4f32:
Opc =
IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
ResultReg = createResultReg(&WebAssembly::V128RegClass);
break;
case MVT::v2f64:
Opc =
IsDirect ? WebAssembly::CALL_v2f64 : WebAssembly::PCALL_INDIRECT_v2f64;
ResultReg = createResultReg(&WebAssembly::V128RegClass);
break;
case MVT::ExceptRef:
Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
: WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
Expand Down Expand Up @@ -1297,9 +1317,15 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
case MVT::v4i32:
Opc = WebAssembly::RETURN_v4i32;
break;
case MVT::v2i64:
Opc = WebAssembly::RETURN_v2i64;
break;
case MVT::v4f32:
Opc = WebAssembly::RETURN_v4f32;
break;
case MVT::v2f64:
Opc = WebAssembly::RETURN_v2f64;
break;
case MVT::ExceptRef:
Opc = WebAssembly::RETURN_EXCEPT_REF;
break;
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Expand Up @@ -59,7 +59,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
}
// Compute derived properties from the register classes.
computeRegisterProperties(Subtarget->getRegisterInfo());
Expand Down
10 changes: 10 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyInstrCall.td
Expand Up @@ -91,7 +91,9 @@ let Uses = [SP32, SP64], isCall = 1 in {
defm "" : SIMD_CALL<v16i8, "i8x16.">;
defm "" : SIMD_CALL<v8i16, "i16x8.">;
defm "" : SIMD_CALL<v4i32, "i32x4.">;
defm "" : SIMD_CALL<v2i64, "i64x2.">;
defm "" : SIMD_CALL<v4f32, "f32x4.">;
defm "" : SIMD_CALL<v2f64, "f64x2.">;

defm CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops),
(outs), (ins function32_op:$callee),
Expand Down Expand Up @@ -132,8 +134,12 @@ def : Pat<(v8i16 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_v8i16 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v4i32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_v4i32 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v2i64 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_v2i64 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v4f32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_v4f32 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v2f64 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_v2f64 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(ExceptRef
(WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_EXCEPT_REF tglobaladdr:$callee)>;
Expand All @@ -155,8 +161,12 @@ def : Pat<(v8i16 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_v8i16 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v4i32 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_v4i32 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v2i64 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_v2i64 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v4f32 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_v4f32 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(v2f64 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_v2f64 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(ExceptRef
(WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_EXCEPT_REF texternalsym:$callee)>;
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyInstrControl.td
Expand Up @@ -124,7 +124,9 @@ let isReturn = 1 in {
defm "": SIMD_RETURN<v16i8>;
defm "": SIMD_RETURN<v8i16>;
defm "": SIMD_RETURN<v4i32>;
defm "": SIMD_RETURN<v2i64>;
defm "": SIMD_RETURN<v4f32>;
defm "": SIMD_RETURN<v2f64>;

defm RETURN_VOID : NRI<(outs), (ins), [(WebAssemblyreturn)], "return", 0x0f>;

Expand Down
30 changes: 22 additions & 8 deletions lib/Target/WebAssembly/WebAssemblyInstrFormats.td
Expand Up @@ -60,9 +60,9 @@ multiclass NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",

multiclass SIMD_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
list<dag> pattern_r, string asmstr_r = "",
string asmstr_s = "", bits<32> inst = -1> {
string asmstr_s = "", bits<32> simdop = -1> {
defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
inst>,
!or(0xfd00, !and(0xff, simdop))>,
Requires<[HasSIMD128]>;
}

Expand Down Expand Up @@ -119,31 +119,45 @@ multiclass BinaryFP<SDNode node, string name, bits<32> f32Inst,
!strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("f64.", name), f64Inst>;
}
multiclass SIMDBinary<SDNode node, SDNode fnode, string name> {
multiclass SIMDBinaryInt<SDNode node, string name, bits<32> baseInst> {
defm _I8x16 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v16i8 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("i8x16.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("i8x16.", name)>;
!strconcat("i8x16.", name), baseInst>;
defm _I16x8 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v8i16 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("i16x8.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("i16x8.", name)>;
!strconcat("i16x8.", name), !add(baseInst, 1)>;
defm _I32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v4i32 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("i32x4.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("i32x4.", name)>;
!strconcat("i32x4.", name), !add(baseInst, 2)>;
defm _I64x2 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v2i64 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("i64x2.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("i64x2.", name), !add(baseInst, 3)>;
}
multiclass SIMDBinaryFP<SDNode node, string name, bits<32> baseInst> {
defm _F32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v4f32 V128:$dst), (fnode V128:$lhs, V128:$rhs))],
[(set (v4f32 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("f32x4.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("f32x4.", name)>;
!strconcat("f32x4.", name), baseInst>;
defm _F64x2 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
(outs), (ins),
[(set (v2f64 V128:$dst), (node V128:$lhs, V128:$rhs))],
!strconcat("f64x2.",
!strconcat(name, "\t$dst, $lhs, $rhs")),
!strconcat("f64x2.", name), !add(baseInst, 1)>;
}
multiclass ComparisonInt<CondCode cond, string name, bits<32> i32Inst, bits<32> i64Inst> {
defm _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs), (outs), (ins),
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyInstrInfo.td
Expand Up @@ -172,7 +172,9 @@ defm "": ARGUMENT<EXCEPT_REF>;
defm "": SIMD_ARGUMENT<v16i8>;
defm "": SIMD_ARGUMENT<v8i16>;
defm "": SIMD_ARGUMENT<v4i32>;
defm "": SIMD_ARGUMENT<v2i64>;
defm "": SIMD_ARGUMENT<v4f32>;
defm "": SIMD_ARGUMENT<v2f64>;

let Defs = [ARGUMENTS] in {

Expand Down
21 changes: 16 additions & 5 deletions lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
Expand Up @@ -12,8 +12,19 @@
///
//===----------------------------------------------------------------------===//

let isCommutable = 1 in {
defm ADD : SIMDBinary<add, fadd, "add ">;
defm MUL: SIMDBinary<mul, fmul, "mul ">;
} // isCommutable = 1
defm SUB: SIMDBinary<sub, fsub, "sub ">;
let Defs = [ARGUMENTS] in {

let isCommutable = 1 in
defm ADD : SIMDBinaryInt<add, "add ", 24>;
defm SUB : SIMDBinaryInt<sub, "sub ", 28>;
let isCommutable = 1 in
defm MUL : SIMDBinaryInt<mul, "mul ", 32>;

let isCommutable = 1 in
defm ADD : SIMDBinaryFP<fadd, "add ", 122>;
defm SUB : SIMDBinaryFP<fsub, "sub ", 124>;
defm DIV : SIMDBinaryFP<fdiv, "div ", 126>;
let isCommutable = 1 in
defm MUL : SIMDBinaryFP<fmul, "mul ", 128>;

} // Defs = [ARGUMENTS]
10 changes: 10 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyPeephole.cpp
Expand Up @@ -192,11 +192,21 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4i32,
WebAssembly::COPY_V128);
break;
case WebAssembly::RETURN_v2i64:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v2i64,
WebAssembly::COPY_V128);
break;
case WebAssembly::RETURN_v4f32:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4f32,
WebAssembly::COPY_V128);
break;
case WebAssembly::RETURN_v2f64:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v2f64,
WebAssembly::COPY_V128);
break;
case WebAssembly::RETURN_VOID:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_VOID,
Expand Down
4 changes: 2 additions & 2 deletions lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
Expand Up @@ -63,6 +63,6 @@ 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 V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128,
(add V128_0)>;
def EXCEPT_REF : WebAssemblyRegClass<[ExceptRef], 0, (add EXCEPT_REF_0)>;

6 changes: 6 additions & 0 deletions lib/Target/WebAssembly/WebAssemblyUtilities.cpp
Expand Up @@ -34,7 +34,9 @@ bool WebAssembly::isArgument(const MachineInstr &MI) {
case WebAssembly::ARGUMENT_v16i8:
case WebAssembly::ARGUMENT_v8i16:
case WebAssembly::ARGUMENT_v4i32:
case WebAssembly::ARGUMENT_v2i64:
case WebAssembly::ARGUMENT_v4f32:
case WebAssembly::ARGUMENT_v2f64:
return true;
default:
return false;
Expand Down Expand Up @@ -88,7 +90,9 @@ bool WebAssembly::isCallDirect(const MachineInstr &MI) {
case WebAssembly::CALL_v16i8:
case WebAssembly::CALL_v8i16:
case WebAssembly::CALL_v4i32:
case WebAssembly::CALL_v2i64:
case WebAssembly::CALL_v4f32:
case WebAssembly::CALL_v2f64:
case WebAssembly::CALL_EXCEPT_REF:
return true;
default:
Expand All @@ -106,7 +110,9 @@ bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
case WebAssembly::CALL_INDIRECT_v16i8:
case WebAssembly::CALL_INDIRECT_v8i16:
case WebAssembly::CALL_INDIRECT_v4i32:
case WebAssembly::CALL_INDIRECT_v2i64:
case WebAssembly::CALL_INDIRECT_v4f32:
case WebAssembly::CALL_INDIRECT_v2f64:
case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
return true;
default:
Expand Down

0 comments on commit 4f88627

Please sign in to comment.