10b57cec5SDimitry Andric// WebAssemblyInstrAtomics.td-WebAssembly Atomic codegen support-*- tablegen -*- 20b57cec5SDimitry Andric// 30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric// 70b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric/// 90b57cec5SDimitry Andric/// \file 100b57cec5SDimitry Andric/// WebAssembly Atomic operand code-gen constructs. 110b57cec5SDimitry Andric/// 120b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andriclet UseNamedOperandTable = 1 in 150b57cec5SDimitry Andricmulticlass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s, 16*5ffd83dbSDimitry Andric list<dag> pattern_r, string asmstr_r, 17*5ffd83dbSDimitry Andric string asmstr_s, bits<32> atomic_op, 18*5ffd83dbSDimitry Andric string is64 = "false"> { 190b57cec5SDimitry Andric defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s, 20*5ffd83dbSDimitry Andric !or(0xfe00, !and(0xff, atomic_op)), is64>, 210b57cec5SDimitry Andric Requires<[HasAtomics]>; 220b57cec5SDimitry Andric} 230b57cec5SDimitry Andric 240b57cec5SDimitry Andricmulticlass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "", 250b57cec5SDimitry Andric bits<32> atomic_op = -1> { 260b57cec5SDimitry Andric defm "" : NRI<oops, iops, pattern, asmstr, 270b57cec5SDimitry Andric !or(0xfe00, !and(0xff, atomic_op))>, 280b57cec5SDimitry Andric Requires<[HasAtomics]>; 290b57cec5SDimitry Andric} 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 320b57cec5SDimitry Andric// Atomic wait / notify 330b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 340b57cec5SDimitry Andric 350b57cec5SDimitry Andriclet hasSideEffects = 1 in { 36*5ffd83dbSDimitry Andricdefm ATOMIC_NOTIFY_A32 : 370b57cec5SDimitry Andric ATOMIC_I<(outs I32:$dst), 380b57cec5SDimitry Andric (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count), 390b57cec5SDimitry Andric (outs), (ins P2Align:$p2align, offset32_op:$off), [], 400b57cec5SDimitry Andric "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count", 41*5ffd83dbSDimitry Andric "atomic.notify \t${off}${p2align}", 0x00, "false">; 42*5ffd83dbSDimitry Andricdefm ATOMIC_NOTIFY_A64 : 43*5ffd83dbSDimitry Andric ATOMIC_I<(outs I32:$dst), 44*5ffd83dbSDimitry Andric (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count), 45*5ffd83dbSDimitry Andric (outs), (ins P2Align:$p2align, offset64_op:$off), [], 46*5ffd83dbSDimitry Andric "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count", 47*5ffd83dbSDimitry Andric "atomic.notify \t${off}${p2align}", 0x00, "true">; 480b57cec5SDimitry Andriclet mayLoad = 1 in { 49*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I32_A32 : 500b57cec5SDimitry Andric ATOMIC_I<(outs I32:$dst), 510b57cec5SDimitry Andric (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp, 520b57cec5SDimitry Andric I64:$timeout), 530b57cec5SDimitry Andric (outs), (ins P2Align:$p2align, offset32_op:$off), [], 540b57cec5SDimitry Andric "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", 55*5ffd83dbSDimitry Andric "i32.atomic.wait \t${off}${p2align}", 0x01, "false">; 56*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I32_A64 : 57*5ffd83dbSDimitry Andric ATOMIC_I<(outs I32:$dst), 58*5ffd83dbSDimitry Andric (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp, 59*5ffd83dbSDimitry Andric I64:$timeout), 60*5ffd83dbSDimitry Andric (outs), (ins P2Align:$p2align, offset64_op:$off), [], 61*5ffd83dbSDimitry Andric "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", 62*5ffd83dbSDimitry Andric "i32.atomic.wait \t${off}${p2align}", 0x01, "true">; 63*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I64_A32 : 640b57cec5SDimitry Andric ATOMIC_I<(outs I32:$dst), 650b57cec5SDimitry Andric (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp, 660b57cec5SDimitry Andric I64:$timeout), 670b57cec5SDimitry Andric (outs), (ins P2Align:$p2align, offset32_op:$off), [], 680b57cec5SDimitry Andric "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", 69*5ffd83dbSDimitry Andric "i64.atomic.wait \t${off}${p2align}", 0x02, "false">; 70*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I64_A64 : 71*5ffd83dbSDimitry Andric ATOMIC_I<(outs I32:$dst), 72*5ffd83dbSDimitry Andric (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp, 73*5ffd83dbSDimitry Andric I64:$timeout), 74*5ffd83dbSDimitry Andric (outs), (ins P2Align:$p2align, offset64_op:$off), [], 75*5ffd83dbSDimitry Andric "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout", 76*5ffd83dbSDimitry Andric "i64.atomic.wait \t${off}${p2align}", 0x02, "true">; 770b57cec5SDimitry Andric} // mayLoad = 1 780b57cec5SDimitry Andric} // hasSideEffects = 1 790b57cec5SDimitry Andric 800b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 810b57cec5SDimitry Andric// Select notifys with no constant offset. 82*5ffd83dbSDimitry Andricdef NotifyPatNoOffset_A32 : 830b57cec5SDimitry Andric Pat<(i32 (int_wasm_atomic_notify I32:$addr, I32:$count)), 84*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A32 0, 0, I32:$addr, I32:$count)>, 85*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 86*5ffd83dbSDimitry Andricdef NotifyPatNoOffset_A64 : 87*5ffd83dbSDimitry Andric Pat<(i32 (int_wasm_atomic_notify I64:$addr, I32:$count)), 88*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A64 0, 0, I64:$addr, I32:$count)>, 89*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric// Select notifys with a constant offset. 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric// Pattern with address + immediate offset 94*5ffd83dbSDimitry Andricmulticlass NotifyPatImmOff<PatFrag operand, string inst> { 95*5ffd83dbSDimitry Andric def : Pat<(i32 (int_wasm_atomic_notify (operand I32:$addr, imm:$off), 96*5ffd83dbSDimitry Andric I32:$count)), 97*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, I32:$count)>, 98*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 99*5ffd83dbSDimitry Andric def : Pat<(i32 (int_wasm_atomic_notify (operand I64:$addr, imm:$off), 100*5ffd83dbSDimitry Andric I32:$count)), 101*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, I32:$count)>, 102*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 103*5ffd83dbSDimitry Andric} 104*5ffd83dbSDimitry Andricdefm : NotifyPatImmOff<regPlusImm, "ATOMIC_NOTIFY">; 105*5ffd83dbSDimitry Andricdefm : NotifyPatImmOff<or_is_add, "ATOMIC_NOTIFY">; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric// Select notifys with just a constant offset. 108*5ffd83dbSDimitry Andricdef NotifyPatOffsetOnly_A32 : 1090b57cec5SDimitry Andric Pat<(i32 (int_wasm_atomic_notify imm:$off, I32:$count)), 110*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A32 0, imm:$off, (CONST_I32 0), I32:$count)>, 111*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 112*5ffd83dbSDimitry Andricdef NotifyPatOffsetOnly_A64 : 113*5ffd83dbSDimitry Andric Pat<(i32 (int_wasm_atomic_notify imm:$off, I32:$count)), 114*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A64 0, imm:$off, (CONST_I64 0), I32:$count)>, 115*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 1160b57cec5SDimitry Andric 117*5ffd83dbSDimitry Andricdef NotifyPatGlobalAddrOffOnly_A32 : 1180b57cec5SDimitry Andric Pat<(i32 (int_wasm_atomic_notify (WebAssemblywrapper tglobaladdr:$off), 1190b57cec5SDimitry Andric I32:$count)), 120*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A32 0, tglobaladdr:$off, (CONST_I32 0), I32:$count)>, 121*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 122*5ffd83dbSDimitry Andricdef NotifyPatGlobalAddrOffOnly_A64 : 123*5ffd83dbSDimitry Andric Pat<(i32 (int_wasm_atomic_notify (WebAssemblywrapper tglobaladdr:$off), 124*5ffd83dbSDimitry Andric I32:$count)), 125*5ffd83dbSDimitry Andric (ATOMIC_NOTIFY_A64 0, tglobaladdr:$off, (CONST_I64 0), I32:$count)>, 126*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric// Select waits with no constant offset. 129*5ffd83dbSDimitry Andricmulticlass WaitPatNoOffset<ValueType ty, Intrinsic kind, 130*5ffd83dbSDimitry Andric string inst> { 131*5ffd83dbSDimitry Andric def : Pat<(i32 (kind I32:$addr, ty:$exp, I64:$timeout)), 132*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, I64:$timeout)>, 133*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 134*5ffd83dbSDimitry Andric def : Pat<(i32 (kind I64:$addr, ty:$exp, I64:$timeout)), 135*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, I64:$timeout)>, 136*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 137*5ffd83dbSDimitry Andric} 138*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">; 139*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">; 140*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">; 141*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric// Select waits with a constant offset. 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric// Pattern with address + immediate offset 146*5ffd83dbSDimitry Andricmulticlass WaitPatImmOff<ValueType ty, Intrinsic kind, PatFrag operand, 147*5ffd83dbSDimitry Andric string inst> { 148*5ffd83dbSDimitry Andric def : Pat<(i32 (kind (operand I32:$addr, imm:$off), ty:$exp, I64:$timeout)), 149*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp, 150*5ffd83dbSDimitry Andric I64:$timeout)>, 151*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 152*5ffd83dbSDimitry Andric def : Pat<(i32 (kind (operand I64:$addr, imm:$off), ty:$exp, I64:$timeout)), 153*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp, 154*5ffd83dbSDimitry Andric I64:$timeout)>, 155*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 156*5ffd83dbSDimitry Andric} 157*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, regPlusImm, 158*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I32">; 159*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, or_is_add, 160*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I32">; 161*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, regPlusImm, 162*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I64">; 163*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, or_is_add, 164*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I64">; 1650b57cec5SDimitry Andric 166*5ffd83dbSDimitry Andric// Select wait_i32, "ATOMIC_WAIT_I32s with just a constant offset. 167*5ffd83dbSDimitry Andricmulticlass WaitPatOffsetOnly<ValueType ty, Intrinsic kind, string inst> { 168*5ffd83dbSDimitry Andric def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)), 169*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp, 170*5ffd83dbSDimitry Andric I64:$timeout)>, 171*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 172*5ffd83dbSDimitry Andric def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)), 173*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp, 174*5ffd83dbSDimitry Andric I64:$timeout)>, 175*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 176*5ffd83dbSDimitry Andric} 177*5ffd83dbSDimitry Andricdefm : WaitPatOffsetOnly<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">; 178*5ffd83dbSDimitry Andricdefm : WaitPatOffsetOnly<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">; 1790b57cec5SDimitry Andric 180*5ffd83dbSDimitry Andricmulticlass WaitPatGlobalAddrOffOnly<ValueType ty, Intrinsic kind, string inst> { 181*5ffd83dbSDimitry Andric def : Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, 182*5ffd83dbSDimitry Andric I64:$timeout)), 183*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, 184*5ffd83dbSDimitry Andric I64:$timeout)>, 185*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 186*5ffd83dbSDimitry Andric def : Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, 187*5ffd83dbSDimitry Andric I64:$timeout)), 188*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp, 189*5ffd83dbSDimitry Andric I64:$timeout)>, 190*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 191*5ffd83dbSDimitry Andric} 192*5ffd83dbSDimitry Andricdefm : WaitPatGlobalAddrOffOnly<i32, int_wasm_atomic_wait_i32, 193*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I32">; 194*5ffd83dbSDimitry Andricdefm : WaitPatGlobalAddrOffOnly<i64, int_wasm_atomic_wait_i64, 195*5ffd83dbSDimitry Andric "ATOMIC_WAIT_I64">; 1960b57cec5SDimitry Andric} // Predicates = [HasAtomics] 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 1998bcb0991SDimitry Andric// Atomic fences 2008bcb0991SDimitry Andric//===----------------------------------------------------------------------===// 2018bcb0991SDimitry Andric 2028bcb0991SDimitry Andric// A compiler fence instruction that prevents reordering of instructions. 2038bcb0991SDimitry Andriclet Defs = [ARGUMENTS] in { 2048bcb0991SDimitry Andriclet isPseudo = 1, hasSideEffects = 1 in 2058bcb0991SDimitry Andricdefm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">; 2068bcb0991SDimitry Andriclet hasSideEffects = 1 in 2078bcb0991SDimitry Andricdefm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins i8imm:$flags), [], "atomic.fence", 2088bcb0991SDimitry Andric 0x03>; 2098bcb0991SDimitry Andric} // Defs = [ARGUMENTS] 2108bcb0991SDimitry Andric 2118bcb0991SDimitry Andric//===----------------------------------------------------------------------===// 2120b57cec5SDimitry Andric// Atomic loads 2130b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andricmulticlass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> { 216*5ffd83dbSDimitry Andric defm "" : WebAssemblyLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op)), 217*5ffd83dbSDimitry Andric [HasAtomics]>; 2180b57cec5SDimitry Andric} 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andricdefm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>; 2210b57cec5SDimitry Andricdefm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric// Select loads with no constant offset. 2240b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 225*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_32, "ATOMIC_LOAD_I32">; 226*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, atomic_load_64, "ATOMIC_LOAD_I64">; 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric// Select loads with a constant offset. 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric// Pattern with address + immediate offset 231*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_32, regPlusImm, "ATOMIC_LOAD_I32">; 232*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, atomic_load_64, regPlusImm, "ATOMIC_LOAD_I64">; 233*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_32, or_is_add, "ATOMIC_LOAD_I32">; 234*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, atomic_load_64, or_is_add, "ATOMIC_LOAD_I64">; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric// Select loads with just a constant offset. 237*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">; 238*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">; 2390b57cec5SDimitry Andric 240*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">; 241*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric} // Predicates = [HasAtomics] 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric// Extending loads. Note that there are only zero-extending atomic loads, no 2460b57cec5SDimitry Andric// sign-extending loads. 2470b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I32 : AtomicLoad<I32, "i32.atomic.load8_u", 0x12>; 2480b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I32 : AtomicLoad<I32, "i32.atomic.load16_u", 0x13>; 2490b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I64 : AtomicLoad<I64, "i64.atomic.load8_u", 0x14>; 2500b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I64 : AtomicLoad<I64, "i64.atomic.load16_u", 0x15>; 2510b57cec5SDimitry Andricdefm ATOMIC_LOAD32_U_I64 : AtomicLoad<I64, "i64.atomic.load32_u", 0x16>; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric// Fragments for extending loads. These are different from regular loads because 2540b57cec5SDimitry Andric// the SDNodes are derived from AtomicSDNode rather than LoadSDNode and 2550b57cec5SDimitry Andric// therefore don't have the extension type field. So instead of matching that, 2560b57cec5SDimitry Andric// we match the patterns that the type legalizer expands them to. 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric// We directly match zext patterns and select the zext atomic loads. 2590b57cec5SDimitry Andric// i32 (zext (i8 (atomic_load_8))) gets legalized to 2600b57cec5SDimitry Andric// i32 (and (i32 (atomic_load_8)), 255) 2610b57cec5SDimitry Andric// These can be selected to a single zero-extending atomic load instruction. 2620b57cec5SDimitry Andricdef zext_aload_8_32 : 2630b57cec5SDimitry Andric PatFrag<(ops node:$addr), (and (i32 (atomic_load_8 node:$addr)), 255)>; 2640b57cec5SDimitry Andricdef zext_aload_16_32 : 2650b57cec5SDimitry Andric PatFrag<(ops node:$addr), (and (i32 (atomic_load_16 node:$addr)), 65535)>; 2660b57cec5SDimitry Andric// Unlike regular loads, extension to i64 is handled differently than i32. 2670b57cec5SDimitry Andric// i64 (zext (i8 (atomic_load_8))) gets legalized to 2680b57cec5SDimitry Andric// i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255) 2690b57cec5SDimitry Andricdef zext_aload_8_64 : 2700b57cec5SDimitry Andric PatFrag<(ops node:$addr), 2710b57cec5SDimitry Andric (and (i64 (anyext (i32 (atomic_load_8 node:$addr)))), 255)>; 2720b57cec5SDimitry Andricdef zext_aload_16_64 : 2730b57cec5SDimitry Andric PatFrag<(ops node:$addr), 2740b57cec5SDimitry Andric (and (i64 (anyext (i32 (atomic_load_16 node:$addr)))), 65535)>; 2750b57cec5SDimitry Andricdef zext_aload_32_64 : 2760b57cec5SDimitry Andric PatFrag<(ops node:$addr), 2770b57cec5SDimitry Andric (zext (i32 (atomic_load node:$addr)))>; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric// We don't have single sext atomic load instructions. So for sext loads, we 2800b57cec5SDimitry Andric// match bare subword loads (for 32-bit results) and anyext loads (for 64-bit 2810b57cec5SDimitry Andric// results) and select a zext load; the next instruction will be sext_inreg 2820b57cec5SDimitry Andric// which is selected by itself. 2830b57cec5SDimitry Andricdef sext_aload_8_64 : 2840b57cec5SDimitry Andric PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>; 2850b57cec5SDimitry Andricdef sext_aload_16_64 : 2860b57cec5SDimitry Andric PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 2890b57cec5SDimitry Andric// Select zero-extending loads with no constant offset. 290*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">; 291*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">; 292*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 293*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 294*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric// Select sign-extending loads with no constant offset 297*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; 298*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; 299*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 300*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 3010b57cec5SDimitry Andric// 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric// Zero-extending loads with constant offset 304*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_8_32, regPlusImm, "ATOMIC_LOAD8_U_I32">; 305*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_16_32, regPlusImm, "ATOMIC_LOAD16_U_I32">; 306*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_8_32, or_is_add, "ATOMIC_LOAD8_U_I32">; 307*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_16_32, or_is_add, "ATOMIC_LOAD16_U_I32">; 308*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">; 309*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">; 310*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, "ATOMIC_LOAD32_U_I64">; 311*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">; 312*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">; 313*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, "ATOMIC_LOAD32_U_I64">; 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric// Sign-extending loads with constant offset 316*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_8, regPlusImm, "ATOMIC_LOAD8_U_I32">; 317*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_16, regPlusImm, "ATOMIC_LOAD16_U_I32">; 318*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_8, or_is_add, "ATOMIC_LOAD8_U_I32">; 319*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_16, or_is_add, "ATOMIC_LOAD16_U_I32">; 320*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">; 321*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">; 322*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">; 323*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">; 3240b57cec5SDimitry Andric// No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric// Extending loads with just a constant offset 327*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">; 328*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">; 329*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 330*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 331*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; 332*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; 333*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; 334*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 335*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 3360b57cec5SDimitry Andric 337*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">; 338*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">; 339*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 340*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 341*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">; 342*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">; 343*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">; 344*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">; 345*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">; 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric} // Predicates = [HasAtomics] 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 3500b57cec5SDimitry Andric// Atomic stores 3510b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andricmulticlass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> { 354*5ffd83dbSDimitry Andric defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op)), 355*5ffd83dbSDimitry Andric [HasAtomics]>; 3560b57cec5SDimitry Andric} 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andricdefm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>; 3590b57cec5SDimitry Andricdefm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>; 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric// We need an 'atomic' version of store patterns because store and atomic_store 3620b57cec5SDimitry Andric// nodes have different operand orders: 3630b57cec5SDimitry Andric// store: (store $val, $ptr) 3640b57cec5SDimitry Andric// atomic_store: (store $ptr, $val) 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric// Select stores with no constant offset. 369*5ffd83dbSDimitry Andricmulticlass AStorePatNoOffset<ValueType ty, PatFrag kind, string inst> { 370*5ffd83dbSDimitry Andric def : Pat<(kind I32:$addr, ty:$val), 371*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>, 372*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 373*5ffd83dbSDimitry Andric def : Pat<(kind I64:$addr, ty:$val), 374*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>, 375*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 376*5ffd83dbSDimitry Andric} 377*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_32, "ATOMIC_STORE_I32">; 378*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, atomic_store_64, "ATOMIC_STORE_I64">; 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric// Select stores with a constant offset. 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric// Pattern with address + immediate offset 383*5ffd83dbSDimitry Andricmulticlass AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, 384*5ffd83dbSDimitry Andric string inst> { 385*5ffd83dbSDimitry Andric def : Pat<(kind (operand I32:$addr, imm:$off), ty:$val), 386*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>, 387*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 388*5ffd83dbSDimitry Andric def : Pat<(kind (operand I64:$addr, imm:$off), ty:$val), 389*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>, 390*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 391*5ffd83dbSDimitry Andric} 392*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_32, regPlusImm, "ATOMIC_STORE_I32">; 393*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, atomic_store_64, regPlusImm, "ATOMIC_STORE_I64">; 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric// Select stores with just a constant offset. 396*5ffd83dbSDimitry Andricmulticlass AStorePatOffsetOnly<ValueType ty, PatFrag kind, string inst> { 397*5ffd83dbSDimitry Andric def : Pat<(kind imm:$off, ty:$val), 398*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>, 399*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 400*5ffd83dbSDimitry Andric def : Pat<(kind imm:$off, ty:$val), 401*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>, 402*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 403*5ffd83dbSDimitry Andric} 404*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">; 405*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">; 4060b57cec5SDimitry Andric 407*5ffd83dbSDimitry Andricmulticlass AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { 408*5ffd83dbSDimitry Andric def : Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val), 409*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, 410*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 411*5ffd83dbSDimitry Andric def : Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val), 412*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>, 413*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 414*5ffd83dbSDimitry Andric} 415*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">; 416*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">; 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric} // Predicates = [HasAtomics] 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric// Truncating stores. 4210b57cec5SDimitry Andricdefm ATOMIC_STORE8_I32 : AtomicStore<I32, "i32.atomic.store8", 0x19>; 4220b57cec5SDimitry Andricdefm ATOMIC_STORE16_I32 : AtomicStore<I32, "i32.atomic.store16", 0x1a>; 4230b57cec5SDimitry Andricdefm ATOMIC_STORE8_I64 : AtomicStore<I64, "i64.atomic.store8", 0x1b>; 4240b57cec5SDimitry Andricdefm ATOMIC_STORE16_I64 : AtomicStore<I64, "i64.atomic.store16", 0x1c>; 4250b57cec5SDimitry Andricdefm ATOMIC_STORE32_I64 : AtomicStore<I64, "i64.atomic.store32", 0x1d>; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric// Fragments for truncating stores. 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric// We don't have single truncating atomic store instructions. For 32-bit 4300b57cec5SDimitry Andric// instructions, we just need to match bare atomic stores. On the other hand, 4310b57cec5SDimitry Andric// truncating stores from i64 values are once truncated to i32 first. 4320b57cec5SDimitry Andricclass trunc_astore_64<PatFrag kind> : 4330b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 4340b57cec5SDimitry Andric (kind node:$addr, (i32 (trunc (i64 node:$val))))>; 4350b57cec5SDimitry Andricdef trunc_astore_8_64 : trunc_astore_64<atomic_store_8>; 4360b57cec5SDimitry Andricdef trunc_astore_16_64 : trunc_astore_64<atomic_store_16>; 4370b57cec5SDimitry Andricdef trunc_astore_32_64 : trunc_astore_64<atomic_store_32>; 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric// Truncating stores with no constant offset 442*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_8, "ATOMIC_STORE8_I32">; 443*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_16, "ATOMIC_STORE16_I32">; 444*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; 445*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; 446*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric// Truncating stores with a constant offset 449*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_8, regPlusImm, "ATOMIC_STORE8_I32">; 450*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_16, regPlusImm, "ATOMIC_STORE16_I32">; 451*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, "ATOMIC_STORE8_I64">; 452*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, 453*5ffd83dbSDimitry Andric "ATOMIC_STORE16_I64">; 454*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, 455*5ffd83dbSDimitry Andric "ATOMIC_STORE32_I64">; 456*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_8, or_is_add, "ATOMIC_STORE8_I32">; 457*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_16, or_is_add, "ATOMIC_STORE16_I32">; 458*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, "ATOMIC_STORE8_I64">; 459*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, 460*5ffd83dbSDimitry Andric "ATOMIC_STORE16_I64">; 461*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, 462*5ffd83dbSDimitry Andric "ATOMIC_STORE32_I64">; 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric// Truncating stores with just a constant offset 465*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">; 466*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">; 467*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; 468*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; 469*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; 4700b57cec5SDimitry Andric 471*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">; 472*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">; 473*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">; 474*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">; 475*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric} // Predicates = [HasAtomics] 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 4800b57cec5SDimitry Andric// Atomic binary read-modify-writes 4810b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andricmulticlass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name, 4840b57cec5SDimitry Andric int atomic_op> { 485*5ffd83dbSDimitry Andric defm "_A32" : 4860b57cec5SDimitry Andric ATOMIC_I<(outs rc:$dst), 4870b57cec5SDimitry Andric (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), 4880b57cec5SDimitry Andric (outs), (ins P2Align:$p2align, offset32_op:$off), [], 4890b57cec5SDimitry Andric !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"), 490*5ffd83dbSDimitry Andric !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">; 491*5ffd83dbSDimitry Andric defm "_A64" : 492*5ffd83dbSDimitry Andric ATOMIC_I<(outs rc:$dst), 493*5ffd83dbSDimitry Andric (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val), 494*5ffd83dbSDimitry Andric (outs), (ins P2Align:$p2align, offset64_op:$off), [], 495*5ffd83dbSDimitry Andric !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"), 496*5ffd83dbSDimitry Andric !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">; 4970b57cec5SDimitry Andric} 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>; 5000b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0x1f>; 5010b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I32 : 5020b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.add_u", 0x20>; 5030b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I32 : 5040b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.add_u", 0x21>; 5050b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I64 : 5060b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.add_u", 0x22>; 5070b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I64 : 5080b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.add_u", 0x23>; 5090b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_ADD_I64 : 5100b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.add_u", 0x24>; 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0x25>; 5130b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0x26>; 5140b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I32 : 5150b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.sub_u", 0x27>; 5160b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I32 : 5170b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.sub_u", 0x28>; 5180b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I64 : 5190b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.sub_u", 0x29>; 5200b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I64 : 5210b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.sub_u", 0x2a>; 5220b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_SUB_I64 : 5230b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.sub_u", 0x2b>; 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0x2c>; 5260b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0x2d>; 5270b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I32 : 5280b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.and_u", 0x2e>; 5290b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I32 : 5300b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.and_u", 0x2f>; 5310b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I64 : 5320b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.and_u", 0x30>; 5330b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I64 : 5340b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.and_u", 0x31>; 5350b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_AND_I64 : 5360b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.and_u", 0x32>; 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0x33>; 5390b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0x34>; 5400b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I32 : 5410b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.or_u", 0x35>; 5420b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I32 : 5430b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.or_u", 0x36>; 5440b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I64 : 5450b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.or_u", 0x37>; 5460b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I64 : 5470b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.or_u", 0x38>; 5480b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_OR_I64 : 5490b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.or_u", 0x39>; 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0x3a>; 5520b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0x3b>; 5530b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I32 : 5540b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xor_u", 0x3c>; 5550b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I32 : 5560b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xor_u", 0x3d>; 5570b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I64 : 5580b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xor_u", 0x3e>; 5590b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I64 : 5600b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xor_u", 0x3f>; 5610b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XOR_I64 : 5620b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xor_u", 0x40>; 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I32 : 5650b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0x41>; 5660b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I64 : 5670b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0x42>; 5680b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I32 : 5690b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xchg_u", 0x43>; 5700b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I32 : 5710b57cec5SDimitry Andric WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xchg_u", 0x44>; 5720b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I64 : 5730b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xchg_u", 0x45>; 5740b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I64 : 5750b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xchg_u", 0x46>; 5760b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XCHG_I64 : 5770b57cec5SDimitry Andric WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>; 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric// Select binary RMWs with no constant offset. 580*5ffd83dbSDimitry Andricmulticlass BinRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> { 581*5ffd83dbSDimitry Andric def : Pat<(ty (kind I32:$addr, ty:$val)), 582*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>, 583*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 584*5ffd83dbSDimitry Andric def : Pat<(ty (kind I64:$addr, ty:$val)), 585*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>, 586*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 587*5ffd83dbSDimitry Andric} 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric// Select binary RMWs with a constant offset. 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric// Pattern with address + immediate offset 592*5ffd83dbSDimitry Andricmulticlass BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, 593*5ffd83dbSDimitry Andric string inst> { 594*5ffd83dbSDimitry Andric def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)), 595*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>, 596*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 597*5ffd83dbSDimitry Andric def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$val)), 598*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>, 599*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 600*5ffd83dbSDimitry Andric} 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric// Select binary RMWs with just a constant offset. 603*5ffd83dbSDimitry Andricmulticlass BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> { 604*5ffd83dbSDimitry Andric def : Pat<(ty (kind imm:$off, ty:$val)), 605*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>, 606*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 607*5ffd83dbSDimitry Andric def : Pat<(ty (kind imm:$off, ty:$val)), 608*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>, 609*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 610*5ffd83dbSDimitry Andric} 6110b57cec5SDimitry Andric 612*5ffd83dbSDimitry Andricmulticlass BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> { 613*5ffd83dbSDimitry Andric def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)), 614*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>, 615*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 616*5ffd83dbSDimitry Andric def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)), 617*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>, 618*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 619*5ffd83dbSDimitry Andric} 6200b57cec5SDimitry Andric 6210b57cec5SDimitry Andric// Patterns for various addressing modes. 622*5ffd83dbSDimitry Andricmulticlass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32, 623*5ffd83dbSDimitry Andric string inst_64> { 624*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i32, rmw_32, inst_32>; 625*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, rmw_64, inst_64>; 6260b57cec5SDimitry Andric 627*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>; 628*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>; 629*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>; 630*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>; 6310b57cec5SDimitry Andric 632*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>; 633*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>; 6340b57cec5SDimitry Andric 635*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>; 636*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>; 6370b57cec5SDimitry Andric} 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 640*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64, 641*5ffd83dbSDimitry Andric "ATOMIC_RMW_ADD_I32", "ATOMIC_RMW_ADD_I64">; 642*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_sub_32, atomic_load_sub_64, 643*5ffd83dbSDimitry Andric "ATOMIC_RMW_SUB_I32", "ATOMIC_RMW_SUB_I64">; 644*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_and_32, atomic_load_and_64, 645*5ffd83dbSDimitry Andric "ATOMIC_RMW_AND_I32", "ATOMIC_RMW_AND_I64">; 646*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_or_32, atomic_load_or_64, 647*5ffd83dbSDimitry Andric "ATOMIC_RMW_OR_I32", "ATOMIC_RMW_OR_I64">; 648*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_xor_32, atomic_load_xor_64, 649*5ffd83dbSDimitry Andric "ATOMIC_RMW_XOR_I32", "ATOMIC_RMW_XOR_I64">; 650*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_swap_32, atomic_swap_64, 651*5ffd83dbSDimitry Andric "ATOMIC_RMW_XCHG_I32", "ATOMIC_RMW_XCHG_I64">; 6520b57cec5SDimitry Andric} // Predicates = [HasAtomics] 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric// Truncating & zero-extending binary RMW patterns. 6550b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and zero-extending 6560b57cec5SDimitry Andric// load patterns above. 6570b57cec5SDimitry Andricclass zext_bin_rmw_8_32<PatFrag kind> : 6580b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6590b57cec5SDimitry Andric (and (i32 (kind node:$addr, node:$val)), 255)>; 6600b57cec5SDimitry Andricclass zext_bin_rmw_16_32<PatFrag kind> : 6610b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6620b57cec5SDimitry Andric (and (i32 (kind node:$addr, node:$val)), 65535)>; 6630b57cec5SDimitry Andricclass zext_bin_rmw_8_64<PatFrag kind> : 6640b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6650b57cec5SDimitry Andric (and (i64 (anyext (i32 (kind node:$addr, 6660b57cec5SDimitry Andric (i32 (trunc (i64 node:$val))))))), 255)>; 6670b57cec5SDimitry Andricclass zext_bin_rmw_16_64<PatFrag kind> : 6680b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6690b57cec5SDimitry Andric (and (i64 (anyext (i32 (kind node:$addr, 6700b57cec5SDimitry Andric (i32 (trunc (i64 node:$val))))))), 65535)>; 6710b57cec5SDimitry Andricclass zext_bin_rmw_32_64<PatFrag kind> : 6720b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6730b57cec5SDimitry Andric (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>; 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric// Truncating & sign-extending binary RMW patterns. 6760b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and sign-extending 6770b57cec5SDimitry Andric// load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for 6780b57cec5SDimitry Andric// 64-bit) and select a zext RMW; the next instruction will be sext_inreg which 6790b57cec5SDimitry Andric// is selected by itself. 6800b57cec5SDimitry Andricclass sext_bin_rmw_8_32<PatFrag kind> : 6810b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>; 6820b57cec5SDimitry Andricclass sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>; 6830b57cec5SDimitry Andricclass sext_bin_rmw_8_64<PatFrag kind> : 6840b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$val), 6850b57cec5SDimitry Andric (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>; 6860b57cec5SDimitry Andricclass sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>; 6870b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending binary RMWs. 6900b57cec5SDimitry Andricmulticlass BinRMWTruncExtPattern< 6910b57cec5SDimitry Andric PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64, 6920b57cec5SDimitry Andric NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> { 6930b57cec5SDimitry Andric // Truncating-extending binary RMWs with no constant offset 694*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; 695*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; 696*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; 697*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; 698*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; 6990b57cec5SDimitry Andric 700*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; 701*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; 702*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; 703*5ffd83dbSDimitry Andric defm : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric // Truncating-extending binary RMWs with a constant offset 706*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; 707*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm, 708*5ffd83dbSDimitry Andric inst16_32>; 709*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; 710*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm, 711*5ffd83dbSDimitry Andric inst16_64>; 712*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm, 713*5ffd83dbSDimitry Andric inst32_64>; 714*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>; 715*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>; 716*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>; 717*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>; 718*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>; 7190b57cec5SDimitry Andric 720*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; 721*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm, 722*5ffd83dbSDimitry Andric inst16_32>; 723*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; 724*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm, 725*5ffd83dbSDimitry Andric inst16_64>; 726*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>; 727*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>; 728*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>; 729*5ffd83dbSDimitry Andric defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>; 7300b57cec5SDimitry Andric 7310b57cec5SDimitry Andric // Truncating-extending binary RMWs with just a constant offset 732*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; 733*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; 734*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; 735*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; 736*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; 7370b57cec5SDimitry Andric 738*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; 739*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; 740*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; 741*5ffd83dbSDimitry Andric defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; 7420b57cec5SDimitry Andric 743*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>; 744*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>; 745*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>; 746*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>; 747*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>; 7480b57cec5SDimitry Andric 749*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>; 750*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>; 751*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>; 752*5ffd83dbSDimitry Andric defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>; 7530b57cec5SDimitry Andric} 7540b57cec5SDimitry Andric 7550b57cec5SDimitry Andriclet Predicates = [HasAtomics] in { 7560b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7570b57cec5SDimitry Andric atomic_load_add_8, atomic_load_add_16, atomic_load_add_32, atomic_load_add_64, 758*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_ADD_I32", "ATOMIC_RMW16_U_ADD_I32", 759*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_ADD_I64", "ATOMIC_RMW16_U_ADD_I64", "ATOMIC_RMW32_U_ADD_I64">; 7600b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7610b57cec5SDimitry Andric atomic_load_sub_8, atomic_load_sub_16, atomic_load_sub_32, atomic_load_sub_64, 762*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_SUB_I32", "ATOMIC_RMW16_U_SUB_I32", 763*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_SUB_I64", "ATOMIC_RMW16_U_SUB_I64", "ATOMIC_RMW32_U_SUB_I64">; 7640b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7650b57cec5SDimitry Andric atomic_load_and_8, atomic_load_and_16, atomic_load_and_32, atomic_load_and_64, 766*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_AND_I32", "ATOMIC_RMW16_U_AND_I32", 767*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_AND_I64", "ATOMIC_RMW16_U_AND_I64", "ATOMIC_RMW32_U_AND_I64">; 7680b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7690b57cec5SDimitry Andric atomic_load_or_8, atomic_load_or_16, atomic_load_or_32, atomic_load_or_64, 770*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_OR_I32", "ATOMIC_RMW16_U_OR_I32", 771*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_OR_I64", "ATOMIC_RMW16_U_OR_I64", "ATOMIC_RMW32_U_OR_I64">; 7720b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7730b57cec5SDimitry Andric atomic_load_xor_8, atomic_load_xor_16, atomic_load_xor_32, atomic_load_xor_64, 774*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_XOR_I32", "ATOMIC_RMW16_U_XOR_I32", 775*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_XOR_I64", "ATOMIC_RMW16_U_XOR_I64", "ATOMIC_RMW32_U_XOR_I64">; 7760b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern< 7770b57cec5SDimitry Andric atomic_swap_8, atomic_swap_16, atomic_swap_32, atomic_swap_64, 778*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_XCHG_I32", "ATOMIC_RMW16_U_XCHG_I32", 779*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_XCHG_I64", "ATOMIC_RMW16_U_XCHG_I64", 780*5ffd83dbSDimitry Andric "ATOMIC_RMW32_U_XCHG_I64">; 7810b57cec5SDimitry Andric} // Predicates = [HasAtomics] 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 7840b57cec5SDimitry Andric// Atomic ternary read-modify-writes 7850b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric// TODO LLVM IR's cmpxchg instruction returns a pair of {loaded value, success 7880b57cec5SDimitry Andric// flag}. When we use the success flag or both values, we can't make use of i64 7890b57cec5SDimitry Andric// truncate/extend versions of instructions for now, which is suboptimal. 7900b57cec5SDimitry Andric// Consider adding a pass after instruction selection that optimizes this case 7910b57cec5SDimitry Andric// if it is frequent. 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andricmulticlass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name, 7940b57cec5SDimitry Andric int atomic_op> { 795*5ffd83dbSDimitry Andric defm "_A32" : 7960b57cec5SDimitry Andric ATOMIC_I<(outs rc:$dst), 7970b57cec5SDimitry Andric (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp, 7980b57cec5SDimitry Andric rc:$new_), 7990b57cec5SDimitry Andric (outs), (ins P2Align:$p2align, offset32_op:$off), [], 8000b57cec5SDimitry Andric !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"), 801*5ffd83dbSDimitry Andric !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">; 802*5ffd83dbSDimitry Andric defm "_A64" : 803*5ffd83dbSDimitry Andric ATOMIC_I<(outs rc:$dst), 804*5ffd83dbSDimitry Andric (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp, 805*5ffd83dbSDimitry Andric rc:$new_), 806*5ffd83dbSDimitry Andric (outs), (ins P2Align:$p2align, offset64_op:$off), [], 807*5ffd83dbSDimitry Andric !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"), 808*5ffd83dbSDimitry Andric !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">; 8090b57cec5SDimitry Andric} 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I32 : 8120b57cec5SDimitry Andric WebAssemblyTerRMW<I32, "i32.atomic.rmw.cmpxchg", 0x48>; 8130b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I64 : 8140b57cec5SDimitry Andric WebAssemblyTerRMW<I64, "i64.atomic.rmw.cmpxchg", 0x49>; 8150b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I32 : 8160b57cec5SDimitry Andric WebAssemblyTerRMW<I32, "i32.atomic.rmw8.cmpxchg_u", 0x4a>; 8170b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I32 : 8180b57cec5SDimitry Andric WebAssemblyTerRMW<I32, "i32.atomic.rmw16.cmpxchg_u", 0x4b>; 8190b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I64 : 8200b57cec5SDimitry Andric WebAssemblyTerRMW<I64, "i64.atomic.rmw8.cmpxchg_u", 0x4c>; 8210b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I64 : 8220b57cec5SDimitry Andric WebAssemblyTerRMW<I64, "i64.atomic.rmw16.cmpxchg_u", 0x4d>; 8230b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_CMPXCHG_I64 : 8240b57cec5SDimitry Andric WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>; 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric// Select ternary RMWs with no constant offset. 827*5ffd83dbSDimitry Andricmulticlass TerRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> { 828*5ffd83dbSDimitry Andric def : Pat<(ty (kind I32:$addr, ty:$exp, ty:$new)), 829*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, ty:$new)>, 830*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 831*5ffd83dbSDimitry Andric def : Pat<(ty (kind I64:$addr, ty:$exp, ty:$new)), 832*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, ty:$new)>, 833*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 834*5ffd83dbSDimitry Andric} 8350b57cec5SDimitry Andric 8360b57cec5SDimitry Andric// Select ternary RMWs with a constant offset. 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric// Pattern with address + immediate offset 839*5ffd83dbSDimitry Andricmulticlass TerRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, 840*5ffd83dbSDimitry Andric string inst> { 841*5ffd83dbSDimitry Andric def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$exp, ty:$new)), 842*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp, ty:$new)>, 843*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 844*5ffd83dbSDimitry Andric def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$exp, ty:$new)), 845*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp, ty:$new)>, 846*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 847*5ffd83dbSDimitry Andric} 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric// Select ternary RMWs with just a constant offset. 850*5ffd83dbSDimitry Andricmulticlass TerRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> { 851*5ffd83dbSDimitry Andric def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)), 852*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp, 853*5ffd83dbSDimitry Andric ty:$new)>; 854*5ffd83dbSDimitry Andric def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)), 855*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp, 856*5ffd83dbSDimitry Andric ty:$new)>; 857*5ffd83dbSDimitry Andric} 8580b57cec5SDimitry Andric 859*5ffd83dbSDimitry Andricmulticlass TerRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> { 860*5ffd83dbSDimitry Andric def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)), 861*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, 862*5ffd83dbSDimitry Andric ty:$new)>, 863*5ffd83dbSDimitry Andric Requires<[HasAddr32]>; 864*5ffd83dbSDimitry Andric def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)), 865*5ffd83dbSDimitry Andric (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp, 866*5ffd83dbSDimitry Andric ty:$new)>, 867*5ffd83dbSDimitry Andric Requires<[HasAddr64]>; 868*5ffd83dbSDimitry Andric} 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric// Patterns for various addressing modes. 871*5ffd83dbSDimitry Andricmulticlass TerRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32, 872*5ffd83dbSDimitry Andric string inst_64> { 873*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i32, rmw_32, inst_32>; 874*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, rmw_64, inst_64>; 8750b57cec5SDimitry Andric 876*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>; 877*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>; 878*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>; 879*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>; 8800b57cec5SDimitry Andric 881*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i32, rmw_32, inst_32>; 882*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, rmw_64, inst_64>; 8830b57cec5SDimitry Andric 884*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>; 885*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>; 8860b57cec5SDimitry Andric} 8870b57cec5SDimitry Andric 8880b57cec5SDimitry Andriclet Predicates = [HasAtomics] in 8890b57cec5SDimitry Andricdefm : TerRMWPattern<atomic_cmp_swap_32, atomic_cmp_swap_64, 890*5ffd83dbSDimitry Andric "ATOMIC_RMW_CMPXCHG_I32", "ATOMIC_RMW_CMPXCHG_I64">; 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric// Truncating & zero-extending ternary RMW patterns. 8930b57cec5SDimitry Andric// DAG legalization & optimization before instruction selection may introduce 8940b57cec5SDimitry Andric// additional nodes such as anyext or assertzext depending on operand types. 8950b57cec5SDimitry Andricclass zext_ter_rmw_8_32<PatFrag kind> : 8960b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 8970b57cec5SDimitry Andric (and (i32 (kind node:$addr, node:$exp, node:$new)), 255)>; 8980b57cec5SDimitry Andricclass zext_ter_rmw_16_32<PatFrag kind> : 8990b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 9000b57cec5SDimitry Andric (and (i32 (kind node:$addr, node:$exp, node:$new)), 65535)>; 9010b57cec5SDimitry Andricclass zext_ter_rmw_8_64<PatFrag kind> : 9020b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 9030b57cec5SDimitry Andric (zext (i32 (assertzext (i32 (kind node:$addr, 9040b57cec5SDimitry Andric (i32 (trunc (i64 node:$exp))), 9050b57cec5SDimitry Andric (i32 (trunc (i64 node:$new))))))))>; 9060b57cec5SDimitry Andricclass zext_ter_rmw_16_64<PatFrag kind> : zext_ter_rmw_8_64<kind>; 9070b57cec5SDimitry Andricclass zext_ter_rmw_32_64<PatFrag kind> : 9080b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 9090b57cec5SDimitry Andric (zext (i32 (kind node:$addr, 9100b57cec5SDimitry Andric (i32 (trunc (i64 node:$exp))), 9110b57cec5SDimitry Andric (i32 (trunc (i64 node:$new))))))>; 9120b57cec5SDimitry Andric 9130b57cec5SDimitry Andric// Truncating & sign-extending ternary RMW patterns. 9140b57cec5SDimitry Andric// We match subword RMWs (for 32-bit) and anyext RMWs (for 64-bit) and select a 9150b57cec5SDimitry Andric// zext RMW; the next instruction will be sext_inreg which is selected by 9160b57cec5SDimitry Andric// itself. 9170b57cec5SDimitry Andricclass sext_ter_rmw_8_32<PatFrag kind> : 9180b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 9190b57cec5SDimitry Andric (kind node:$addr, node:$exp, node:$new)>; 9200b57cec5SDimitry Andricclass sext_ter_rmw_16_32<PatFrag kind> : sext_ter_rmw_8_32<kind>; 9210b57cec5SDimitry Andricclass sext_ter_rmw_8_64<PatFrag kind> : 9220b57cec5SDimitry Andric PatFrag<(ops node:$addr, node:$exp, node:$new), 9230b57cec5SDimitry Andric (anyext (i32 (assertzext (i32 9240b57cec5SDimitry Andric (kind node:$addr, 9250b57cec5SDimitry Andric (i32 (trunc (i64 node:$exp))), 9260b57cec5SDimitry Andric (i32 (trunc (i64 node:$new))))))))>; 9270b57cec5SDimitry Andricclass sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>; 9280b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending ternary RMWs. 9310b57cec5SDimitry Andricmulticlass TerRMWTruncExtPattern< 9320b57cec5SDimitry Andric PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64, 933*5ffd83dbSDimitry Andric string inst8_32, string inst16_32, string inst8_64, string inst16_64, 934*5ffd83dbSDimitry Andric string inst32_64> { 9350b57cec5SDimitry Andric // Truncating-extending ternary RMWs with no constant offset 936*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; 937*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; 938*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; 939*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; 940*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; 9410b57cec5SDimitry Andric 942*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; 943*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; 944*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; 945*5ffd83dbSDimitry Andric defm : TerRMWPatNoOffset<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; 9460b57cec5SDimitry Andric 9470b57cec5SDimitry Andric // Truncating-extending ternary RMWs with a constant offset 948*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; 949*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, regPlusImm, 950*5ffd83dbSDimitry Andric inst16_32>; 951*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; 952*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, regPlusImm, 953*5ffd83dbSDimitry Andric inst16_64>; 954*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, regPlusImm, 955*5ffd83dbSDimitry Andric inst32_64>; 956*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>; 957*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>; 958*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>; 959*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>; 960*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, or_is_add, inst32_64>; 9610b57cec5SDimitry Andric 962*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>; 963*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, regPlusImm, 964*5ffd83dbSDimitry Andric inst16_32>; 965*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>; 966*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, regPlusImm, 967*5ffd83dbSDimitry Andric inst16_64>; 968*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>; 969*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>; 970*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>; 971*5ffd83dbSDimitry Andric defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>; 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric // Truncating-extending ternary RMWs with just a constant offset 974*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; 975*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; 976*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; 977*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; 978*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; 9790b57cec5SDimitry Andric 980*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; 981*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; 982*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; 983*5ffd83dbSDimitry Andric defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; 9840b57cec5SDimitry Andric 985*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>; 986*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>; 987*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>; 988*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>; 989*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>; 9900b57cec5SDimitry Andric 991*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>; 992*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>; 993*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>; 994*5ffd83dbSDimitry Andric defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>; 9950b57cec5SDimitry Andric} 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andriclet Predicates = [HasAtomics] in 9980b57cec5SDimitry Andricdefm : TerRMWTruncExtPattern< 9990b57cec5SDimitry Andric atomic_cmp_swap_8, atomic_cmp_swap_16, atomic_cmp_swap_32, atomic_cmp_swap_64, 1000*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_CMPXCHG_I32", "ATOMIC_RMW16_U_CMPXCHG_I32", 1001*5ffd83dbSDimitry Andric "ATOMIC_RMW8_U_CMPXCHG_I64", "ATOMIC_RMW16_U_CMPXCHG_I64", 1002*5ffd83dbSDimitry Andric "ATOMIC_RMW32_U_CMPXCHG_I64">; 1003