mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[WebAssembly] Adding 64-bit versions of all load & store ops.
Context: https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md This is just a first step, adding the new instruction variants while keeping the existing 32-bit functionality working. Some of the basic load/store tests have new wasm64 versions that show that the basics of the target are working. Further features need implementation, but these will be added in followups to keep things reviewable. Differential Revision: https://reviews.llvm.org/D80769
This commit is contained in:
parent
32f1a435a4
commit
2a3fc0c8b2
@ -199,6 +199,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
|
||||
case WebAssembly::OPERAND_GLOBAL:
|
||||
case WebAssembly::OPERAND_FUNCTION32:
|
||||
case WebAssembly::OPERAND_OFFSET32:
|
||||
case WebAssembly::OPERAND_OFFSET64:
|
||||
case WebAssembly::OPERAND_P2ALIGN:
|
||||
case WebAssembly::OPERAND_TYPEINDEX:
|
||||
case WebAssembly::OPERAND_EVENT:
|
||||
|
@ -77,6 +77,7 @@ WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
|
||||
{"fixup_sleb128_i32", 0, 5 * 8, 0},
|
||||
{"fixup_sleb128_i64", 0, 10 * 8, 0},
|
||||
{"fixup_uleb128_i32", 0, 5 * 8, 0},
|
||||
{"fixup_uleb128_i64", 0, 10 * 8, 0},
|
||||
};
|
||||
|
||||
if (Kind < FirstTargetFixupKind)
|
||||
|
@ -17,6 +17,7 @@ enum Fixups {
|
||||
fixup_sleb128_i32 = FirstTargetFixupKind, // 32-bit signed
|
||||
fixup_sleb128_i64, // 64-bit signed
|
||||
fixup_uleb128_i32, // 32-bit unsigned
|
||||
fixup_uleb128_i64, // 64-bit unsigned
|
||||
|
||||
// Marker
|
||||
LastTargetFixupKind,
|
||||
|
@ -101,6 +101,9 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
|
||||
case WebAssembly::OPERAND_I64IMM:
|
||||
encodeSLEB128(int64_t(MO.getImm()), OS);
|
||||
break;
|
||||
case WebAssembly::OPERAND_OFFSET64:
|
||||
encodeULEB128(uint64_t(MO.getImm()), OS);
|
||||
break;
|
||||
case WebAssembly::OPERAND_SIGNATURE:
|
||||
OS << uint8_t(MO.getImm());
|
||||
break;
|
||||
@ -158,6 +161,9 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
|
||||
case WebAssembly::OPERAND_EVENT:
|
||||
FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
|
||||
break;
|
||||
case WebAssembly::OPERAND_OFFSET64:
|
||||
FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected symbolic operand kind");
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ enum OperandType {
|
||||
OPERAND_FUNCTION32,
|
||||
/// 32-bit unsigned memory offsets.
|
||||
OPERAND_OFFSET32,
|
||||
/// 64-bit unsigned memory offsets.
|
||||
OPERAND_OFFSET64,
|
||||
/// p2align immediate for load and store address alignment.
|
||||
OPERAND_P2ALIGN,
|
||||
/// signature immediate for block/loop.
|
||||
@ -145,216 +147,121 @@ wasm::ValType toValType(const MVT &Ty);
|
||||
/// Return the default p2align value for a load or store with the given opcode.
|
||||
inline unsigned GetDefaultP2AlignAny(unsigned Opc) {
|
||||
switch (Opc) {
|
||||
case WebAssembly::LOAD8_S_I32:
|
||||
case WebAssembly::LOAD8_S_I32_S:
|
||||
case WebAssembly::LOAD8_U_I32:
|
||||
case WebAssembly::LOAD8_U_I32_S:
|
||||
case WebAssembly::LOAD8_S_I64:
|
||||
case WebAssembly::LOAD8_S_I64_S:
|
||||
case WebAssembly::LOAD8_U_I64:
|
||||
case WebAssembly::LOAD8_U_I64_S:
|
||||
case WebAssembly::ATOMIC_LOAD8_U_I32:
|
||||
case WebAssembly::ATOMIC_LOAD8_U_I32_S:
|
||||
case WebAssembly::ATOMIC_LOAD8_U_I64:
|
||||
case WebAssembly::ATOMIC_LOAD8_U_I64_S:
|
||||
case WebAssembly::STORE8_I32:
|
||||
case WebAssembly::STORE8_I32_S:
|
||||
case WebAssembly::STORE8_I64:
|
||||
case WebAssembly::STORE8_I64_S:
|
||||
case WebAssembly::ATOMIC_STORE8_I32:
|
||||
case WebAssembly::ATOMIC_STORE8_I32_S:
|
||||
case WebAssembly::ATOMIC_STORE8_I64:
|
||||
case WebAssembly::ATOMIC_STORE8_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_ADD_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_ADD_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_ADD_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_ADD_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_SUB_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_SUB_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_SUB_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_SUB_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_AND_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_AND_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_AND_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_AND_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_OR_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_OR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_OR_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_OR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XOR_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XOR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XOR_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XOR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_XCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW8_U_CMPXCHG_I64_S:
|
||||
case WebAssembly::LOAD_SPLAT_v8x16:
|
||||
case WebAssembly::LOAD_SPLAT_v8x16_S:
|
||||
#define WASM_LOAD_STORE(NAME) \
|
||||
case WebAssembly::NAME##_A32: \
|
||||
case WebAssembly::NAME##_A64: \
|
||||
case WebAssembly::NAME##_A32_S: \
|
||||
case WebAssembly::NAME##_A64_S:
|
||||
WASM_LOAD_STORE(LOAD8_S_I32)
|
||||
WASM_LOAD_STORE(LOAD8_U_I32)
|
||||
WASM_LOAD_STORE(LOAD8_S_I64)
|
||||
WASM_LOAD_STORE(LOAD8_U_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD8_U_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD8_U_I64)
|
||||
WASM_LOAD_STORE(STORE8_I32)
|
||||
WASM_LOAD_STORE(STORE8_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE8_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE8_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_ADD_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_SUB_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_AND_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_OR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_XOR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_XCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I64)
|
||||
WASM_LOAD_STORE(LOAD_SPLAT_v8x16)
|
||||
return 0;
|
||||
case WebAssembly::LOAD16_S_I32:
|
||||
case WebAssembly::LOAD16_S_I32_S:
|
||||
case WebAssembly::LOAD16_U_I32:
|
||||
case WebAssembly::LOAD16_U_I32_S:
|
||||
case WebAssembly::LOAD16_S_I64:
|
||||
case WebAssembly::LOAD16_S_I64_S:
|
||||
case WebAssembly::LOAD16_U_I64:
|
||||
case WebAssembly::LOAD16_U_I64_S:
|
||||
case WebAssembly::ATOMIC_LOAD16_U_I32:
|
||||
case WebAssembly::ATOMIC_LOAD16_U_I32_S:
|
||||
case WebAssembly::ATOMIC_LOAD16_U_I64:
|
||||
case WebAssembly::ATOMIC_LOAD16_U_I64_S:
|
||||
case WebAssembly::STORE16_I32:
|
||||
case WebAssembly::STORE16_I32_S:
|
||||
case WebAssembly::STORE16_I64:
|
||||
case WebAssembly::STORE16_I64_S:
|
||||
case WebAssembly::ATOMIC_STORE16_I32:
|
||||
case WebAssembly::ATOMIC_STORE16_I32_S:
|
||||
case WebAssembly::ATOMIC_STORE16_I64:
|
||||
case WebAssembly::ATOMIC_STORE16_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_ADD_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_ADD_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_ADD_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_ADD_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_SUB_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_SUB_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_SUB_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_SUB_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_AND_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_AND_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_AND_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_AND_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_OR_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_OR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_OR_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_OR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XOR_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XOR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XOR_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XOR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_XCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW16_U_CMPXCHG_I64_S:
|
||||
case WebAssembly::LOAD_SPLAT_v16x8:
|
||||
case WebAssembly::LOAD_SPLAT_v16x8_S:
|
||||
WASM_LOAD_STORE(LOAD16_S_I32)
|
||||
WASM_LOAD_STORE(LOAD16_U_I32)
|
||||
WASM_LOAD_STORE(LOAD16_S_I64)
|
||||
WASM_LOAD_STORE(LOAD16_U_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD16_U_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD16_U_I64)
|
||||
WASM_LOAD_STORE(STORE16_I32)
|
||||
WASM_LOAD_STORE(STORE16_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE16_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE16_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_ADD_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_SUB_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_AND_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_OR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_XOR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_XCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I64)
|
||||
WASM_LOAD_STORE(LOAD_SPLAT_v16x8)
|
||||
return 1;
|
||||
case WebAssembly::LOAD_I32:
|
||||
case WebAssembly::LOAD_I32_S:
|
||||
case WebAssembly::LOAD_F32:
|
||||
case WebAssembly::LOAD_F32_S:
|
||||
case WebAssembly::STORE_I32:
|
||||
case WebAssembly::STORE_I32_S:
|
||||
case WebAssembly::STORE_F32:
|
||||
case WebAssembly::STORE_F32_S:
|
||||
case WebAssembly::LOAD32_S_I64:
|
||||
case WebAssembly::LOAD32_S_I64_S:
|
||||
case WebAssembly::LOAD32_U_I64:
|
||||
case WebAssembly::LOAD32_U_I64_S:
|
||||
case WebAssembly::STORE32_I64:
|
||||
case WebAssembly::STORE32_I64_S:
|
||||
case WebAssembly::ATOMIC_LOAD_I32:
|
||||
case WebAssembly::ATOMIC_LOAD_I32_S:
|
||||
case WebAssembly::ATOMIC_LOAD32_U_I64:
|
||||
case WebAssembly::ATOMIC_LOAD32_U_I64_S:
|
||||
case WebAssembly::ATOMIC_STORE_I32:
|
||||
case WebAssembly::ATOMIC_STORE_I32_S:
|
||||
case WebAssembly::ATOMIC_STORE32_I64:
|
||||
case WebAssembly::ATOMIC_STORE32_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_ADD_I32:
|
||||
case WebAssembly::ATOMIC_RMW_ADD_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_ADD_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_ADD_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_SUB_I32:
|
||||
case WebAssembly::ATOMIC_RMW_SUB_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_SUB_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_SUB_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_AND_I32:
|
||||
case WebAssembly::ATOMIC_RMW_AND_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_AND_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_AND_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_OR_I32:
|
||||
case WebAssembly::ATOMIC_RMW_OR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_OR_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_OR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_XOR_I32:
|
||||
case WebAssembly::ATOMIC_RMW_XOR_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_XOR_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_XOR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_XCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW_XCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_XCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_XCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_CMPXCHG_I32:
|
||||
case WebAssembly::ATOMIC_RMW_CMPXCHG_I32_S:
|
||||
case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW32_U_CMPXCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_NOTIFY:
|
||||
case WebAssembly::ATOMIC_NOTIFY_S:
|
||||
case WebAssembly::ATOMIC_WAIT_I32:
|
||||
case WebAssembly::ATOMIC_WAIT_I32_S:
|
||||
case WebAssembly::LOAD_SPLAT_v32x4:
|
||||
case WebAssembly::LOAD_SPLAT_v32x4_S:
|
||||
WASM_LOAD_STORE(LOAD_I32)
|
||||
WASM_LOAD_STORE(LOAD_F32)
|
||||
WASM_LOAD_STORE(STORE_I32)
|
||||
WASM_LOAD_STORE(STORE_F32)
|
||||
WASM_LOAD_STORE(LOAD32_S_I64)
|
||||
WASM_LOAD_STORE(LOAD32_U_I64)
|
||||
WASM_LOAD_STORE(STORE32_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD32_U_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE32_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_ADD_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_ADD_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_SUB_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_SUB_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_AND_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_AND_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_OR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_OR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_XOR_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_XOR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_XCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I32)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW32_U_CMPXCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_NOTIFY)
|
||||
WASM_LOAD_STORE(ATOMIC_WAIT_I32)
|
||||
WASM_LOAD_STORE(LOAD_SPLAT_v32x4)
|
||||
return 2;
|
||||
case WebAssembly::LOAD_I64:
|
||||
case WebAssembly::LOAD_I64_S:
|
||||
case WebAssembly::LOAD_F64:
|
||||
case WebAssembly::LOAD_F64_S:
|
||||
case WebAssembly::STORE_I64:
|
||||
case WebAssembly::STORE_I64_S:
|
||||
case WebAssembly::STORE_F64:
|
||||
case WebAssembly::STORE_F64_S:
|
||||
case WebAssembly::ATOMIC_LOAD_I64:
|
||||
case WebAssembly::ATOMIC_LOAD_I64_S:
|
||||
case WebAssembly::ATOMIC_STORE_I64:
|
||||
case WebAssembly::ATOMIC_STORE_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_ADD_I64:
|
||||
case WebAssembly::ATOMIC_RMW_ADD_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_SUB_I64:
|
||||
case WebAssembly::ATOMIC_RMW_SUB_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_AND_I64:
|
||||
case WebAssembly::ATOMIC_RMW_AND_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_OR_I64:
|
||||
case WebAssembly::ATOMIC_RMW_OR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_XOR_I64:
|
||||
case WebAssembly::ATOMIC_RMW_XOR_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_XCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW_XCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_RMW_CMPXCHG_I64:
|
||||
case WebAssembly::ATOMIC_RMW_CMPXCHG_I64_S:
|
||||
case WebAssembly::ATOMIC_WAIT_I64:
|
||||
case WebAssembly::ATOMIC_WAIT_I64_S:
|
||||
case WebAssembly::LOAD_SPLAT_v64x2:
|
||||
case WebAssembly::LOAD_SPLAT_v64x2_S:
|
||||
case WebAssembly::LOAD_EXTEND_S_v8i16:
|
||||
case WebAssembly::LOAD_EXTEND_S_v8i16_S:
|
||||
case WebAssembly::LOAD_EXTEND_U_v8i16:
|
||||
case WebAssembly::LOAD_EXTEND_U_v8i16_S:
|
||||
case WebAssembly::LOAD_EXTEND_S_v4i32:
|
||||
case WebAssembly::LOAD_EXTEND_S_v4i32_S:
|
||||
case WebAssembly::LOAD_EXTEND_U_v4i32:
|
||||
case WebAssembly::LOAD_EXTEND_U_v4i32_S:
|
||||
case WebAssembly::LOAD_EXTEND_S_v2i64:
|
||||
case WebAssembly::LOAD_EXTEND_S_v2i64_S:
|
||||
case WebAssembly::LOAD_EXTEND_U_v2i64:
|
||||
case WebAssembly::LOAD_EXTEND_U_v2i64_S:
|
||||
WASM_LOAD_STORE(LOAD_I64)
|
||||
WASM_LOAD_STORE(LOAD_F64)
|
||||
WASM_LOAD_STORE(STORE_I64)
|
||||
WASM_LOAD_STORE(STORE_F64)
|
||||
WASM_LOAD_STORE(ATOMIC_LOAD_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_STORE_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_ADD_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_SUB_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_AND_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_OR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_XOR_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_XCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I64)
|
||||
WASM_LOAD_STORE(ATOMIC_WAIT_I64)
|
||||
WASM_LOAD_STORE(LOAD_SPLAT_v64x2)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_S_v8i16)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_U_v8i16)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_S_v4i32)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_U_v4i32)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_S_v2i64)
|
||||
WASM_LOAD_STORE(LOAD_EXTEND_U_v2i64)
|
||||
return 3;
|
||||
case WebAssembly::LOAD_V128:
|
||||
case WebAssembly::LOAD_V128_S:
|
||||
case WebAssembly::STORE_V128:
|
||||
case WebAssembly::STORE_V128_S:
|
||||
WASM_LOAD_STORE(LOAD_V128)
|
||||
WASM_LOAD_STORE(STORE_V128)
|
||||
return 4;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
#undef WASM_LOAD_STORE
|
||||
}
|
||||
|
||||
inline unsigned GetDefaultP2Align(unsigned Opc) {
|
||||
|
@ -87,12 +87,12 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
|
||||
switch (unsigned(Fixup.getKind())) {
|
||||
case WebAssembly::fixup_sleb128_i32:
|
||||
case WebAssembly::fixup_sleb128_i64:
|
||||
if (SymA.isFunction())
|
||||
return wasm::R_WASM_TABLE_INDEX_SLEB;
|
||||
return wasm::R_WASM_MEMORY_ADDR_SLEB;
|
||||
case WebAssembly::fixup_sleb128_i64:
|
||||
llvm_unreachable("fixup_sleb128_i64 not implemented yet");
|
||||
case WebAssembly::fixup_uleb128_i32:
|
||||
case WebAssembly::fixup_uleb128_i64:
|
||||
if (SymA.isGlobal())
|
||||
return wasm::R_WASM_GLOBAL_INDEX_LEB;
|
||||
if (SymA.isFunction())
|
||||
|
@ -1160,30 +1160,31 @@ bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
|
||||
|
||||
unsigned Opc;
|
||||
const TargetRegisterClass *RC;
|
||||
bool A64 = Subtarget->hasAddr64();
|
||||
switch (getSimpleType(Load->getType())) {
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
Opc = WebAssembly::LOAD8_U_I32;
|
||||
Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
|
||||
RC = &WebAssembly::I32RegClass;
|
||||
break;
|
||||
case MVT::i16:
|
||||
Opc = WebAssembly::LOAD16_U_I32;
|
||||
Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
|
||||
RC = &WebAssembly::I32RegClass;
|
||||
break;
|
||||
case MVT::i32:
|
||||
Opc = WebAssembly::LOAD_I32;
|
||||
Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
|
||||
RC = &WebAssembly::I32RegClass;
|
||||
break;
|
||||
case MVT::i64:
|
||||
Opc = WebAssembly::LOAD_I64;
|
||||
Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
|
||||
RC = &WebAssembly::I64RegClass;
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = WebAssembly::LOAD_F32;
|
||||
Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
|
||||
RC = &WebAssembly::F32RegClass;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = WebAssembly::LOAD_F64;
|
||||
Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
|
||||
RC = &WebAssembly::F64RegClass;
|
||||
break;
|
||||
default:
|
||||
@ -1216,27 +1217,28 @@ bool WebAssemblyFastISel::selectStore(const Instruction *I) {
|
||||
|
||||
unsigned Opc;
|
||||
bool VTIsi1 = false;
|
||||
bool A64 = Subtarget->hasAddr64();
|
||||
switch (getSimpleType(Store->getValueOperand()->getType())) {
|
||||
case MVT::i1:
|
||||
VTIsi1 = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case MVT::i8:
|
||||
Opc = WebAssembly::STORE8_I32;
|
||||
Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
|
||||
break;
|
||||
case MVT::i16:
|
||||
Opc = WebAssembly::STORE16_I32;
|
||||
Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
|
||||
break;
|
||||
case MVT::i32:
|
||||
Opc = WebAssembly::STORE_I32;
|
||||
Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
|
||||
break;
|
||||
case MVT::i64:
|
||||
Opc = WebAssembly::STORE_I64;
|
||||
Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = WebAssembly::STORE_F32;
|
||||
Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = WebAssembly::STORE_F64;
|
||||
Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -53,11 +53,6 @@ public:
|
||||
|
||||
Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
|
||||
|
||||
// Wasm64 is not fully supported right now (and is not specified)
|
||||
if (Subtarget->hasAddr64())
|
||||
report_fatal_error(
|
||||
"64-bit WebAssembly (wasm64) is not currently supported");
|
||||
|
||||
return SelectionDAGISel::runOnMachineFunction(MF);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -166,6 +166,9 @@ def function32_op : Operand<i32>;
|
||||
let OperandType = "OPERAND_OFFSET32" in
|
||||
def offset32_op : Operand<i32>;
|
||||
|
||||
let OperandType = "OPERAND_OFFSET64" in
|
||||
def offset64_op : Operand<i64>;
|
||||
|
||||
let OperandType = "OPERAND_P2ALIGN" in {
|
||||
def P2Align : Operand<i32> {
|
||||
let PrintMethod = "printWebAssemblyP2AlignOperand";
|
||||
|
@ -12,7 +12,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// TODO:
|
||||
// - HasAddr64
|
||||
// - WebAssemblyTargetLowering having to do with atomics
|
||||
// - Each has optional alignment.
|
||||
|
||||
@ -41,181 +40,219 @@ def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
|
||||
// offsets folded into them, so we can just use add.
|
||||
|
||||
// Defines atomic and non-atomic loads, regular and extending.
|
||||
multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> {
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in
|
||||
defm "": I<(outs rc:$dst),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off),
|
||||
[], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>;
|
||||
multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode,
|
||||
list<Predicate> reqs> {
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in {
|
||||
defm "_A32": I<(outs rc:$dst),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off),
|
||||
[], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>,
|
||||
Requires<reqs>;
|
||||
defm "_A64": I<(outs rc:$dst),
|
||||
(ins P2Align:$p2align, offset64_op:$off, I64:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset64_op:$off),
|
||||
[], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>,
|
||||
Requires<reqs>;
|
||||
}
|
||||
}
|
||||
|
||||
// Basic load.
|
||||
// FIXME: When we can break syntax compatibility, reorder the fields in the
|
||||
// asmstrings to match the binary encoding.
|
||||
defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
|
||||
defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
|
||||
defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
|
||||
defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
|
||||
defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28, []>;
|
||||
defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29, []>;
|
||||
defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a, []>;
|
||||
defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b, []>;
|
||||
|
||||
// Select loads with no constant offset.
|
||||
class LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
|
||||
Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>;
|
||||
|
||||
def : LoadPatNoOffset<i32, load, LOAD_I32>;
|
||||
def : LoadPatNoOffset<i64, load, LOAD_I64>;
|
||||
def : LoadPatNoOffset<f32, load, LOAD_F32>;
|
||||
def : LoadPatNoOffset<f64, load, LOAD_F64>;
|
||||
multiclass LoadPatNoOffset<ValueType ty, PatFrag kind, string inst> {
|
||||
def : Pat<(ty (kind I32:$addr)), (!cast<NI>(inst # "_A32") 0, 0, I32:$addr)>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(ty (kind I64:$addr)), (!cast<NI>(inst # "_A64") 0, 0, I64:$addr)>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
|
||||
defm : LoadPatNoOffset<i32, load, "LOAD_I32">;
|
||||
defm : LoadPatNoOffset<i64, load, "LOAD_I64">;
|
||||
defm : LoadPatNoOffset<f32, load, "LOAD_F32">;
|
||||
defm : LoadPatNoOffset<f64, load, "LOAD_F64">;
|
||||
|
||||
// Select loads with a constant offset.
|
||||
|
||||
// Pattern with address + immediate offset
|
||||
class LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
|
||||
Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>;
|
||||
multiclass LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand,
|
||||
string inst> {
|
||||
def : Pat<(ty (kind (operand I32:$addr, imm:$off))),
|
||||
(!cast<NI>(inst # "_A32") 0, imm:$off, I32:$addr)>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(ty (kind (operand I64:$addr, imm:$off))),
|
||||
(!cast<NI>(inst # "_A64") 0, imm:$off, I64:$addr)>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
|
||||
def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
|
||||
def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
|
||||
def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
|
||||
def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
|
||||
def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
|
||||
def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
|
||||
def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
|
||||
def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
|
||||
defm : LoadPatImmOff<i32, load, regPlusImm, "LOAD_I32">;
|
||||
defm : LoadPatImmOff<i64, load, regPlusImm, "LOAD_I64">;
|
||||
defm : LoadPatImmOff<f32, load, regPlusImm, "LOAD_F32">;
|
||||
defm : LoadPatImmOff<f64, load, regPlusImm, "LOAD_F64">;
|
||||
defm : LoadPatImmOff<i32, load, or_is_add, "LOAD_I32">;
|
||||
defm : LoadPatImmOff<i64, load, or_is_add, "LOAD_I64">;
|
||||
defm : LoadPatImmOff<f32, load, or_is_add, "LOAD_F32">;
|
||||
defm : LoadPatImmOff<f64, load, or_is_add, "LOAD_F64">;
|
||||
|
||||
// Select loads with just a constant offset.
|
||||
class LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
|
||||
Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
|
||||
multiclass LoadPatOffsetOnly<ValueType ty, PatFrag kind, string inst> {
|
||||
def : Pat<(ty (kind imm:$off)),
|
||||
(!cast<NI>(inst # "_A32") 0, imm:$off, (CONST_I32 0))>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(ty (kind imm:$off)),
|
||||
(!cast<NI>(inst # "_A64") 0, imm:$off, (CONST_I64 0))>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
|
||||
def : LoadPatOffsetOnly<i32, load, LOAD_I32>;
|
||||
def : LoadPatOffsetOnly<i64, load, LOAD_I64>;
|
||||
def : LoadPatOffsetOnly<f32, load, LOAD_F32>;
|
||||
def : LoadPatOffsetOnly<f64, load, LOAD_F64>;
|
||||
defm : LoadPatOffsetOnly<i32, load, "LOAD_I32">;
|
||||
defm : LoadPatOffsetOnly<i64, load, "LOAD_I64">;
|
||||
defm : LoadPatOffsetOnly<f32, load, "LOAD_F32">;
|
||||
defm : LoadPatOffsetOnly<f64, load, "LOAD_F64">;
|
||||
|
||||
class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
|
||||
Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
|
||||
(inst 0, tglobaladdr:$off, (CONST_I32 0))>, Requires<[IsNotPIC]>;
|
||||
multiclass LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> {
|
||||
def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
|
||||
(!cast<NI>(inst # "_A32") 0, tglobaladdr:$off, (CONST_I32 0))>,
|
||||
Requires<[IsNotPIC, HasAddr32]>;
|
||||
def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
|
||||
(!cast<NI>(inst # "_A64") 0, tglobaladdr:$off, (CONST_I64 0))>,
|
||||
Requires<[IsNotPIC, HasAddr64]>;
|
||||
}
|
||||
|
||||
def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
|
||||
def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, load, "LOAD_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, load, "LOAD_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<f32, load, "LOAD_F32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<f64, load, "LOAD_F64">;
|
||||
|
||||
// Extending load.
|
||||
defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
|
||||
defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
|
||||
defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
|
||||
defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
|
||||
defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
|
||||
defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
|
||||
defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
|
||||
defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>;
|
||||
defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
|
||||
defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
|
||||
defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c, []>;
|
||||
defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d, []>;
|
||||
defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e, []>;
|
||||
defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f, []>;
|
||||
defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30, []>;
|
||||
defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31, []>;
|
||||
defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32, []>;
|
||||
defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33, []>;
|
||||
defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34, []>;
|
||||
defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35, []>;
|
||||
|
||||
// Select extending loads with no constant offset.
|
||||
def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
|
||||
def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
|
||||
def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
|
||||
def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
|
||||
def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
|
||||
def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
|
||||
def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
|
||||
defm : LoadPatNoOffset<i32, sextloadi8, "LOAD8_S_I32">;
|
||||
defm : LoadPatNoOffset<i32, zextloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatNoOffset<i32, sextloadi16, "LOAD16_S_I32">;
|
||||
defm : LoadPatNoOffset<i32, zextloadi16, "LOAD16_U_I32">;
|
||||
defm : LoadPatNoOffset<i64, sextloadi8, "LOAD8_S_I64">;
|
||||
defm : LoadPatNoOffset<i64, zextloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatNoOffset<i64, sextloadi16, "LOAD16_S_I64">;
|
||||
defm : LoadPatNoOffset<i64, zextloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatNoOffset<i64, sextloadi32, "LOAD32_S_I64">;
|
||||
defm : LoadPatNoOffset<i64, zextloadi32, "LOAD32_U_I64">;
|
||||
|
||||
// Select extending loads with a constant offset.
|
||||
def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
|
||||
def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
|
||||
def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
|
||||
def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
|
||||
def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
|
||||
def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
|
||||
def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
|
||||
defm : LoadPatImmOff<i32, sextloadi8, regPlusImm, "LOAD8_S_I32">;
|
||||
defm : LoadPatImmOff<i32, zextloadi8, regPlusImm, "LOAD8_U_I32">;
|
||||
defm : LoadPatImmOff<i32, sextloadi16, regPlusImm, "LOAD16_S_I32">;
|
||||
defm : LoadPatImmOff<i32, zextloadi16, regPlusImm, "LOAD16_U_I32">;
|
||||
defm : LoadPatImmOff<i64, sextloadi8, regPlusImm, "LOAD8_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi8, regPlusImm, "LOAD8_U_I64">;
|
||||
defm : LoadPatImmOff<i64, sextloadi16, regPlusImm, "LOAD16_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi16, regPlusImm, "LOAD16_U_I64">;
|
||||
defm : LoadPatImmOff<i64, sextloadi32, regPlusImm, "LOAD32_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi32, regPlusImm, "LOAD32_U_I64">;
|
||||
|
||||
def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
|
||||
def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
|
||||
def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
|
||||
def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
|
||||
def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
|
||||
def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
|
||||
def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
|
||||
def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
|
||||
defm : LoadPatImmOff<i32, sextloadi8, or_is_add, "LOAD8_S_I32">;
|
||||
defm : LoadPatImmOff<i32, zextloadi8, or_is_add, "LOAD8_U_I32">;
|
||||
defm : LoadPatImmOff<i32, sextloadi16, or_is_add, "LOAD16_S_I32">;
|
||||
defm : LoadPatImmOff<i32, zextloadi16, or_is_add, "LOAD16_U_I32">;
|
||||
defm : LoadPatImmOff<i64, sextloadi8, or_is_add, "LOAD8_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi8, or_is_add, "LOAD8_U_I64">;
|
||||
defm : LoadPatImmOff<i64, sextloadi16, or_is_add, "LOAD16_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi16, or_is_add, "LOAD16_U_I64">;
|
||||
defm : LoadPatImmOff<i64, sextloadi32, or_is_add, "LOAD32_S_I64">;
|
||||
defm : LoadPatImmOff<i64, zextloadi32, or_is_add, "LOAD32_U_I64">;
|
||||
|
||||
// Select extending loads with just a constant offset.
|
||||
def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
|
||||
def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
|
||||
def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
|
||||
defm : LoadPatOffsetOnly<i32, sextloadi8, "LOAD8_S_I32">;
|
||||
defm : LoadPatOffsetOnly<i32, zextloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatOffsetOnly<i32, sextloadi16, "LOAD16_S_I32">;
|
||||
defm : LoadPatOffsetOnly<i32, zextloadi16, "LOAD16_U_I32">;
|
||||
|
||||
def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
|
||||
def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
|
||||
def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
|
||||
def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
|
||||
defm : LoadPatOffsetOnly<i64, sextloadi8, "LOAD8_S_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, zextloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, sextloadi16, "LOAD16_S_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, zextloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, sextloadi32, "LOAD32_S_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, zextloadi32, "LOAD32_U_I64">;
|
||||
|
||||
def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, sextloadi8, "LOAD8_S_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, zextloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, sextloadi16, "LOAD16_S_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, zextloadi16, "LOAD16_U_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, sextloadi8, "LOAD8_S_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, zextloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, sextloadi16, "LOAD16_S_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, zextloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, sextloadi32, "LOAD32_S_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, zextloadi32, "LOAD32_U_I64">;
|
||||
|
||||
// Resolve "don't care" extending loads to zero-extending loads. This is
|
||||
// somewhat arbitrary, but zero-extending is conceptually simpler.
|
||||
|
||||
// Select "don't care" extending loads with no constant offset.
|
||||
def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
|
||||
def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
|
||||
defm : LoadPatNoOffset<i32, extloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatNoOffset<i32, extloadi16, "LOAD16_U_I32">;
|
||||
defm : LoadPatNoOffset<i64, extloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatNoOffset<i64, extloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatNoOffset<i64, extloadi32, "LOAD32_U_I64">;
|
||||
|
||||
// Select "don't care" extending loads with a constant offset.
|
||||
def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
|
||||
def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
|
||||
def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
|
||||
def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
|
||||
def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
|
||||
def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
|
||||
def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
|
||||
def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
|
||||
def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
|
||||
def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
|
||||
defm : LoadPatImmOff<i32, extloadi8, regPlusImm, "LOAD8_U_I32">;
|
||||
defm : LoadPatImmOff<i32, extloadi16, regPlusImm, "LOAD16_U_I32">;
|
||||
defm : LoadPatImmOff<i64, extloadi8, regPlusImm, "LOAD8_U_I64">;
|
||||
defm : LoadPatImmOff<i64, extloadi16, regPlusImm, "LOAD16_U_I64">;
|
||||
defm : LoadPatImmOff<i64, extloadi32, regPlusImm, "LOAD32_U_I64">;
|
||||
defm : LoadPatImmOff<i32, extloadi8, or_is_add, "LOAD8_U_I32">;
|
||||
defm : LoadPatImmOff<i32, extloadi16, or_is_add, "LOAD16_U_I32">;
|
||||
defm : LoadPatImmOff<i64, extloadi8, or_is_add, "LOAD8_U_I64">;
|
||||
defm : LoadPatImmOff<i64, extloadi16, or_is_add, "LOAD16_U_I64">;
|
||||
defm : LoadPatImmOff<i64, extloadi32, or_is_add, "LOAD32_U_I64">;
|
||||
|
||||
// Select "don't care" extending loads with just a constant offset.
|
||||
def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
|
||||
def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
|
||||
def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
|
||||
defm : LoadPatOffsetOnly<i32, extloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatOffsetOnly<i32, extloadi16, "LOAD16_U_I32">;
|
||||
defm : LoadPatOffsetOnly<i64, extloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, extloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatOffsetOnly<i64, extloadi32, "LOAD32_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, extloadi8, "LOAD8_U_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i32, extloadi16, "LOAD16_U_I32">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, extloadi8, "LOAD8_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, extloadi16, "LOAD16_U_I64">;
|
||||
defm : LoadPatGlobalAddrOffOnly<i64, extloadi32, "LOAD32_U_I64">;
|
||||
|
||||
// Defines atomic and non-atomic stores, regular and truncating
|
||||
multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
|
||||
let mayStore = 1, UseNamedOperandTable = 1 in
|
||||
defm "" : I<(outs),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
|
||||
(outs),
|
||||
(ins P2Align:$p2align, offset32_op:$off), [],
|
||||
!strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>;
|
||||
defm "_A32" : I<(outs),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
|
||||
(outs),
|
||||
(ins P2Align:$p2align, offset32_op:$off), [],
|
||||
!strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>;
|
||||
let mayStore = 1, UseNamedOperandTable = 1 in
|
||||
defm "_A64" : I<(outs),
|
||||
(ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
|
||||
(outs),
|
||||
(ins P2Align:$p2align, offset64_op:$off), [],
|
||||
!strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
|
||||
!strconcat(Name, "\t${off}${p2align}"), Opcode>;
|
||||
}
|
||||
|
||||
// Basic store.
|
||||
// Note: WebAssembly inverts SelectionDAG's usual operand order.
|
||||
defm STORE_I32 : WebAssemblyStore<I32, "i32.store", 0x36>;
|
||||
@ -224,43 +261,68 @@ defm STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>;
|
||||
defm STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>;
|
||||
|
||||
// Select stores with no constant offset.
|
||||
class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> :
|
||||
Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>;
|
||||
multiclass StorePatNoOffset<ValueType ty, PatFrag node, string inst> {
|
||||
def : Pat<(node ty:$val, I32:$addr),
|
||||
(!cast<NI>(inst # "_A32") 0, 0, I32:$addr, ty:$val)>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(node ty:$val, I64:$addr),
|
||||
(!cast<NI>(inst # "_A64") 0, 0, I64:$addr, ty:$val)>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
|
||||
def : StorePatNoOffset<i32, store, STORE_I32>;
|
||||
def : StorePatNoOffset<i64, store, STORE_I64>;
|
||||
def : StorePatNoOffset<f32, store, STORE_F32>;
|
||||
def : StorePatNoOffset<f64, store, STORE_F64>;
|
||||
defm : StorePatNoOffset<i32, store, "STORE_I32">;
|
||||
defm : StorePatNoOffset<i64, store, "STORE_I64">;
|
||||
defm : StorePatNoOffset<f32, store, "STORE_F32">;
|
||||
defm : StorePatNoOffset<f64, store, "STORE_F64">;
|
||||
|
||||
// Select stores with a constant offset.
|
||||
class StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
|
||||
Pat<(kind ty:$val, (operand I32:$addr, imm:$off)),
|
||||
(inst 0, imm:$off, I32:$addr, ty:$val)>;
|
||||
multiclass StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand,
|
||||
string inst> {
|
||||
def : Pat<(kind ty:$val, (operand I32:$addr, imm:$off)),
|
||||
(!cast<NI>(inst # "_A32") 0, imm:$off, I32:$addr, ty:$val)>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(kind ty:$val, (operand I64:$addr, imm:$off)),
|
||||
(!cast<NI>(inst # "_A64") 0, imm:$off, I64:$addr, ty:$val)>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
|
||||
def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>;
|
||||
def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>;
|
||||
def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>;
|
||||
def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>;
|
||||
def : StorePatImmOff<i32, store, or_is_add, STORE_I32>;
|
||||
def : StorePatImmOff<i64, store, or_is_add, STORE_I64>;
|
||||
def : StorePatImmOff<f32, store, or_is_add, STORE_F32>;
|
||||
def : StorePatImmOff<f64, store, or_is_add, STORE_F64>;
|
||||
defm : StorePatImmOff<i32, store, regPlusImm, "STORE_I32">;
|
||||
defm : StorePatImmOff<i64, store, regPlusImm, "STORE_I64">;
|
||||
defm : StorePatImmOff<f32, store, regPlusImm, "STORE_F32">;
|
||||
defm : StorePatImmOff<f64, store, regPlusImm, "STORE_F64">;
|
||||
defm : StorePatImmOff<i32, store, or_is_add, "STORE_I32">;
|
||||
defm : StorePatImmOff<i64, store, or_is_add, "STORE_I64">;
|
||||
defm : StorePatImmOff<f32, store, or_is_add, "STORE_F32">;
|
||||
defm : StorePatImmOff<f64, store, or_is_add, "STORE_F64">;
|
||||
|
||||
// Select stores with just a constant offset.
|
||||
class StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
|
||||
Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
|
||||
def : StorePatOffsetOnly<i32, store, STORE_I32>;
|
||||
def : StorePatOffsetOnly<i64, store, STORE_I64>;
|
||||
def : StorePatOffsetOnly<f32, store, STORE_F32>;
|
||||
def : StorePatOffsetOnly<f64, store, STORE_F64>;
|
||||
multiclass StorePatOffsetOnly<ValueType ty, PatFrag kind, string inst> {
|
||||
def : Pat<(kind ty:$val, imm:$off),
|
||||
(!cast<NI>(inst # "_A32") 0, imm:$off, (CONST_I32 0), ty:$val)>,
|
||||
Requires<[HasAddr32]>;
|
||||
def : Pat<(kind ty:$val, imm:$off),
|
||||
(!cast<NI>(inst # "_A64") 0, imm:$off, (CONST_I64 0), ty:$val)>,
|
||||
Requires<[HasAddr64]>;
|
||||
}
|
||||
defm : StorePatOffsetOnly<i32, store, "STORE_I32">;
|
||||
defm : StorePatOffsetOnly<i64, store, "STORE_I64">;
|
||||
defm : StorePatOffsetOnly<f32, store, "STORE_F32">;
|
||||
defm : StorePatOffsetOnly<f64, store, "STORE_F64">;
|
||||
|
||||
class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
|
||||
Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
|
||||
(inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, Requires<[IsNotPIC]>;
|
||||
def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>;
|
||||
def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>;
|
||||
def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>;
|
||||
def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>;
|
||||
multiclass StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> {
|
||||
def : Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
|
||||
(!cast<NI>(inst # "_A32") 0, tglobaladdr:$off, (CONST_I32 0),
|
||||
ty:$val)>,
|
||||
Requires<[IsNotPIC, HasAddr32]>;
|
||||
def : Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
|
||||
(!cast<NI>(inst # "_A64") 0, tglobaladdr:$off, (CONST_I64 0),
|
||||
ty:$val)>,
|
||||
Requires<[IsNotPIC, HasAddr64]>;
|
||||
}
|
||||
defm : StorePatGlobalAddrOffOnly<i32, store, "STORE_I32">;
|
||||
defm : StorePatGlobalAddrOffOnly<i64, store, "STORE_I64">;
|
||||
defm : StorePatGlobalAddrOffOnly<f32, store, "STORE_F32">;
|
||||
defm : StorePatGlobalAddrOffOnly<f64, store, "STORE_F64">;
|
||||
|
||||
// Truncating store.
|
||||
defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>;
|
||||
@ -270,35 +332,35 @@ defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>;
|
||||
defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>;
|
||||
|
||||
// Select truncating stores with no constant offset.
|
||||
def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>;
|
||||
def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>;
|
||||
def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>;
|
||||
def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>;
|
||||
def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>;
|
||||
defm : StorePatNoOffset<i32, truncstorei8, "STORE8_I32">;
|
||||
defm : StorePatNoOffset<i32, truncstorei16, "STORE16_I32">;
|
||||
defm : StorePatNoOffset<i64, truncstorei8, "STORE8_I64">;
|
||||
defm : StorePatNoOffset<i64, truncstorei16, "STORE16_I64">;
|
||||
defm : StorePatNoOffset<i64, truncstorei32, "STORE32_I64">;
|
||||
|
||||
// Select truncating stores with a constant offset.
|
||||
def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>;
|
||||
def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>;
|
||||
def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>;
|
||||
def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>;
|
||||
def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>;
|
||||
def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>;
|
||||
def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>;
|
||||
def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>;
|
||||
def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>;
|
||||
def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>;
|
||||
defm : StorePatImmOff<i32, truncstorei8, regPlusImm, "STORE8_I32">;
|
||||
defm : StorePatImmOff<i32, truncstorei16, regPlusImm, "STORE16_I32">;
|
||||
defm : StorePatImmOff<i64, truncstorei8, regPlusImm, "STORE8_I64">;
|
||||
defm : StorePatImmOff<i64, truncstorei16, regPlusImm, "STORE16_I64">;
|
||||
defm : StorePatImmOff<i64, truncstorei32, regPlusImm, "STORE32_I64">;
|
||||
defm : StorePatImmOff<i32, truncstorei8, or_is_add, "STORE8_I32">;
|
||||
defm : StorePatImmOff<i32, truncstorei16, or_is_add, "STORE16_I32">;
|
||||
defm : StorePatImmOff<i64, truncstorei8, or_is_add, "STORE8_I64">;
|
||||
defm : StorePatImmOff<i64, truncstorei16, or_is_add, "STORE16_I64">;
|
||||
defm : StorePatImmOff<i64, truncstorei32, or_is_add, "STORE32_I64">;
|
||||
|
||||
// Select truncating stores with just a constant offset.
|
||||
def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>;
|
||||
def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>;
|
||||
def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>;
|
||||
def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>;
|
||||
def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>;
|
||||
def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>;
|
||||
def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>;
|
||||
def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>;
|
||||
def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>;
|
||||
def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>;
|
||||
defm : StorePatOffsetOnly<i32, truncstorei8, "STORE8_I32">;
|
||||
defm : StorePatOffsetOnly<i32, truncstorei16, "STORE16_I32">;
|
||||
defm : StorePatOffsetOnly<i64, truncstorei8, "STORE8_I64">;
|
||||
defm : StorePatOffsetOnly<i64, truncstorei16, "STORE16_I64">;
|
||||
defm : StorePatOffsetOnly<i64, truncstorei32, "STORE32_I64">;
|
||||
defm : StorePatGlobalAddrOffOnly<i32, truncstorei8, "STORE8_I32">;
|
||||
defm : StorePatGlobalAddrOffOnly<i32, truncstorei16, "STORE16_I32">;
|
||||
defm : StorePatGlobalAddrOffOnly<i64, truncstorei8, "STORE8_I64">;
|
||||
defm : StorePatGlobalAddrOffOnly<i64, truncstorei16, "STORE16_I64">;
|
||||
defm : StorePatGlobalAddrOffOnly<i64, truncstorei32, "STORE32_I64">;
|
||||
|
||||
// Current memory size.
|
||||
defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
|
||||
@ -306,8 +368,7 @@ defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
|
||||
[(set I32:$dst,
|
||||
(int_wasm_memory_size (i32 imm:$flags)))],
|
||||
"memory.size\t$dst, $flags", "memory.size\t$flags",
|
||||
0x3f>,
|
||||
Requires<[HasAddr32]>;
|
||||
0x3f>;
|
||||
|
||||
// Grow memory.
|
||||
defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
|
||||
@ -316,5 +377,4 @@ defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
|
||||
(int_wasm_memory_grow (i32 imm:$flags),
|
||||
I32:$delta))],
|
||||
"memory.grow\t$dst, $flags, $delta",
|
||||
"memory.grow\t$flags", 0x40>,
|
||||
Requires<[HasAddr32]>;
|
||||
"memory.grow\t$flags", 0x40>;
|
||||
|
@ -40,30 +40,46 @@ def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Load: v128.load
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in
|
||||
defm LOAD_V128 :
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in {
|
||||
defm LOAD_V128_A32 :
|
||||
SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
|
||||
"v128.load\t$dst, ${off}(${addr})$p2align",
|
||||
"v128.load\t$off$p2align", 0>;
|
||||
defm LOAD_V128_A64 :
|
||||
SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
|
||||
"v128.load\t$dst, ${off}(${addr})$p2align",
|
||||
"v128.load\t$off$p2align", 0>;
|
||||
}
|
||||
|
||||
// Def load and store patterns from WebAssemblyInstrMemory.td for vector types
|
||||
foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in {
|
||||
def : LoadPatNoOffset<vec_t, load, LOAD_V128>;
|
||||
def : LoadPatImmOff<vec_t, load, regPlusImm, LOAD_V128>;
|
||||
def : LoadPatImmOff<vec_t, load, or_is_add, LOAD_V128>;
|
||||
def : LoadPatOffsetOnly<vec_t, load, LOAD_V128>;
|
||||
def : LoadPatGlobalAddrOffOnly<vec_t, load, LOAD_V128>;
|
||||
defm : LoadPatNoOffset<vec_t, load, "LOAD_V128">;
|
||||
defm : LoadPatImmOff<vec_t, load, regPlusImm, "LOAD_V128">;
|
||||
defm : LoadPatImmOff<vec_t, load, or_is_add, "LOAD_V128">;
|
||||
defm : LoadPatOffsetOnly<vec_t, load, "LOAD_V128">;
|
||||
defm : LoadPatGlobalAddrOffOnly<vec_t, load, "LOAD_V128">;
|
||||
}
|
||||
|
||||
// vNxM.load_splat
|
||||
multiclass SIMDLoadSplat<string vec, bits<32> simdop> {
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in
|
||||
defm LOAD_SPLAT_#vec :
|
||||
SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in {
|
||||
defm LOAD_SPLAT_#vec#_A32 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs),
|
||||
(ins P2Align:$p2align, offset32_op:$off), [],
|
||||
vec#".load_splat\t$dst, ${off}(${addr})$p2align",
|
||||
vec#".load_splat\t$off$p2align", simdop>;
|
||||
defm LOAD_SPLAT_#vec#_A64 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset64_op:$off, I64:$addr),
|
||||
(outs),
|
||||
(ins P2Align:$p2align, offset64_op:$off), [],
|
||||
vec#".load_splat\t$dst, ${off}(${addr})$p2align",
|
||||
vec#".load_splat\t$off$p2align", simdop>;
|
||||
}
|
||||
}
|
||||
|
||||
defm "" : SIMDLoadSplat<"v8x16", 7>;
|
||||
@ -78,38 +94,52 @@ def load_splat : PatFrag<(ops node:$addr), (wasm_load_splat node:$addr)>;
|
||||
|
||||
foreach args = [["v16i8", "v8x16"], ["v8i16", "v16x8"], ["v4i32", "v32x4"],
|
||||
["v2i64", "v64x2"], ["v4f32", "v32x4"], ["v2f64", "v64x2"]] in {
|
||||
def : LoadPatNoOffset<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
!cast<NI>("LOAD_SPLAT_"#args[1])>;
|
||||
def : LoadPatImmOff<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
regPlusImm,
|
||||
!cast<NI>("LOAD_SPLAT_"#args[1])>;
|
||||
def : LoadPatImmOff<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
or_is_add,
|
||||
!cast<NI>("LOAD_SPLAT_"#args[1])>;
|
||||
def : LoadPatOffsetOnly<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
!cast<NI>("LOAD_SPLAT_"#args[1])>;
|
||||
def : LoadPatGlobalAddrOffOnly<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
!cast<NI>("LOAD_SPLAT_"#args[1])>;
|
||||
defm : LoadPatNoOffset<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
"LOAD_SPLAT_"#args[1]>;
|
||||
defm : LoadPatImmOff<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
regPlusImm,
|
||||
"LOAD_SPLAT_"#args[1]>;
|
||||
defm : LoadPatImmOff<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
or_is_add,
|
||||
"LOAD_SPLAT_"#args[1]>;
|
||||
defm : LoadPatOffsetOnly<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
"LOAD_SPLAT_"#args[1]>;
|
||||
defm : LoadPatGlobalAddrOffOnly<!cast<ValueType>(args[0]),
|
||||
load_splat,
|
||||
"LOAD_SPLAT_"#args[1]>;
|
||||
}
|
||||
|
||||
// Load and extend
|
||||
multiclass SIMDLoadExtend<ValueType vec_t, string name, bits<32> simdop> {
|
||||
let mayLoad = 1, UseNamedOperandTable = 1 in {
|
||||
defm LOAD_EXTEND_S_#vec_t :
|
||||
SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
defm LOAD_EXTEND_S_#vec_t#_A32 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
|
||||
name#"_s\t$dst, ${off}(${addr})$p2align",
|
||||
name#"_s\t$off$p2align", simdop>;
|
||||
defm LOAD_EXTEND_U_#vec_t :
|
||||
SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
defm LOAD_EXTEND_U_#vec_t#_A32 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset32_op:$off, I32:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
|
||||
name#"_u\t$dst, ${off}(${addr})$p2align",
|
||||
name#"_u\t$off$p2align", !add(simdop, 1)>;
|
||||
defm LOAD_EXTEND_S_#vec_t#_A64 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset64_op:$off, I64:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
|
||||
name#"_s\t$dst, ${off}(${addr})$p2align",
|
||||
name#"_s\t$off$p2align", simdop>;
|
||||
defm LOAD_EXTEND_U_#vec_t#_A64 :
|
||||
SIMD_I<(outs V128:$dst),
|
||||
(ins P2Align:$p2align, offset64_op:$off, I64:$addr),
|
||||
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
|
||||
name#"_u\t$dst, ${off}(${addr})$p2align",
|
||||
name#"_u\t$off$p2align", !add(simdop, 1)>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,34 +151,39 @@ foreach types = [[v8i16, i8], [v4i32, i16], [v2i64, i32]] in
|
||||
foreach exts = [["sextloadv", "_S"],
|
||||
["zextloadv", "_U"],
|
||||
["extloadv", "_U"]] in {
|
||||
def : LoadPatNoOffset<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
!cast<NI>("LOAD_EXTEND"#exts[1]#"_"#types[0])>;
|
||||
def : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), regPlusImm,
|
||||
!cast<NI>("LOAD_EXTEND"#exts[1]#"_"#types[0])>;
|
||||
def : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), or_is_add,
|
||||
!cast<NI>("LOAD_EXTEND"#exts[1]#"_"#types[0])>;
|
||||
def : LoadPatOffsetOnly<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
!cast<NI>("LOAD_EXTEND"#exts[1]#"_"#types[0])>;
|
||||
def : LoadPatGlobalAddrOffOnly<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
!cast<NI>("LOAD_EXTEND"#exts[1]#"_"#types[0])>;
|
||||
defm : LoadPatNoOffset<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
"LOAD_EXTEND"#exts[1]#"_"#types[0]>;
|
||||
defm : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), regPlusImm,
|
||||
"LOAD_EXTEND"#exts[1]#"_"#types[0]>;
|
||||
defm : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), or_is_add,
|
||||
"LOAD_EXTEND"#exts[1]#"_"#types[0]>;
|
||||
defm : LoadPatOffsetOnly<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
"LOAD_EXTEND"#exts[1]#"_"#types[0]>;
|
||||
defm : LoadPatGlobalAddrOffOnly<types[0], !cast<PatFrag>(exts[0]#types[1]),
|
||||
"LOAD_EXTEND"#exts[1]#"_"#types[0]>;
|
||||
}
|
||||
|
||||
|
||||
// Store: v128.store
|
||||
let mayStore = 1, UseNamedOperandTable = 1 in
|
||||
defm STORE_V128 :
|
||||
let mayStore = 1, UseNamedOperandTable = 1 in {
|
||||
defm STORE_V128_A32 :
|
||||
SIMD_I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, V128:$vec),
|
||||
(outs), (ins P2Align:$p2align, offset32_op:$off), [],
|
||||
"v128.store\t${off}(${addr})$p2align, $vec",
|
||||
"v128.store\t$off$p2align", 11>;
|
||||
|
||||
defm STORE_V128_A64 :
|
||||
SIMD_I<(outs), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, V128:$vec),
|
||||
(outs), (ins P2Align:$p2align, offset64_op:$off), [],
|
||||
"v128.store\t${off}(${addr})$p2align, $vec",
|
||||
"v128.store\t$off$p2align", 11>;
|
||||
}
|
||||
foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in {
|
||||
// Def load and store patterns from WebAssemblyInstrMemory.td for vector types
|
||||
def : StorePatNoOffset<vec_t, store, STORE_V128>;
|
||||
def : StorePatImmOff<vec_t, store, regPlusImm, STORE_V128>;
|
||||
def : StorePatImmOff<vec_t, store, or_is_add, STORE_V128>;
|
||||
def : StorePatOffsetOnly<vec_t, store, STORE_V128>;
|
||||
def : StorePatGlobalAddrOffOnly<vec_t, store, STORE_V128>;
|
||||
defm : StorePatNoOffset<vec_t, store, "STORE_V128">;
|
||||
defm : StorePatImmOff<vec_t, store, regPlusImm, "STORE_V128">;
|
||||
defm : StorePatImmOff<vec_t, store, or_is_add, "STORE_V128">;
|
||||
defm : StorePatOffsetOnly<vec_t, store, "STORE_V128">;
|
||||
defm : StorePatGlobalAddrOffOnly<vec_t, store, "STORE_V128">;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -26,7 +26,7 @@ liveins:
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
; CHECK: %[[REG:[0-9]+]]:i32 = ATOMIC_NOTIFY
|
||||
; CHECK: %[[REG:[0-9]+]]:i32 = ATOMIC_NOTIFY_A32
|
||||
; CHECK: LOCAL_SET_I32 [[LOCAL:[0-9]+]], %[[REG]]
|
||||
; CHECK: COMPILER_FENCE
|
||||
; CHECK: ADD_I32
|
||||
@ -35,7 +35,7 @@ body: |
|
||||
|
||||
liveins: $arguments
|
||||
%0:i32 = CONST_I32 0, implicit-def $arguments
|
||||
%1:i32 = ATOMIC_NOTIFY 2, 0, %0:i32, %0:i32, implicit-def $arguments
|
||||
%1:i32 = ATOMIC_NOTIFY_A32 2, 0, %0:i32, %0:i32, implicit-def $arguments
|
||||
COMPILER_FENCE implicit-def $arguments
|
||||
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
|
||||
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
|
||||
@ -50,7 +50,7 @@ liveins:
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
; CHECK: %[[REG:[0-9]+]]:i32 = ATOMIC_NOTIFY
|
||||
; CHECK: %[[REG:[0-9]+]]:i32 = ATOMIC_NOTIFY_A32
|
||||
; CHECK: LOCAL_SET_I32 [[LOCAL:[0-9]+]], %[[REG]]
|
||||
; CHECK: ATOMIC_FENCE
|
||||
; CHECK: ADD_I32
|
||||
@ -59,7 +59,7 @@ body: |
|
||||
|
||||
liveins: $arguments
|
||||
%0:i32 = CONST_I32 0, implicit-def $arguments
|
||||
%1:i32 = ATOMIC_NOTIFY 2, 0, %0:i32, %0:i32, implicit-def $arguments
|
||||
%1:i32 = ATOMIC_NOTIFY_A32 2, 0, %0:i32, %0:i32, implicit-def $arguments
|
||||
ATOMIC_FENCE 0, implicit-def $arguments
|
||||
%2:i32 = ADD_I32 %0:i32, %0:i32, implicit-def $arguments
|
||||
CALL @foo, %2:i32, %1:i32, implicit-def $arguments
|
||||
|
@ -1,17 +1,16 @@
|
||||
; This tests that llc accepts all valid WebAssembly CPUs.
|
||||
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm32-unknown-unknown -mcpu=mvp 2>&1 | FileCheck %s
|
||||
; RUN: not --crash llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=mvp 2>&1 | FileCheck %s --check-prefix=WASM64
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=mvp 2>&1 | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm32-unknown-unknown -mcpu=generic 2>&1 | FileCheck %s
|
||||
; RUN: not --crash llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=generic 2>&1 | FileCheck %s --check-prefix=WASM64
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=generic 2>&1 | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm32-unknown-unknown -mcpu=bleeding-edge 2>&1 | FileCheck %s
|
||||
; RUN: not --crash llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=bleeding-edge 2>&1 | FileCheck %s --check-prefix=WASM64
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=bleeding-edge 2>&1 | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm32-unknown-unknown -mcpu=invalidcpu 2>&1 | FileCheck %s --check-prefix=INVALID
|
||||
; RUN: not --crash llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=invalidcpu 2>&1 | FileCheck %s --check-prefix=WASM64
|
||||
; RUN: llc < %s -asm-verbose=false -mtriple=wasm64-unknown-unknown-wasm -mcpu=invalidcpu 2>&1 | FileCheck %s --check-prefix=INVALID
|
||||
|
||||
; CHECK-NOT: is not a recognized processor for this target
|
||||
; INVALID: {{.+}} is not a recognized processor for this target
|
||||
; WASM64: 64-bit WebAssembly (wasm64) is not currently supported
|
||||
|
||||
define i32 @f(i32 %i_like_the_web) {
|
||||
ret i32 %i_like_the_web
|
||||
|
@ -1,10 +1,8 @@
|
||||
; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -mattr=+atomics,+sign-ext -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that extending loads are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: sext_i8_i32:
|
||||
; CHECK: i32.atomic.load8_u $push0=, 0($0){{$}}
|
||||
; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
|
||||
|
@ -1,10 +1,8 @@
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that extending loads are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: sext_i8_i32:
|
||||
; CHECK: i32.load8_s $push0=, 0($0){{$}}
|
||||
; CHECK-NEXT: return $pop0{{$}}
|
||||
|
@ -1,10 +1,8 @@
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that i1 extending loads and truncating stores are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: load_u_i1_i32:
|
||||
; CHECK: i32.load8_u $push[[NUM0:[0-9]+]]=, 0($0){{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM0]]{{$}}
|
||||
|
@ -1,13 +1,13 @@
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that basic loads are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: ldi32:
|
||||
; CHECK-NEXT: .functype ldi32 (i32) -> (i32){{$}}
|
||||
; CHK32-NEXT: .functype ldi32 (i32) -> (i32){{$}}
|
||||
; CHK64-NEXT: .functype ldi32 (i64) -> (i32){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
@ -17,7 +17,8 @@ define i32 @ldi32(i32 *%p) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: ldi64:
|
||||
; CHECK-NEXT: .functype ldi64 (i32) -> (i64){{$}}
|
||||
; CHK32-NEXT: .functype ldi64 (i32) -> (i64){{$}}
|
||||
; CHK64-NEXT: .functype ldi64 (i64) -> (i64){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
@ -27,7 +28,8 @@ define i64 @ldi64(i64 *%p) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: ldf32:
|
||||
; CHECK-NEXT: .functype ldf32 (i32) -> (f32){{$}}
|
||||
; CHK32-NEXT: .functype ldf32 (i32) -> (f32){{$}}
|
||||
; CHK64-NEXT: .functype ldf32 (i64) -> (f32){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: f32.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
@ -37,7 +39,8 @@ define float @ldf32(float *%p) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: ldf64:
|
||||
; CHECK-NEXT: .functype ldf64 (i32) -> (f64){{$}}
|
||||
; CHK32-NEXT: .functype ldf64 (i32) -> (f64){{$}}
|
||||
; CHK64-NEXT: .functype ldf64 (i64) -> (f64){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: f64.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
|
||||
; CHECK-NEXT: return $pop[[NUM]]{{$}}
|
||||
|
@ -1,10 +1,8 @@
|
||||
; RUN: llc < %s -mattr=+atomics,+sign-ext -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -mattr=+atomics,+sign-ext -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -mattr=+atomics,+sign-ext -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that truncating stores are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: trunc_i8_i32:
|
||||
; CHECK: i32.atomic.store8 0($0), $1{{$}}
|
||||
define void @trunc_i8_i32(i8 *%p, i32 %v) {
|
||||
|
@ -1,10 +1,8 @@
|
||||
; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that truncating stores are assembled properly.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: trunc_i8_i32:
|
||||
; CHECK: i32.store8 0($0), $1{{$}}
|
||||
define void @trunc_i8_i32(i8 *%p, i32 %v) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
|
||||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck --check-prefixes CHECK,CHK32 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck --check-prefixes CHECK,CHK64 %s
|
||||
|
||||
; Test that basic stores are assembled properly.
|
||||
|
||||
@ -7,7 +9,8 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
; CHECK-LABEL: sti32:
|
||||
; CHECK-NEXT: .functype sti32 (i32, i32) -> (){{$}}
|
||||
; CHK32-NEXT: .functype sti32 (i32, i32) -> (){{$}}
|
||||
; CHK64-NEXT: .functype sti32 (i64, i32) -> (){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
|
||||
; CHECK-NEXT: i32.store 0($pop[[L0]]), $pop[[L1]]{{$}}
|
||||
@ -18,7 +21,8 @@ define void @sti32(i32 *%p, i32 %v) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: sti64:
|
||||
; CHECK-NEXT: .functype sti64 (i32, i64) -> (){{$}}
|
||||
; CHK32-NEXT: .functype sti64 (i32, i64) -> (){{$}}
|
||||
; CHK64-NEXT: .functype sti64 (i64, i64) -> (){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
|
||||
; CHECK-NEXT: i64.store 0($pop[[L0]]), $pop[[L1]]{{$}}
|
||||
@ -29,7 +33,8 @@ define void @sti64(i64 *%p, i64 %v) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: stf32:
|
||||
; CHECK-NEXT: .functype stf32 (i32, f32) -> (){{$}}
|
||||
; CHK32-NEXT: .functype stf32 (i32, f32) -> (){{$}}
|
||||
; CHK64-NEXT: .functype stf32 (i64, f32) -> (){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
|
||||
; CHECK-NEXT: f32.store 0($pop[[L0]]), $pop[[L1]]{{$}}
|
||||
@ -40,7 +45,8 @@ define void @stf32(float *%p, float %v) {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: stf64:
|
||||
; CHECK-NEXT: .functype stf64 (i32, f64) -> (){{$}}
|
||||
; CHK32-NEXT: .functype stf64 (i32, f64) -> (){{$}}
|
||||
; CHK64-NEXT: .functype stf64 (i64, f64) -> (){{$}}
|
||||
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
|
||||
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
|
||||
; CHECK-NEXT: f64.store 0($pop[[L0]]), $pop[[L1]]{{$}}
|
||||
|
106
test/MC/WebAssembly/wasm64.s
Normal file
106
test/MC/WebAssembly/wasm64.s
Normal file
@ -0,0 +1,106 @@
|
||||
# RUN: llvm-mc -triple=wasm64-unknown-unknown -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
|
||||
# Check that it converts to .o without errors, but don't check any output:
|
||||
# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
|
||||
|
||||
# Most of our other tests are for wasm32, this one adds some wasm64 specific tests.
|
||||
|
||||
test:
|
||||
.functype test (i64) -> ()
|
||||
.local i64
|
||||
|
||||
### basic loads
|
||||
|
||||
i64.const 0 # get i64 from constant.
|
||||
f32.load 0
|
||||
drop
|
||||
|
||||
local.get 0 # get i64 from local.
|
||||
f32.load 0
|
||||
drop
|
||||
|
||||
# i64.const .L.str # get i64 relocatable.
|
||||
# f32.load 0
|
||||
# drop
|
||||
|
||||
global.get myglob64 # get i64 from global
|
||||
f32.load 0
|
||||
drop
|
||||
|
||||
### basic stores
|
||||
|
||||
f32.const 0.0
|
||||
i64.const 0 # get i64 from constant.
|
||||
f32.store 0
|
||||
|
||||
f32.const 0.0
|
||||
local.get 0 # get i64 from local.
|
||||
f32.store 0
|
||||
|
||||
# f32.const 0.0
|
||||
# i64.const .L.str # get i64 relocatable.
|
||||
# f32.store 0
|
||||
|
||||
f32.const 0.0
|
||||
global.get myglob64 # get i64 from global
|
||||
f32.store 0
|
||||
|
||||
end_function
|
||||
|
||||
.section .rodata..L.str,"",@
|
||||
.hidden .L.str
|
||||
.type .L.str,@object
|
||||
.L.str:
|
||||
.asciz "Hello, World!"
|
||||
|
||||
.globaltype myglob64, i64
|
||||
|
||||
|
||||
|
||||
# CHECK: .functype test (i64) -> ()
|
||||
# CHECK-NEXT: .local i64
|
||||
|
||||
|
||||
# CHECK: i64.const 0
|
||||
# CHECK-NEXT: f32.load 0
|
||||
# CHECK-NEXT: drop
|
||||
|
||||
# CHECK: local.get 0
|
||||
# CHECK-NEXT: f32.load 0
|
||||
# CHECK-NEXT: drop
|
||||
|
||||
# NCHECK: i64.const .L.str
|
||||
# NCHECK-NEXT: f32.load 0
|
||||
# NCHECK-NEXT: drop
|
||||
|
||||
# CHECK: global.get myglob64
|
||||
# CHECK-NEXT: f32.load 0
|
||||
# CHECK-NEXT: drop
|
||||
|
||||
|
||||
# CHECK: f32.const 0x0p0
|
||||
# CHECK-NEXT: i64.const 0
|
||||
# CHECK-NEXT: f32.store 0
|
||||
|
||||
# CHECK: f32.const 0x0p0
|
||||
# CHECK-NEXT: local.get 0
|
||||
# CHECK-NEXT: f32.store 0
|
||||
|
||||
# NCHECK: f32.const 0x0p0
|
||||
# NCHECK-NEXT: i64.const .L.str
|
||||
# NCHECK-NEXT: f32.store 0
|
||||
|
||||
# CHECK: f32.const 0x0p0
|
||||
# CHECK-NEXT: global.get myglob64
|
||||
# CHECK-NEXT: f32.store 0
|
||||
|
||||
|
||||
# CHECK: end_function
|
||||
# CHECK-NEXT: .Ltmp0:
|
||||
# CHECK-NEXT: .size test, .Ltmp0-test
|
||||
|
||||
# CHECK: .section .rodata..L.str,"",@
|
||||
# CHECK-NEXT: .hidden .L.str
|
||||
# CHECK-NEXT: .L.str:
|
||||
# CHECK-NEXT: .asciz "Hello, World!"
|
||||
|
||||
# CHECK: .globaltype myglob64, i64
|
Loading…
x
Reference in New Issue
Block a user