diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
3 files changed, 153 insertions, 1 deletions
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index cc22a11133a..4a224cb8858 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -124,6 +124,8 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) { case WebAssembly::STORE8_I32_S: case WebAssembly::STORE8_I64: case WebAssembly::STORE8_I64_S: + case WebAssembly::ATOMIC_STORE8_I32: + case WebAssembly::ATOMIC_STORE8_I64: return 0; case WebAssembly::LOAD16_S_I32: case WebAssembly::LOAD16_S_I32_S: @@ -141,6 +143,8 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) { case WebAssembly::STORE16_I32_S: case WebAssembly::STORE16_I64: case WebAssembly::STORE16_I64_S: + case WebAssembly::ATOMIC_STORE16_I32: + case WebAssembly::ATOMIC_STORE16_I64: return 1; case WebAssembly::LOAD_I32: case WebAssembly::LOAD_I32_S: @@ -160,6 +164,8 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) { 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_STORE32_I64: return 2; case WebAssembly::LOAD_I64: case WebAssembly::LOAD_I64_S: @@ -171,6 +177,7 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) { case WebAssembly::STORE_F64_S: case WebAssembly::ATOMIC_LOAD_I64: case WebAssembly::ATOMIC_LOAD_I64_S: + case WebAssembly::ATOMIC_STORE_I64: return 3; default: llvm_unreachable("Only loads and stores have p2align values"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td index 15e48d3b33c..e19de1ac0ef 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td @@ -196,7 +196,145 @@ def : LoadPatExternSymOffOnly<i64, anyext_aload_16_64, ATOMIC_LOAD16_U_I64>; // Atomic stores //===----------------------------------------------------------------------===// -// TODO: add atomic stores here... +let Defs = [ARGUMENTS] in { +defm ATOMIC_STORE_I32 : WebAssemblyStore<I32, "i32.atomic.store", 0xfe17>; +defm ATOMIC_STORE_I64 : WebAssemblyStore<I64, "i64.atomic.store", 0xfe18>; +} // Defs = [ARGUMENTS] + +// We need an 'atomic' version of store patterns because store and atomic_store +// nodes have different operand orders: +// store: (store $val, $ptr) +// atomic_store: (store $ptr, $val) + +let Predicates = [HasAtomics] in { + +// Select stores with no constant offset. +class AStorePatNoOffset<ValueType ty, PatFrag node, NI inst> : + Pat<(node I32:$addr, ty:$val), (inst 0, 0, $addr, $val)>; +def : AStorePatNoOffset<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatNoOffset<i64, atomic_store_64, ATOMIC_STORE_I64>; + +// Select stores with a constant offset. + +// Pattern with address + immediate offset +class AStorePatImmOff<ValueType ty, PatFrag storekind, PatFrag operand, + NI inst> : + Pat<(storekind (operand I32:$addr, imm:$off), ty:$val), + (inst 0, imm:$off, $addr, ty:$val)>; +def : AStorePatImmOff<i32, atomic_store_32, regPlusImm, ATOMIC_STORE_I32>; +def : AStorePatImmOff<i64, atomic_store_64, regPlusImm, ATOMIC_STORE_I64>; +def : AStorePatImmOff<i32, atomic_store_32, or_is_add, ATOMIC_STORE_I32>; +def : AStorePatImmOff<i64, atomic_store_64, or_is_add, ATOMIC_STORE_I64>; + +class AStorePatGlobalAddr<ValueType ty, PatFrag storekind, NI inst> : + Pat<(storekind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)), + ty:$val), + (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>; +def : AStorePatGlobalAddr<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatGlobalAddr<i64, atomic_store_64, ATOMIC_STORE_I64>; + +class AStorePatExternalSym<ValueType ty, PatFrag storekind, NI inst> : + Pat<(storekind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)), + ty:$val), + (inst 0, texternalsym:$off, I32:$addr, ty:$val)>; +def : AStorePatExternalSym<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatExternalSym<i64, atomic_store_64, ATOMIC_STORE_I64>; + +// Select stores with just a constant offset. +class AStorePatOffsetOnly<ValueType ty, PatFrag storekind, NI inst> : + Pat<(storekind imm:$off, ty:$val), + (inst 0, imm:$off, (CONST_I32 0), ty:$val)>; +def : AStorePatOffsetOnly<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatOffsetOnly<i64, atomic_store_64, ATOMIC_STORE_I64>; + +class AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag storekind, NI inst> : + Pat<(storekind (WebAssemblywrapper tglobaladdr:$off), ty:$val), + (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>; +def : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>; + +class AStorePatExternSymOffOnly<ValueType ty, PatFrag storekind, NI inst> : + Pat<(storekind (WebAssemblywrapper texternalsym:$off), ty:$val), + (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>; +def : AStorePatExternSymOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>; +def : AStorePatExternSymOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>; + +} // Predicates = [HasAtomics] + +// Truncating stores. +let Defs = [ARGUMENTS] in { +defm ATOMIC_STORE8_I32 : WebAssemblyStore<I32, "i32.atomic.store8", 0xfe19>; +defm ATOMIC_STORE16_I32 : WebAssemblyStore<I32, "i32.atomic.store16", 0xfe1a>; +defm ATOMIC_STORE8_I64 : WebAssemblyStore<I64, "i64.atomic.store8", 0xfe1b>; +defm ATOMIC_STORE16_I64 : WebAssemblyStore<I64, "i64.atomic.store16", 0xfe1c>; +defm ATOMIC_STORE32_I64 : WebAssemblyStore<I64, "i64.atomic.store32", 0xfe1d>; +} // Defs = [ARGUMENTS] + +// Fragments for truncating stores. + +// We don't have single truncating atomic store instructions. For 32-bit +// instructions, we just need to match bare atomic stores. On the other hand, +// truncating stores from i64 values are once truncated to i32 first. +class trunc_astore_64<PatFrag storekind> : + PatFrag<(ops node:$addr, node:$val), + (storekind node:$addr, (i32 (trunc (i64 node:$val))))>; +def trunc_astore_8_64 : trunc_astore_64<atomic_store_8>; +def trunc_astore_16_64 : trunc_astore_64<atomic_store_16>; +def trunc_astore_32_64 : trunc_astore_64<atomic_store_32>; + +let Predicates = [HasAtomics] in { + +// Truncating stores with no constant offset +def : AStorePatNoOffset<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatNoOffset<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatNoOffset<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatNoOffset<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatNoOffset<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +// Truncating stores with a constant offset +def : AStorePatImmOff<i32, atomic_store_8, regPlusImm, ATOMIC_STORE8_I32>; +def : AStorePatImmOff<i32, atomic_store_16, regPlusImm, ATOMIC_STORE16_I32>; +def : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, ATOMIC_STORE8_I64>; +def : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, ATOMIC_STORE16_I64>; +def : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, ATOMIC_STORE32_I64>; +def : AStorePatImmOff<i32, atomic_store_8, or_is_add, ATOMIC_STORE8_I32>; +def : AStorePatImmOff<i32, atomic_store_16, or_is_add, ATOMIC_STORE16_I32>; +def : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, ATOMIC_STORE8_I64>; +def : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, ATOMIC_STORE16_I64>; +def : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, ATOMIC_STORE32_I64>; + +def : AStorePatGlobalAddr<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatGlobalAddr<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatGlobalAddr<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatGlobalAddr<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatGlobalAddr<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +def : AStorePatExternalSym<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatExternalSym<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatExternalSym<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatExternalSym<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatExternalSym<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +// Truncating stores with just a constant offset +def : AStorePatOffsetOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatOffsetOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatOffsetOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatOffsetOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatOffsetOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +def : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +def : AStorePatExternSymOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>; +def : AStorePatExternSymOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>; +def : AStorePatExternSymOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>; +def : AStorePatExternSymOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>; +def : AStorePatExternSymOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>; + +} // Predicates = [HasAtomics] //===----------------------------------------------------------------------===// // Low-level exclusive operations diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp index 93c109f9390..6f0ae897b96 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp @@ -118,6 +118,13 @@ bool WebAssemblySetP2AlignOperands::runOnMachineFunction(MachineFunction &MF) { case WebAssembly::STORE8_I64: case WebAssembly::STORE16_I64: case WebAssembly::STORE32_I64: + case WebAssembly::ATOMIC_STORE_I32: + case WebAssembly::ATOMIC_STORE8_I32: + case WebAssembly::ATOMIC_STORE16_I32: + case WebAssembly::ATOMIC_STORE_I64: + case WebAssembly::ATOMIC_STORE8_I64: + case WebAssembly::ATOMIC_STORE16_I64: + case WebAssembly::ATOMIC_STORE32_I64: RewriteP2Align(MI, WebAssembly::StoreP2AlignOperandNo); break; default: |