Title: [270214] trunk
Revision
270214
Author
ysuz...@apple.com
Date
2020-11-27 20:31:41 -0800 (Fri, 27 Nov 2020)

Log Message

[JSC] Use ARM atomic ops in wasm
https://bugs.webkit.org/show_bug.cgi?id=219281

Reviewed by Filip Pizlo.

JSTests:

* wasm/threads-spec-tests/atomic-signed.wast.js:
* wasm/threads-spec-tests/resources/atomic-signed.wast:

Source/_javascript_Core:

This patch uses ARM LSE Atomic instructions in wasm atomic operations. This includes support in MacroAssembler, offlineasm, Air and B3,
so that FTL atomic operations automatically leverage ARM LSE atomic instructions too. Later we can extend DFG JIT to use it too.

One interesting thing is that this includes a fix for cmpxchg wasm operation implementations. Unfortunately, current wasm cmpxchg ops
are not the same to ARM cas / X86 cmpxchg. For example, i64.atomic.rmw8.cmpxchg_u takes i64 expected value. And the spec requires that
we should perform `i64-expected-value <cmp> loaded-zero-extended-1byte-value`. For example, if the expected value is `0xffffffff_ffffff00`,
and the value stored in the memory is `0x00`, then the wasm op needs to fail since `0x00` is not `0xffffffff_ffffff00`. But x86 and ARM
cmpxchg / cas ops behave differently since it truncates expected value to 1byte when performing 1byte cmpxchg. So we need to have a check
which performs the value is within 1byte range in this operation.

* assembler/ARM64EAssembler.h:
(JSC::ARM64EAssembler::exoticAtomicLoadStore):
(JSC::ARM64EAssembler::exoticAtomicCAS):
(JSC::ARM64EAssembler::ldaddal):
(JSC::ARM64EAssembler::ldeoral):
(JSC::ARM64EAssembler::ldclral):
(JSC::ARM64EAssembler::ldsetal):
(JSC::ARM64EAssembler::swpal):
(JSC::ARM64EAssembler::casal):
* assembler/MacroAssemblerARM64E.h:
(JSC::MacroAssemblerARM64E::atomicXchgAdd8):
(JSC::MacroAssemblerARM64E::atomicXchgAdd16):
(JSC::MacroAssemblerARM64E::atomicXchgAdd32):
(JSC::MacroAssemblerARM64E::atomicXchgAdd64):
(JSC::MacroAssemblerARM64E::atomicXchgXor8):
(JSC::MacroAssemblerARM64E::atomicXchgXor16):
(JSC::MacroAssemblerARM64E::atomicXchgXor32):
(JSC::MacroAssemblerARM64E::atomicXchgXor64):
(JSC::MacroAssemblerARM64E::atomicXchgOr8):
(JSC::MacroAssemblerARM64E::atomicXchgOr16):
(JSC::MacroAssemblerARM64E::atomicXchgOr32):
(JSC::MacroAssemblerARM64E::atomicXchgOr64):
(JSC::MacroAssemblerARM64E::atomicXchgClear8):
(JSC::MacroAssemblerARM64E::atomicXchgClear16):
(JSC::MacroAssemblerARM64E::atomicXchgClear32):
(JSC::MacroAssemblerARM64E::atomicXchgClear64):
(JSC::MacroAssemblerARM64E::atomicXchg8):
(JSC::MacroAssemblerARM64E::atomicXchg16):
(JSC::MacroAssemblerARM64E::atomicXchg32):
(JSC::MacroAssemblerARM64E::atomicXchg64):
(JSC::MacroAssemblerARM64E::atomicStrongCAS8):
(JSC::MacroAssemblerARM64E::atomicStrongCAS16):
(JSC::MacroAssemblerARM64E::atomicStrongCAS32):
(JSC::MacroAssemblerARM64E::atomicStrongCAS64):
* b3/B3LowerMacros.cpp:
* b3/B3LowerToAir.cpp:
* b3/air/AirOpcode.opcodes:
* b3/air/opcode_generator.rb:
* disassembler/ARM64/A64DOpcode.cpp:
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::format):
(JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::format):
(JSC::ARM64Disassembler::A64DOpcodeCAS::format):
* disassembler/ARM64/A64DOpcode.h:
(JSC::ARM64Disassembler::A64DOpcode::appendInstructionName):
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opName):
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::rs):
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opc):
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::ar):
(JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opNumber):
(JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::opName):
(JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::rs):
(JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::ar):
(JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::opNumber):
(JSC::ARM64Disassembler::A64DOpcodeCAS::opName):
(JSC::ARM64Disassembler::A64DOpcodeCAS::rs):
(JSC::ARM64Disassembler::A64DOpcodeCAS::o1):
(JSC::ARM64Disassembler::A64DOpcodeCAS::l):
(JSC::ARM64Disassembler::A64DOpcodeCAS::opNumber):
* llint/WebAssembly.asm:
* offlineasm/arm64.rb:
* offlineasm/instructions.rb:
* offlineasm/x86.rb:
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::sanitizeAtomicResult):
(JSC::Wasm::AirIRGenerator::appendGeneralAtomic):
(JSC::Wasm::AirIRGenerator::appendStrongCAS):
(JSC::Wasm::AirIRGenerator::emitAtomicLoadOp):
(JSC::Wasm::AirIRGenerator::emitAtomicStoreOp):
(JSC::Wasm::AirIRGenerator::emitAtomicBinaryRMWOp):
(JSC::Wasm::AirIRGenerator::emitAtomicCompareExchange):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::emitAtomicCompareExchange):

Modified Paths

Diff

Modified: trunk/JSTests/ChangeLog (270213 => 270214)


--- trunk/JSTests/ChangeLog	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/JSTests/ChangeLog	2020-11-28 04:31:41 UTC (rev 270214)
@@ -1,3 +1,13 @@
+2020-11-27  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Use ARM atomic ops in wasm
+        https://bugs.webkit.org/show_bug.cgi?id=219281
+
+        Reviewed by Filip Pizlo.
+
+        * wasm/threads-spec-tests/atomic-signed.wast.js:
+        * wasm/threads-spec-tests/resources/atomic-signed.wast:
+
 2020-11-26  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Add wasm atomics instructions

Modified: trunk/JSTests/wasm/threads-spec-tests/atomic-signed.wast.js (270213 => 270214)


--- trunk/JSTests/wasm/threads-spec-tests/atomic-signed.wast.js	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/JSTests/wasm/threads-spec-tests/atomic-signed.wast.js	2020-11-28 04:31:41 UTC (rev 270214)
@@ -641,65 +641,110 @@
 // atomic-signed.wast:387
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
 
+// atomic-signed.wast:389
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
+
+// atomic-signed.wast:390
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa0\x80\x80\x80\x00\x01\x02\x24\x31\x19\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x38\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa6\x80\x80\x80\x00\x01\xa0\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x42\x11\x10\x00\x01\x42\xf0\x01\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw8.cmpxchg_u", [0, int64("-1_085_102_592_571_150_096"), int64("17")]), int64("240"))
+
 // atomic-signed.wast:391
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
+
+// atomic-signed.wast:393
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:392
+// atomic-signed.wast:394
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa1\x80\x80\x80\x00\x01\x02\x24\x31\x1a\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x31\x36\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa8\x80\x80\x80\x00\x01\xa2\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x42\x91\x22\x10\x00\x01\x42\xf0\xe1\x03\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw16.cmpxchg_u", [0, int64("-1_085_102_592_571_150_096"), int64("4_369")]), int64("61_680"))
+
+// atomic-signed.wast:395
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
+
+// atomic-signed.wast:397
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
+
+// atomic-signed.wast:398
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa1\x80\x80\x80\x00\x01\x02\x24\x31\x1a\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x33\x32\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xad\x80\x80\x80\x00\x01\xa7\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x42\x91\xa2\xc4\x88\x01\x10\x00\x01\x42\xf0\xe1\xc3\x87\x0f\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw32.cmpxchg_u", [0, int64("-1_085_102_592_571_150_096"), int64("286_331_153")]), int64("4_042_322_160"))
+
+// atomic-signed.wast:399
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
+
+// atomic-signed.wast:401
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
+
+// atomic-signed.wast:402
+assert_return(() => call($1, "i32.atomic.rmw8.cmpxchg_u", [0, -252_645_136, 17]), 240);
+
+// atomic-signed.wast:403
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
+
+// atomic-signed.wast:405
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
+
+// atomic-signed.wast:406
+assert_return(() => call($1, "i32.atomic.rmw16.cmpxchg_u", [0, -252_645_136, 4_369]), 61_680);
+
+// atomic-signed.wast:407
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_096"))
+
+// atomic-signed.wast:411
+run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
+
+// atomic-signed.wast:412
 assert_return(() => call($1, "i32.atomic.rmw.cmpxchg", [0, -252_645_136, -231_451_016]), -252_645_136);
 
-// atomic-signed.wast:393
+// atomic-signed.wast:413
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xf8\xac\xd1\x91\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_549_955_976"))
 
-// atomic-signed.wast:395
+// atomic-signed.wast:415
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:396
+// atomic-signed.wast:416
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\x9d\x80\x80\x80\x00\x01\x02\x24\x31\x16\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x2e\x63\x6d\x70\x78\x63\x68\x67\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xb5\x80\x80\x80\x00\x01\xaf\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x42\x82\x84\x88\x90\x90\xa0\xc0\x80\x71\x10\x00\x01\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw.cmpxchg", [0, int64("-1_085_102_592_571_150_096"), int64("-1_080_581_331_751_927_294")]), int64("-1_085_102_592_571_150_096"))
 
-// atomic-signed.wast:397
+// atomic-signed.wast:417
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\x82\x84\x88\x90\x90\xa0\xc0\x80\x71\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_080_581_331_751_927_294"))
 
-// atomic-signed.wast:399
+// atomic-signed.wast:419
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:400
+// atomic-signed.wast:420
 assert_return(() => call($1, "i32.atomic.rmw8.cmpxchg_u", [0, 240, -16_843_010]), 240);
 
-// atomic-signed.wast:401
+// atomic-signed.wast:421
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xfe\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_082"))
 
-// atomic-signed.wast:403
+// atomic-signed.wast:423
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:404
+// atomic-signed.wast:424
 assert_return(() => call($1, "i32.atomic.rmw16.cmpxchg_u", [0, 61_680, -16_843_010]), 61_680);
 
-// atomic-signed.wast:405
+// atomic-signed.wast:425
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xfe\xfd\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_146_498"))
 
-// atomic-signed.wast:407
+// atomic-signed.wast:427
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:408
+// atomic-signed.wast:428
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa0\x80\x80\x80\x00\x01\x02\x24\x31\x19\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x38\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa7\x80\x80\x80\x00\x01\xa1\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\x01\x42\xfe\xfd\xfb\xf7\xef\xdf\xbf\xff\x7e\x10\x00\x01\x42\xf0\x01\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw8.cmpxchg_u", [0, int64("240"), int64("-72_340_172_838_076_674")]), int64("240"))
 
-// atomic-signed.wast:409
+// atomic-signed.wast:429
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xfe\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_150_082"))
 
-// atomic-signed.wast:411
+// atomic-signed.wast:431
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:412
+// atomic-signed.wast:432
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa1\x80\x80\x80\x00\x01\x02\x24\x31\x1a\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x31\x36\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa9\x80\x80\x80\x00\x01\xa3\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\x03\x42\xfe\xfd\xfb\xf7\xef\xdf\xbf\xff\x7e\x10\x00\x01\x42\xf0\xe1\x03\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw16.cmpxchg_u", [0, int64("61_680"), int64("-72_340_172_838_076_674")]), int64("61_680"))
 
-// atomic-signed.wast:413
+// atomic-signed.wast:433
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xfe\xfd\xc3\x87\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_571_146_498"))
 
-// atomic-signed.wast:415
+// atomic-signed.wast:435
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x88\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7e\x00\x02\x8b\x80\x80\x80\x00\x01\x02\x24\x31\x04\x69\x6e\x69\x74\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\x99\x80\x80\x80\x00\x01\x93\x80\x80\x80\x00\x00\x02\x40\x42\xf0\xe1\xc3\x87\x8f\x9e\xbc\xf8\x70\x10\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // run(() => call($1, "init", [int64("-1_085_102_592_571_150_096")]))
 
-// atomic-signed.wast:416
+// atomic-signed.wast:436
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8b\x80\x80\x80\x00\x02\x60\x00\x00\x60\x03\x7f\x7e\x7e\x01\x7e\x02\xa1\x80\x80\x80\x00\x01\x02\x24\x31\x1a\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x72\x6d\x77\x33\x32\x2e\x63\x6d\x70\x78\x63\x68\x67\x5f\x75\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xad\x80\x80\x80\x00\x01\xa7\x80\x80\x80\x00\x00\x02\x40\x41\x00\x42\xf0\xe1\xc3\x87\x0f\x42\xfe\xfd\xfb\xf7\xef\xdf\xbf\xff\x7e\x10\x00\x01\x42\xf0\xe1\xc3\x87\x0f\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.rmw32.cmpxchg_u", [0, int64("4_042_322_160"), int64("-72_340_172_838_076_674")]), int64("4_042_322_160"))
 
-// atomic-signed.wast:417
+// atomic-signed.wast:437
 run(() => call(instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x89\x80\x80\x80\x00\x02\x60\x00\x00\x60\x01\x7f\x01\x7e\x02\x96\x80\x80\x80\x00\x01\x02\x24\x31\x0f\x69\x36\x34\x2e\x61\x74\x6f\x6d\x69\x63\x2e\x6c\x6f\x61\x64\x00\x01\x03\x82\x80\x80\x80\x00\x01\x00\x07\x87\x80\x80\x80\x00\x01\x03\x72\x75\x6e\x00\x01\x0a\xa1\x80\x80\x80\x00\x01\x9b\x80\x80\x80\x00\x00\x02\x40\x41\x00\x10\x00\x01\x42\xfe\xfd\xfb\xf7\x8f\x9e\xbc\xf8\x70\x01\x51\x45\x0d\x00\x0f\x0b\x00\x0b", exports("$1", $1)),  "run", []));  // assert_return(() => call($1, "i64.atomic.load", [0]), int64("-1_085_102_592_335_347_970"))

Modified: trunk/JSTests/wasm/threads-spec-tests/resources/atomic-signed.wast (270213 => 270214)


--- trunk/JSTests/wasm/threads-spec-tests/resources/atomic-signed.wast	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/JSTests/wasm/threads-spec-tests/resources/atomic-signed.wast	2020-11-28 04:31:41 UTC (rev 270214)
@@ -386,6 +386,26 @@
 (assert_return (invoke "i64.atomic.rmw32.cmpxchg_u" (i32.const 0) (i64.const 0) (i64.const 0x00000001f0f0f0f0)) (i64.const 0xf0f0f0f0))
 (assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
 
+(invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))
+(assert_return (invoke "i64.atomic.rmw8.cmpxchg_u" (i32.const 0) (i64.const 0xf0f0f0f0f0f0f0f0) (i64.const 0x0000000000000011)) (i64.const 0xf0))
+(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
+
+(invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))
+(assert_return (invoke "i64.atomic.rmw16.cmpxchg_u" (i32.const 0) (i64.const 0xf0f0f0f0f0f0f0f0) (i64.const 0x0000000000001111)) (i64.const 0xf0f0))
+(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
+
+(invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))
+(assert_return (invoke "i64.atomic.rmw32.cmpxchg_u" (i32.const 0) (i64.const 0xf0f0f0f0f0f0f0f0) (i64.const 0x0000000011111111)) (i64.const 0xf0f0f0f0))
+(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
+
+(invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))
+(assert_return (invoke "i32.atomic.rmw8.cmpxchg_u" (i32.const 0) (i32.const 0xf0f0f0f0) (i32.const 0x00000011)) (i32.const 0xf0))
+(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
+
+(invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))
+(assert_return (invoke "i32.atomic.rmw16.cmpxchg_u" (i32.const 0) (i32.const 0xf0f0f0f0) (i32.const 0x00001111)) (i32.const 0xf0f0))
+(assert_return (invoke "i64.atomic.load" (i32.const 0)) (i64.const 0xf0f0f0f0f0f0f0f0))
+
 ;; *.atomic.rmw*.cmpxchg (compare true)
 
 (invoke "init" (i64.const 0xf0f0f0f0f0f0f0f0))

Modified: trunk/Source/_javascript_Core/ChangeLog (270213 => 270214)


--- trunk/Source/_javascript_Core/ChangeLog	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-11-28 04:31:41 UTC (rev 270214)
@@ -1,3 +1,93 @@
+2020-11-27  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Use ARM atomic ops in wasm
+        https://bugs.webkit.org/show_bug.cgi?id=219281
+
+        Reviewed by Filip Pizlo.
+
+        This patch uses ARM LSE Atomic instructions in wasm atomic operations. This includes support in MacroAssembler, offlineasm, Air and B3,
+        so that FTL atomic operations automatically leverage ARM LSE atomic instructions too. Later we can extend DFG JIT to use it too.
+
+        One interesting thing is that this includes a fix for cmpxchg wasm operation implementations. Unfortunately, current wasm cmpxchg ops
+        are not the same to ARM cas / X86 cmpxchg. For example, i64.atomic.rmw8.cmpxchg_u takes i64 expected value. And the spec requires that
+        we should perform `i64-expected-value <cmp> loaded-zero-extended-1byte-value`. For example, if the expected value is `0xffffffff_ffffff00`,
+        and the value stored in the memory is `0x00`, then the wasm op needs to fail since `0x00` is not `0xffffffff_ffffff00`. But x86 and ARM
+        cmpxchg / cas ops behave differently since it truncates expected value to 1byte when performing 1byte cmpxchg. So we need to have a check
+        which performs the value is within 1byte range in this operation.
+
+        * assembler/ARM64EAssembler.h:
+        (JSC::ARM64EAssembler::exoticAtomicLoadStore):
+        (JSC::ARM64EAssembler::exoticAtomicCAS):
+        (JSC::ARM64EAssembler::ldaddal):
+        (JSC::ARM64EAssembler::ldeoral):
+        (JSC::ARM64EAssembler::ldclral):
+        (JSC::ARM64EAssembler::ldsetal):
+        (JSC::ARM64EAssembler::swpal):
+        (JSC::ARM64EAssembler::casal):
+        * assembler/MacroAssemblerARM64E.h:
+        (JSC::MacroAssemblerARM64E::atomicXchgAdd8):
+        (JSC::MacroAssemblerARM64E::atomicXchgAdd16):
+        (JSC::MacroAssemblerARM64E::atomicXchgAdd32):
+        (JSC::MacroAssemblerARM64E::atomicXchgAdd64):
+        (JSC::MacroAssemblerARM64E::atomicXchgXor8):
+        (JSC::MacroAssemblerARM64E::atomicXchgXor16):
+        (JSC::MacroAssemblerARM64E::atomicXchgXor32):
+        (JSC::MacroAssemblerARM64E::atomicXchgXor64):
+        (JSC::MacroAssemblerARM64E::atomicXchgOr8):
+        (JSC::MacroAssemblerARM64E::atomicXchgOr16):
+        (JSC::MacroAssemblerARM64E::atomicXchgOr32):
+        (JSC::MacroAssemblerARM64E::atomicXchgOr64):
+        (JSC::MacroAssemblerARM64E::atomicXchgClear8):
+        (JSC::MacroAssemblerARM64E::atomicXchgClear16):
+        (JSC::MacroAssemblerARM64E::atomicXchgClear32):
+        (JSC::MacroAssemblerARM64E::atomicXchgClear64):
+        (JSC::MacroAssemblerARM64E::atomicXchg8):
+        (JSC::MacroAssemblerARM64E::atomicXchg16):
+        (JSC::MacroAssemblerARM64E::atomicXchg32):
+        (JSC::MacroAssemblerARM64E::atomicXchg64):
+        (JSC::MacroAssemblerARM64E::atomicStrongCAS8):
+        (JSC::MacroAssemblerARM64E::atomicStrongCAS16):
+        (JSC::MacroAssemblerARM64E::atomicStrongCAS32):
+        (JSC::MacroAssemblerARM64E::atomicStrongCAS64):
+        * b3/B3LowerMacros.cpp:
+        * b3/B3LowerToAir.cpp:
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/opcode_generator.rb:
+        * disassembler/ARM64/A64DOpcode.cpp:
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::format):
+        (JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::format):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::format):
+        * disassembler/ARM64/A64DOpcode.h:
+        (JSC::ARM64Disassembler::A64DOpcode::appendInstructionName):
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opName):
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::rs):
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opc):
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::ar):
+        (JSC::ARM64Disassembler::A64DOpcodeLoadAtomic::opNumber):
+        (JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::opName):
+        (JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::rs):
+        (JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::ar):
+        (JSC::ARM64Disassembler::A64DOpcodeSwapAtomic::opNumber):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::opName):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::rs):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::o1):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::l):
+        (JSC::ARM64Disassembler::A64DOpcodeCAS::opNumber):
+        * llint/WebAssembly.asm:
+        * offlineasm/arm64.rb:
+        * offlineasm/instructions.rb:
+        * offlineasm/x86.rb:
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::sanitizeAtomicResult):
+        (JSC::Wasm::AirIRGenerator::appendGeneralAtomic):
+        (JSC::Wasm::AirIRGenerator::appendStrongCAS):
+        (JSC::Wasm::AirIRGenerator::emitAtomicLoadOp):
+        (JSC::Wasm::AirIRGenerator::emitAtomicStoreOp):
+        (JSC::Wasm::AirIRGenerator::emitAtomicBinaryRMWOp):
+        (JSC::Wasm::AirIRGenerator::emitAtomicCompareExchange):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::emitAtomicCompareExchange):
+
 2020-11-26  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Add wasm atomics instructions

Modified: trunk/Source/_javascript_Core/assembler/ARM64EAssembler.h (270213 => 270214)


--- trunk/Source/_javascript_Core/assembler/ARM64EAssembler.h	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/assembler/ARM64EAssembler.h	2020-11-28 04:31:41 UTC (rev 270214)
@@ -31,6 +31,11 @@
 
 namespace JSC {
 
+#define CHECK_MEMOPSIZE_OF(size) ASSERT(size == 8 || size == 16 || size == 32 || size == 64 || size == 128);
+#define MEMOPSIZE_OF(datasize) ((datasize == 8 || datasize == 128) ? MemOpSize_8_or_128 : (datasize == 16) ? MemOpSize_16 : (datasize == 32) ? MemOpSize_32 : MemOpSize_64)
+#define CHECK_MEMOPSIZE() CHECK_MEMOPSIZE_OF(datasize)
+#define MEMOPSIZE MEMOPSIZE_OF(datasize)
+
 class ARM64EAssembler : public ARM64Assembler {
 protected:
     static constexpr RegisterID unusedID = static_cast<RegisterID>(0b11111);
@@ -279,6 +284,72 @@
     ALWAYS_INLINE void eretaa() { insn(encodeGroup4(Group4Op::ERETAA)); }
     ALWAYS_INLINE void eretab() { insn(encodeGroup4(Group4Op::ERETAB)); }
 
+    enum ExoticAtomicLoadStoreOp {
+        ExoticAtomicLoadStoreOp_Add   = 0b0'000'00,
+        ExoticAtomicLoadStoreOp_Clear = 0b0'001'00,
+        ExoticAtomicLoadStoreOp_Xor   = 0b0'010'00,
+        ExoticAtomicLoadStoreOp_Set   = 0b0'011'00,
+        ExoticAtomicLoadStoreOp_Swap  = 0b1'000'00,
+    };
+
+    static int exoticAtomicLoadStore(MemOpSize size, ExoticAtomicLoadStoreOp op, ExoticLoadFence loadFence, ExoticStoreFence storeFence, RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        ASSERT((rs & 0b11111) == rs);
+        ASSERT((rn & 0b11111) == rn);
+        ASSERT((rt & 0b11111) == rt);
+        return 0b00111000'00100000'00000000'00000000 | size << 30 | loadFence << 23 | storeFence << 22 | rs << 16 | op << 10 | rn << 5 | rt;
+    }
+
+    static int exoticAtomicCAS(MemOpSize size, ExoticLoadFence loadFence, ExoticStoreFence storeFence, RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        ASSERT((rs & 0b11111) == rs);
+        ASSERT((rn & 0b11111) == rn);
+        ASSERT((rt & 0b11111) == rt);
+        return 0b00001000'10100000'01111100'00000000 | size << 30 | storeFence << 22 | rs << 16 | loadFence << 15 | rn << 5 | rt;
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void ldaddal(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicLoadStore(MEMOPSIZE, ExoticAtomicLoadStoreOp_Add, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void ldeoral(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicLoadStore(MEMOPSIZE, ExoticAtomicLoadStoreOp_Xor, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void ldclral(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicLoadStore(MEMOPSIZE, ExoticAtomicLoadStoreOp_Clear, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void ldsetal(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicLoadStore(MEMOPSIZE, ExoticAtomicLoadStoreOp_Set, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void swpal(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicLoadStore(MEMOPSIZE, ExoticAtomicLoadStoreOp_Swap, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
+    template<int datasize>
+    ALWAYS_INLINE void casal(RegisterID rs, RegisterID rt, RegisterID rn)
+    {
+        CHECK_MEMOPSIZE();
+        insn(exoticAtomicCAS(MEMOPSIZE, ExoticLoadFence_Acquire, ExoticStoreFence_Release, rs, rt, rn));
+    }
+
     // Overload of the ARM64 equivalents.
 
     // Needed because we need to call our overloaded linkPointer below.
@@ -371,6 +442,11 @@
     static constexpr ptrdiff_t NUMBER_OF_ADDRESS_ENCODING_INSTRUCTIONS = MAX_POINTER_BITS / BITS_ENCODEABLE_PER_INSTRUCTION;
 };
 
+#undef CHECK_MEMOPSIZE_OF
+#undef MEMOPSIZE_OF
+#undef CHECK_MEMOPSIZE
+#undef MEMOPSIZE
+
 } // namespace JSC
 
 #endif // ENABLE(ASSEMBLER) && CPU(ARM64E)

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h (270213 => 270214)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h	2020-11-28 04:31:41 UTC (rev 270214)
@@ -334,6 +334,126 @@
 #endif
             m_assembler.retab();
     }
+
+    void atomicXchgAdd8(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldaddal<8>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgAdd16(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldaddal<16>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgAdd32(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldaddal<32>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgAdd64(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldaddal<64>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgXor8(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldeoral<8>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgXor16(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldeoral<16>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgXor32(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldeoral<32>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgXor64(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldeoral<64>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgOr8(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldsetal<8>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgOr16(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldsetal<16>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgOr32(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldsetal<32>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgOr64(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldsetal<64>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgClear8(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldclral<8>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgClear16(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldclral<16>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgClear32(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldclral<32>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchgClear64(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.ldclral<64>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchg8(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.swpal<8>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchg16(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.swpal<16>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchg32(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.swpal<32>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicXchg64(RegisterID src, ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.swpal<64>(src, dest, extractSimpleAddress(address));
+    }
+
+    void atomicStrongCAS8(RegisterID expectedAndResult, RegisterID newValue, ImplicitAddress address)
+    {
+        m_assembler.casal<8>(expectedAndResult, newValue, extractSimpleAddress(address));
+    }
+
+    void atomicStrongCAS16(RegisterID expectedAndResult, RegisterID newValue, ImplicitAddress address)
+    {
+        m_assembler.casal<16>(expectedAndResult, newValue, extractSimpleAddress(address));
+    }
+
+    void atomicStrongCAS32(RegisterID expectedAndResult, RegisterID newValue, ImplicitAddress address)
+    {
+        m_assembler.casal<32>(expectedAndResult, newValue, extractSimpleAddress(address));
+    }
+
+    void atomicStrongCAS64(RegisterID expectedAndResult, RegisterID newValue, ImplicitAddress address)
+    {
+        m_assembler.casal<64>(expectedAndResult, newValue, extractSimpleAddress(address));
+    }
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp (270213 => 270214)


--- trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/b3/B3LowerMacros.cpp	2020-11-28 04:31:41 UTC (rev 270214)
@@ -306,6 +306,14 @@
                     if (exempt)
                         break;
                 }
+
+                if (isARM64E()) {
+                    if (m_value->opcode() == AtomicXchgSub) {
+                        m_value->setOpcodeUnsafely(AtomicXchgAdd);
+                        m_value->child(0) = m_insertionSet.insert<Value>(
+                            m_index, Neg, m_origin, m_value->child(0));
+                    }
+                }
                 
                 AtomicValue* atomic = m_value->as<AtomicValue>();
                 Width width = atomic->accessWidth();

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (270213 => 270214)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2020-11-28 04:31:41 UTC (rev 270214)
@@ -2257,6 +2257,19 @@
                 appendTrapping(OPCODE_FOR_WIDTH(AtomicStrongCAS, width), Arg::statusCond(invert ? MacroAssembler::Failure : MacroAssembler::Success), m_eax, tmp(atomic->child(1)), address, boolResultTmp);
             return;
         }
+
+        if (isARM64E()) {
+            append(relaxedMoveForType(atomic->accessType()), expectedValueTmp, valueResultTmp);
+            appendTrapping(OPCODE_FOR_WIDTH(AtomicStrongCAS, width), valueResultTmp, newValueTmp, address);
+            if (returnsOldValue)
+                return;
+            if (isBranch) {
+                m_blockToBlock[m_block]->setSuccessors(success, failure);
+                return;
+            }
+            append(OPCODE_FOR_CANONICAL_WIDTH(Compare, width), Arg::relCond(invert ? MacroAssembler::NotEqual : MacroAssembler::Equal), valueResultTmp, expectedValueTmp, boolResultTmp);
+            return;
+        }
         
         RELEASE_ASSERT(isARM64());
         // We wish to emit:
@@ -3592,6 +3605,11 @@
             
             Arg address = addr(atomic);
             Air::Opcode opcode = OPCODE_FOR_WIDTH(AtomicXchgAdd, atomic->accessWidth());
+            if (isValidForm(opcode, Arg::Tmp, address.kind(), Arg::Tmp)) {
+                appendTrapping(opcode, tmp(atomic->child(0)), address, tmp(atomic));
+                return;
+            }
+
             if (isValidForm(opcode, Arg::Tmp, address.kind())) {
                 append(relaxedMoveForType(atomic->type()), tmp(atomic->child(0)), tmp(atomic));
                 appendTrapping(opcode, tmp(atomic), address);
@@ -3615,6 +3633,16 @@
             AtomicValue* atomic = m_value->as<AtomicValue>();
             if (appendVoidAtomic(OPCODE_FOR_WIDTH(AtomicAnd, atomic->accessWidth())))
                 return;
+
+            if (isARM64E()) {
+                Arg address = addr(atomic);
+                Air::Opcode opcode = OPCODE_FOR_WIDTH(AtomicXchgClear, atomic->accessWidth());
+                if (isValidForm(opcode, Arg::Tmp, address.kind(), Arg::Tmp)) {
+                    append(OPCODE_FOR_CANONICAL_WIDTH(Not, atomic->accessWidth()), tmp(atomic->child(0)), tmp(atomic));
+                    appendTrapping(opcode, tmp(atomic), address, tmp(atomic));
+                    return;
+                }
+            }
             
             appendGeneralAtomic(OPCODE_FOR_CANONICAL_WIDTH(And, atomic->accessWidth()), Commutative);
             return;
@@ -3624,6 +3652,13 @@
             AtomicValue* atomic = m_value->as<AtomicValue>();
             if (appendVoidAtomic(OPCODE_FOR_WIDTH(AtomicOr, atomic->accessWidth())))
                 return;
+
+            Arg address = addr(atomic);
+            Air::Opcode opcode = OPCODE_FOR_WIDTH(AtomicXchgOr, atomic->accessWidth());
+            if (isValidForm(opcode, Arg::Tmp, address.kind(), Arg::Tmp)) {
+                appendTrapping(opcode, tmp(atomic->child(0)), address, tmp(atomic));
+                return;
+            }
             
             appendGeneralAtomic(OPCODE_FOR_CANONICAL_WIDTH(Or, atomic->accessWidth()), Commutative);
             return;
@@ -3633,6 +3668,13 @@
             AtomicValue* atomic = m_value->as<AtomicValue>();
             if (appendVoidAtomic(OPCODE_FOR_WIDTH(AtomicXor, atomic->accessWidth())))
                 return;
+
+            Arg address = addr(atomic);
+            Air::Opcode opcode = OPCODE_FOR_WIDTH(AtomicXchgXor, atomic->accessWidth());
+            if (isValidForm(opcode, Arg::Tmp, address.kind(), Arg::Tmp)) {
+                appendTrapping(opcode, tmp(atomic->child(0)), address, tmp(atomic));
+                return;
+            }
             
             appendGeneralAtomic(OPCODE_FOR_CANONICAL_WIDTH(Xor, atomic->accessWidth()), Commutative);
             return;
@@ -3643,6 +3685,11 @@
             
             Arg address = addr(atomic);
             Air::Opcode opcode = OPCODE_FOR_WIDTH(AtomicXchg, atomic->accessWidth());
+            if (isValidForm(opcode, Arg::Tmp, address.kind(), Arg::Tmp)) {
+                appendTrapping(opcode, tmp(atomic->child(0)), address, tmp(atomic));
+                return;
+            }
+
             if (isValidForm(opcode, Arg::Tmp, address.kind())) {
                 append(relaxedMoveForType(atomic->type()), tmp(atomic->child(0)), tmp(atomic));
                 appendTrapping(opcode, tmp(atomic), address);

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (270213 => 270214)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2020-11-28 04:31:41 UTC (rev 270214)
@@ -824,21 +824,25 @@
     StatusCond, Tmp*, Tmp, Addr, Tmp
     StatusCond, Tmp*, Tmp, Index, Tmp
 
-x86: AtomicStrongCAS8 UD:G:8, U:G:8, UD:G:8 /effects
-    Tmp*, Tmp, Addr
-    Tmp*, Tmp, Index
+x86 arm64e: AtomicStrongCAS8 UD:G:8, U:G:8, UD:G:8 /effects
+    x86: Tmp*, Tmp, Addr
+    x86: Tmp*, Tmp, Index
+    arm64e: Tmp, Tmp, SimpleAddr
 
-x86: AtomicStrongCAS16 UD:G:16, U:G:32, UD:G:16 /effects
-    Tmp*, Tmp, Addr
-    Tmp*, Tmp, Index
+x86 arm64e: AtomicStrongCAS16 UD:G:16, U:G:32, UD:G:16 /effects
+    x86: Tmp*, Tmp, Addr
+    x86: Tmp*, Tmp, Index
+    arm64e: Tmp, Tmp, SimpleAddr
 
-x86: AtomicStrongCAS32 UD:G:32, U:G:32, UD:G:32 /effects
-    Tmp*, Tmp, Addr
-    Tmp*, Tmp, Index
+x86 arm64e: AtomicStrongCAS32 UD:G:32, U:G:32, UD:G:32 /effects
+    x86: Tmp*, Tmp, Addr
+    x86: Tmp*, Tmp, Index
+    arm64e: Tmp, Tmp, SimpleAddr
 
-x86_64: AtomicStrongCAS64 UD:G:64, U:G:64, UD:G:64 /effects
-    Tmp*, Tmp, Addr
-    Tmp*, Tmp, Index
+x86_64 arm64e: AtomicStrongCAS64 UD:G:64, U:G:64, UD:G:64 /effects
+    x86_64: Tmp*, Tmp, Addr
+    x86_64: Tmp*, Tmp, Index
+    arm64e: Tmp, Tmp, SimpleAddr
 
 x86: BranchAtomicStrongCAS8 U:G:32, UD:G:8, U:G:8, UD:G:8 /branch /effects
     StatusCond, Tmp*, Tmp, Addr
@@ -1095,6 +1099,66 @@
 arm64: Depend64 U:G:64, ZD:G:64
     Tmp, Tmp
 
+arm64e: AtomicXchgAdd8 U:G:8, UD:G:8, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgAdd16 U:G:16, UD:G:16, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgAdd32 U:G:32, UD:G:32, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgAdd64 U:G:64, UD:G:64, ZD:G:64 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgOr8 U:G:8, UD:G:8, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgOr16 U:G:16, UD:G:16, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgOr32 U:G:32, UD:G:32, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgOr64 U:G:64, UD:G:64, ZD:G:64 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgClear8 U:G:8, UD:G:8, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgClear16 U:G:16, UD:G:16, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgClear32 U:G:32, UD:G:32, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgClear64 U:G:64, UD:G:64, ZD:G:64 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgXor8 U:G:8, UD:G:8, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgXor16 U:G:16, UD:G:16, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgXor32 U:G:32, UD:G:32, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchgXor64 U:G:64, UD:G:64, ZD:G:64 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchg8 U:G:8, UD:G:8, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchg16 U:G:16, UD:G:16, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchg32 U:G:32, UD:G:32, ZD:G:32 /effects
+    Tmp, SimpleAddr, Tmp
+
+arm64e: AtomicXchg64 U:G:64, UD:G:64, ZD:G:64 /effects
+    Tmp, SimpleAddr, Tmp
+
 Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
     RelCond, Tmp, Tmp, Tmp
     RelCond, Tmp, Imm, Tmp

Modified: trunk/Source/_javascript_Core/b3/air/opcode_generator.rb (270213 => 270214)


--- trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2020-11-28 04:31:41 UTC (rev 270214)
@@ -233,7 +233,7 @@
 end
 
 def isArch(token)
-    token =~ /\A((x86)|(x86_32)|(x86_64)|(arm)|(armv7)|(arm64)|(32)|(64))\Z/
+    token =~ /\A((x86)|(x86_32)|(x86_64)|(arm)|(armv7)|(arm64e)|(arm64)|(32)|(64))\Z/
 end
 
 def isWidth(token)
@@ -335,6 +335,8 @@
                 result << "ARMv7"
             when "arm64"
                 result << "ARM64"
+            when "arm64e"
+                result << "ARM64E"
             when "32"
                 result << "X86"
                 result << "ARMv7"

Modified: trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp (270213 => 270214)


--- trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp	2020-11-28 04:31:41 UTC (rev 270214)
@@ -65,6 +65,7 @@
 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
 
 static const OpcodeGroupInitializer opcodeGroupList[] = {
+    OPCODE_GROUP_ENTRY(0x08, A64DOpcodeCAS),
     OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair),
     OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreExclusive),
     OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair),
@@ -96,6 +97,8 @@
     OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate),
     OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset),
     OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreAuthenticated),
+    OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadAtomic),
+    OPCODE_GROUP_ENTRY(0x18, A64DOpcodeSwapAtomic),
     OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate),
     OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect),
     OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing1Source),
@@ -1255,6 +1258,86 @@
     return m_formatBuffer;
 }
 
+const char* const A64DOpcodeLoadAtomic::s_opNames[64] = {
+    "ldaddb", "ldaddlb", "ldaddab", "ldaddalb",
+    "ldaddh", "ldaddlh", "ldaddah", "ldaddalh",
+    "ldadd", "ldaddl", "ldadda", "ldaddal",
+    "ldadd", "ldaddl", "ldadda", "ldaddal",
+
+    "ldclrb", "ldclrlb", "ldclrab", "ldclralb",
+    "ldclrh", "ldclrlh", "ldclrah", "ldclralh",
+    "ldclr", "ldclrl", "ldclra", "ldclral",
+    "ldclr", "ldclrl", "ldclra", "ldclral",
+
+    "ldeorb", "ldeorlb", "ldeorab", "ldeoralb",
+    "ldeorh", "ldeorlh", "ldeorah", "ldeoralh",
+    "ldeor", "ldeorl", "ldeora", "ldeoral",
+    "ldeor", "ldeorl", "ldeora", "ldeoral",
+
+    "ldsetb", "ldsetlb", "ldsetab", "ldsetalb",
+    "ldseth", "ldsetlh", "ldsetah", "ldsetalh",
+    "ldset", "ldsetl", "ldseta", "ldsetal",
+    "ldset", "ldsetl", "ldseta", "ldsetal",
+};
+
+const char* A64DOpcodeLoadAtomic::format()
+{
+    const auto* name = opName();
+    if (!name)
+        return A64DOpcode::format();
+    appendInstructionName(name);
+    appendSPOrRegisterName(rs(), is64Bit());
+    appendSeparator();
+    appendSPOrRegisterName(rt(), is64Bit());
+    appendSeparator();
+    appendCharacter('[');
+    appendSPOrRegisterName(rn(), is64Bit());
+    appendCharacter(']');
+    return m_formatBuffer;
+}
+
+const char* const A64DOpcodeSwapAtomic::s_opNames[16] = {
+    "swpb", "swplb", "swpab", "swpalb",
+    "swph", "swplh", "swpah", "swpalh",
+    "swp", "swpl", "swpa", "swpal",
+    "swp", "swpl", "swpa", "swpal",
+};
+
+const char* A64DOpcodeSwapAtomic::format()
+{
+    const auto* name = opName();
+    appendInstructionName(name);
+    appendSPOrRegisterName(rs(), is64Bit());
+    appendSeparator();
+    appendSPOrRegisterName(rt(), is64Bit());
+    appendSeparator();
+    appendCharacter('[');
+    appendSPOrRegisterName(rn(), is64Bit());
+    appendCharacter(']');
+    return m_formatBuffer;
+}
+
+const char* const A64DOpcodeCAS::s_opNames[16] = {
+    "casb", "caslb", "casab", "casalb",
+    "cash", "caslh", "casah", "casalh",
+    "cas", "casl", "casa", "casal",
+    "cas", "casl", "casa", "casal",
+};
+
+const char* A64DOpcodeCAS::format()
+{
+    const auto* name = opName();
+    appendInstructionName(name);
+    appendSPOrRegisterName(rs(), is64Bit());
+    appendSeparator();
+    appendSPOrRegisterName(rt(), is64Bit());
+    appendSeparator();
+    appendCharacter('[');
+    appendSPOrRegisterName(rn(), is64Bit());
+    appendCharacter(']');
+    return m_formatBuffer;
+}
+
 const char* A64DOpcodeLoadStoreRegisterPair::opName()
 {
     if (!vBit() && lBit() && size() == 0x1)

Modified: trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h (270213 => 270214)


--- trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h	2020-11-28 04:31:41 UTC (rev 270214)
@@ -116,7 +116,7 @@
 
     void appendInstructionName(const char* instructionName)
     {
-        bufferPrintf("   %-8.8s", instructionName);
+        bufferPrintf("   %-9.9s", instructionName);
     }
 
     void appendRegisterName(unsigned registerNumber, bool is64Bit = true);
@@ -711,6 +711,80 @@
     
 };
 
+class A64DOpcodeLoadAtomic : public A64DOpcodeLoadStore {
+private:
+    static const char* const s_opNames[64];
+
+protected:
+    const char* opName()
+    {
+        unsigned number = opNumber();
+        if (number < 64)
+            return s_opNames[number];
+        return nullptr;
+    }
+
+public:
+    static constexpr uint32_t mask    = 0b00111111'00100000'10001100'00000000U;
+    static constexpr uint32_t pattern = 0b00111000'00100000'00000000'00000000U;
+
+    DEFINE_STATIC_FORMAT(A64DOpcodeLoadAtomic, thisObj);
+
+    const char* format();
+
+    unsigned rs() { return rm(); }
+    unsigned opc() { return (m_opcode >> 12) & 0b111; }
+    unsigned ar() { return (m_opcode >> 22) & 0b11; }
+    unsigned opNumber() { return (opc() << 4) | (size() << 2) | ar(); }
+};
+
+class A64DOpcodeSwapAtomic : public A64DOpcodeLoadStore {
+private:
+    static const char* const s_opNames[16];
+
+protected:
+    const char* opName()
+    {
+        return s_opNames[opNumber()];
+    }
+
+public:
+    static constexpr uint32_t mask    = 0b00111111'00100000'11111100'00000000U;
+    static constexpr uint32_t pattern = 0b00111000'00100000'10000000'00000000U;
+
+    DEFINE_STATIC_FORMAT(A64DOpcodeSwapAtomic, thisObj);
+
+    const char* format();
+
+    unsigned rs() { return rm(); }
+    unsigned ar() { return (m_opcode >> 22) & 0b11; }
+    unsigned opNumber() { return (size() << 2) | ar(); }
+};
+
+class A64DOpcodeCAS : public A64DOpcodeLoadStore {
+private:
+    static const char* const s_opNames[16];
+
+protected:
+    const char* opName()
+    {
+        return s_opNames[opNumber()];
+    }
+
+public:
+    static constexpr uint32_t mask    = 0b00111111'10100000'01111100'00000000U;
+    static constexpr uint32_t pattern = 0b00001000'10100000'01111100'00000000U;
+
+    DEFINE_STATIC_FORMAT(A64DOpcodeCAS, thisObj);
+
+    const char* format();
+
+    unsigned rs() { return rm(); }
+    unsigned o1() { return (m_opcode >> 15) & 0x1; }
+    unsigned l() { return (m_opcode >> 22) & 0x1; }
+    unsigned opNumber() { return (size() << 2) | (l() << 1) | o1(); }
+};
+
 class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
 public:
     static constexpr uint32_t mask = 0x3a000000;

Modified: trunk/Source/_javascript_Core/llint/WebAssembly.asm (270213 => 270214)


--- trunk/Source/_javascript_Core/llint/WebAssembly.asm	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/llint/WebAssembly.asm	2020-11-28 04:31:41 UTC (rev 270214)
@@ -2194,7 +2194,6 @@
         mloadq(ctx, m_value, t0)
         emitCheckAndPreparePointerAddingOffsetWithAlignmentCheck(ctx, t3, t1, 4)
         fni(t0, [t3], t2, t5, t1)
-        zxi2q t0, t0
         assert(macro(ok) bqbeq t0, 0xffffffff, .ok end)
         returnq(ctx, t0)
     end)
@@ -2317,6 +2316,61 @@
         macro(t5GPR, t2GPR)
             xorq t5GPR, t2GPR
         end)
+elsif ARM64E
+    wasmAtomicBinaryRMWOps(_add, Add,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgaddb t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgaddh t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgaddi t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgaddq t0GPR, mem, t0GPR end)
+    wasmAtomicBinaryRMWOps(_sub, Sub,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            negq t0GPR
+            atomicxchgaddb t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            negq t0GPR
+            atomicxchgaddh t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            negq t0GPR
+            atomicxchgaddi t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            negq t0GPR
+            atomicxchgaddq t0GPR, mem, t0GPR
+        end)
+    wasmAtomicBinaryRMWOps(_and, And,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            notq t0GPR
+            atomicxchgclearb t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            notq t0GPR
+            atomicxchgclearh t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            notq t0GPR
+            atomicxchgcleari t0GPR, mem, t0GPR
+        end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR)
+            notq t0GPR
+            atomicxchgclearq t0GPR, mem, t0GPR
+        end)
+    wasmAtomicBinaryRMWOps(_or, Or,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgorb t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgorh t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgori t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgorq t0GPR, mem, t0GPR end)
+    wasmAtomicBinaryRMWOps(_xor, Xor,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgxorb t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgxorh t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgxori t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgxorq t0GPR, mem, t0GPR end)
+    wasmAtomicBinaryRMWOps(_xchg, Xchg,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgb t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgh t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgi t0GPR, mem, t0GPR end,
+        macro(t0GPR, mem, t2GPR, t5GPR, t1GPR) atomicxchgq t0GPR, mem, t0GPR end)
 else
     wasmAtomicBinaryRMWOpsWithWeakCAS(_add, Add,
         macro(t0GPR, t1GPR, t2GPR)
@@ -2392,7 +2446,6 @@
         mloadq(ctx, m_value, t2)
         emitCheckAndPreparePointerAddingOffsetWithAlignmentCheck(ctx, t3, t1, 4)
         fni(t0, t2, [t3], t5, t1)
-        zxi2q t0, t0
         assert(macro(ok) bqbeq t0, 0xffffffff, .ok end)
         returnq(ctx, t0)
     end)
@@ -2410,12 +2463,17 @@
 # t0GPR => expected, t2GPR => value, mem => memory reference
 wasmAtomicCompareExchangeOps(_cmpxchg, Cmpxchg,
     macro(t0GPR, t2GPR, mem, t5GPR, t1GPR)
-        if X86_64
+        if X86_64 or ARM64E
+            bqa t0GPR , 0xff, .fail
             atomicweakcasb t0GPR, t2GPR, mem
+            jmp .done
+        .fail:
+            atomicloadb mem, t0GPR
+        .done:
         else
         .loop:
             loadlinkacqb mem, t1GPR
-            bineq t0GPR, t1GPR, .fail
+            bqneq t0GPR, t1GPR, .fail
             storecondrelb t5GPR, t2GPR, mem
             bieq t5GPR, 0, .done
             jmp .loop
@@ -2428,12 +2486,17 @@
         end
     end,
     macro(t0GPR, t2GPR, mem, t5GPR, t1GPR)
-        if X86_64
+        if X86_64 or ARM64E
+            bqa t0GPR, 0xffff, .fail
             atomicweakcash t0GPR, t2GPR, mem
+            jmp .done
+        .fail:
+            atomicloadh mem, t0GPR
+        .done:
         else
         .loop:
             loadlinkacqh mem, t1GPR
-            bineq t0GPR, t1GPR, .fail
+            bqneq t0GPR, t1GPR, .fail
             storecondrelh t5GPR, t2GPR, mem
             bieq t5GPR, 0, .done
             jmp .loop
@@ -2446,12 +2509,17 @@
         end
     end,
     macro(t0GPR, t2GPR, mem, t5GPR, t1GPR)
-        if X86_64
+        if X86_64 or ARM64E
+            bqa t0GPR, 0xffffffff, .fail
             atomicweakcasi t0GPR, t2GPR, mem
+            jmp .done
+        .fail:
+            atomicloadi mem, t0GPR
+        .done:
         else
         .loop:
             loadlinkacqi mem, t1GPR
-            bineq t0GPR, t1GPR, .fail
+            bqneq t0GPR, t1GPR, .fail
             storecondreli t5GPR, t2GPR, mem
             bieq t5GPR, 0, .done
             jmp .loop
@@ -2464,7 +2532,7 @@
         end
     end,
     macro(t0GPR, t2GPR, mem, t5GPR, t1GPR)
-        if X86_64
+        if X86_64 or ARM64E
             atomicweakcasq t0GPR, t2GPR, mem
         else
         .loop:

Modified: trunk/Source/_javascript_Core/offlineasm/arm64.rb (270213 => 270214)


--- trunk/Source/_javascript_Core/offlineasm/arm64.rb	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/offlineasm/arm64.rb	2020-11-28 04:31:41 UTC (rev 270214)
@@ -230,6 +230,11 @@
         raise "Invalid offset #{offset.value} at #{codeOriginString}" if offset.value < -255 or offset.value > 4095
         "[#{base.arm64Operand(:quad)}, \##{offset.value}]"
     end
+
+    def arm64SimpleAddressOperand(kind)
+        raise "Invalid offset #{offset.value} at #{codeOriginString}" if offset.value != 0
+        "[#{base.arm64Operand(:quad)}]"
+    end
     
     def arm64EmitLea(destination, kind)
         $asm.puts "add #{destination.arm64Operand(kind)}, #{base.arm64Operand(kind)}, \##{offset.value}"
@@ -372,18 +377,19 @@
         result = riscLowerMalformedAddresses(result) {
             | node, address |
             case node.opcode
-            when "loadb", "loadbsi", "loadbsq", "storeb", /^bb/, /^btb/, /^cb/, /^tb/, "loadlinkacqb", "storecondrelb"
+            when "loadb", "loadbsi", "loadbsq", "storeb", /^bb/, /^btb/, /^cb/, /^tb/, "loadlinkacqb", "storecondrelb", /^atomic[a-z]+b$/
                 size = 1
-            when "loadh", "loadhsi", "loadhsq", "orh", "storeh", "loadlinkacqh", "storecondrelh"
+            when "loadh", "loadhsi", "loadhsq", "orh", "storeh", "loadlinkacqh", "storecondrelh", /^atomic[a-z]+h$/
                 size = 2
             when "loadi", "loadis", "storei", "addi", "andi", "lshifti", "muli", "negi",
                 "noti", "ori", "rshifti", "urshifti", "subi", "xori", /^bi/, /^bti/,
-                /^ci/, /^ti/, "addis", "subis", "mulis", "smulli", "leai", "loadf", "storef", "loadlinkacqi", "storecondreli"
+                /^ci/, /^ti/, "addis", "subis", "mulis", "smulli", "leai", "loadf", "storef", "loadlinkacqi", "storecondreli",
+                /^atomic[a-z]+i$/
                 size = 4
             when "loadp", "storep", "loadq", "storeq", "loadd", "stored", "lshiftp", "lshiftq", "negp", "negq", "rshiftp", "rshiftq",
                 "urshiftp", "urshiftq", "addp", "addq", "mulp", "mulq", "andp", "andq", "orp", "orq", "subp", "subq", "xorp", "xorq", "addd",
                 "divd", "subd", "muld", "sqrtd", /^bp/, /^bq/, /^btp/, /^btq/, /^cp/, /^cq/, /^tp/, /^tq/, /^bd/,
-                "jmp", "call", "leap", "leaq", "loadlinkacqq", "storecondrelq"
+                "jmp", "call", "leap", "leaq", "loadlinkacqq", "storecondrelq", /^atomic[a-z]+q$/
                 size = $currentSettings["ADDRESS64"] ? 8 : 4
             else
                 raise "Bad instruction #{node.opcode} for heap access at #{node.codeOriginString}: #{node.dump}"
@@ -443,6 +449,8 @@
                 not (address.is_a? Address and address.offset.value < 0)
             when /^lea/
                 true
+            when /^atomic/
+                true
             else
                 raise "Bad instruction #{node.opcode} for heap access at #{node.codeOriginString}"
             end
@@ -765,6 +773,8 @@
             $asm.puts "sub #{operands[0].arm64Operand(:ptr)}, #{arm64GPRName('xzr', :ptr)}, #{operands[0].arm64Operand(:ptr)}"
         when "negq"
             $asm.puts "sub #{operands[0].arm64Operand(:quad)}, xzr, #{operands[0].arm64Operand(:quad)}"
+        when "notq"
+            $asm.puts "mvn #{operands[0].arm64Operand(:quad)}, #{operands[0].arm64Operand(:quad)}"
         when "loadi"
             emitARM64Access("ldr", "ldur", operands[1], operands[0], :word)
         when "loadis"
@@ -1327,6 +1337,62 @@
             $asm.puts "stlxr #{operands[0].arm64Operand(:word)}, #{operands[1].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}"
         when "storecondrelq"
             $asm.puts "stlxr #{operands[0].arm64Operand(:word)}, #{operands[1].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}"
+        when "atomicxchgaddb"
+            $asm.puts "ldaddalb #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgaddh"
+            $asm.puts "ldaddalh #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgaddi"
+            $asm.puts "ldaddal #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgaddq"
+            $asm.puts "ldaddal #{operands[0].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}, #{operands[1].arm64SimpleAddressOperand(:quad)}"
+        when "atomicxchgclearb"
+            $asm.puts "ldclralb #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgclearh"
+            $asm.puts "ldclralh #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgcleari"
+            $asm.puts "ldclral #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgclearq"
+            $asm.puts "ldclral #{operands[0].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}, #{operands[1].arm64SimpleAddressOperand(:quad)}"
+        when "atomicxchgorb"
+            $asm.puts "ldsetalb #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgorh"
+            $asm.puts "ldsetalh #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgori"
+            $asm.puts "ldsetal #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgorq"
+            $asm.puts "ldsetal #{operands[0].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}, #{operands[1].arm64SimpleAddressOperand(:quad)}"
+        when "atomicxchgxorb"
+            $asm.puts "ldeoralb #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgxorh"
+            $asm.puts "ldeoralh #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgxori"
+            $asm.puts "ldeoral #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgxorq"
+            $asm.puts "ldeoral #{operands[0].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}, #{operands[1].arm64SimpleAddressOperand(:quad)}"
+        when "atomicxchgb"
+            $asm.puts "swpalb #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgh"
+            $asm.puts "swpalh #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgi"
+            $asm.puts "swpal #{operands[0].arm64Operand(:word)}, #{operands[2].arm64Operand(:word)}, #{operands[1].arm64SimpleAddressOperand(:word)}"
+        when "atomicxchgq"
+            $asm.puts "swpal #{operands[0].arm64Operand(:quad)}, #{operands[2].arm64Operand(:quad)}, #{operands[1].arm64SimpleAddressOperand(:quad)}"
+        when "atomicweakcasb"
+            $asm.puts "casalb #{operands[0].arm64Operand(:word)}, #{operands[1].arm64Operand(:word)}, #{operands[2].arm64SimpleAddressOperand(:word)}"
+        when "atomicweakcash"
+            $asm.puts "casalh #{operands[0].arm64Operand(:word)}, #{operands[1].arm64Operand(:word)}, #{operands[2].arm64SimpleAddressOperand(:word)}"
+        when "atomicweakcasi"
+            $asm.puts "casal #{operands[0].arm64Operand(:word)}, #{operands[1].arm64Operand(:word)}, #{operands[2].arm64SimpleAddressOperand(:word)}"
+        when "atomicweakcasq"
+            $asm.puts "casal #{operands[0].arm64Operand(:quad)}, #{operands[1].arm64Operand(:quad)}, #{operands[2].arm64SimpleAddressOperand(:quad)}"
+        when "atomicloadb"
+            $asm.puts "ldarb #{operands[1].arm64Operand(:word)}, #{operands[0].arm64SimpleAddressOperand(:word)}"
+        when "atomicloadh"
+            $asm.puts "ldarh #{operands[1].arm64Operand(:word)}, #{operands[0].arm64SimpleAddressOperand(:word)}"
+        when "atomicloadi"
+            $asm.puts "ldar #{operands[1].arm64Operand(:word)}, #{operands[0].arm64SimpleAddressOperand(:word)}"
+        when "atomicloadq"
+            $asm.puts "ldar #{operands[1].arm64Operand(:quad)}, #{operands[0].arm64SimpleAddressOperand(:quad)}"
         else
             lowerDefault
         end

Modified: trunk/Source/_javascript_Core/offlineasm/instructions.rb (270213 => 270214)


--- trunk/Source/_javascript_Core/offlineasm/instructions.rb	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/offlineasm/instructions.rb	2020-11-28 04:31:41 UTC (rev 270214)
@@ -344,6 +344,7 @@
      "cqoq",
      "idivq",
      "udivq",
+     "notq",
      "atomicxchgaddb",
      "atomicxchgaddh",
      "atomicxchgaddi",
@@ -364,6 +365,10 @@
      "atomicweakcash",
      "atomicweakcasi",
      "atomicweakcasq",
+     "atomicloadb",
+     "atomicloadh",
+     "atomicloadi",
+     "atomicloadq",
      "fence",
     ]
 
@@ -383,6 +388,7 @@
      "divis",
      "divq",
      "divqs",
+     "notq",
      "loadlinkacqb",
      "loadlinkacqh",
      "loadlinkacqi",
@@ -392,6 +398,35 @@
      "storecondreli",
      "storecondrelq",
      "fence",
+     # They are available only if Atomic LSE is supported.
+     "atomicxchgaddb",
+     "atomicxchgaddh",
+     "atomicxchgaddi",
+     "atomicxchgaddq",
+     "atomicxchgclearb",
+     "atomicxchgclearh",
+     "atomicxchgcleari",
+     "atomicxchgclearq",
+     "atomicxchgorb",
+     "atomicxchgorh",
+     "atomicxchgori",
+     "atomicxchgorq",
+     "atomicxchgxorb",
+     "atomicxchgxorh",
+     "atomicxchgxori",
+     "atomicxchgxorq",
+     "atomicxchgb",
+     "atomicxchgh",
+     "atomicxchgi",
+     "atomicxchgq",
+     "atomicweakcasb",
+     "atomicweakcash",
+     "atomicweakcasi",
+     "atomicweakcasq",
+     "atomicloadb",
+     "atomicloadh",
+     "atomicloadi",
+     "atomicloadq",
     ]
 
 RISC_INSTRUCTIONS =

Modified: trunk/Source/_javascript_Core/offlineasm/x86.rb (270213 => 270214)


--- trunk/Source/_javascript_Core/offlineasm/x86.rb	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/offlineasm/x86.rb	2020-11-28 04:31:41 UTC (rev 270214)
@@ -1116,6 +1116,8 @@
             $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
         when "noti"
             $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
+        when "notq"
+            $asm.puts "not#{x86Suffix(:quad)} #{x86Operands(:quad)}"
         when "ori"
             handleX86Op("or#{x86Suffix(:int)}", :int)
         when "orp"
@@ -1162,7 +1164,7 @@
             handleX86Op("xor#{x86Suffix(:quad)}", :quad)
         when "leap"
             emitX86Lea(operands[0], operands[1], :ptr)
-        when "loadi"
+        when "loadi", "atomicloadi"
             $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
         when "storei"
             $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
@@ -1180,11 +1182,11 @@
             $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}"
         when "storep"
             $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
-        when "loadq"
+        when "loadq", "atomicloadq"
             $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}"
         when "storeq"
             $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
-        when "loadb"
+        when "loadb", "atomicloadb"
             if !isIntelSyntax
                 $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}"
             else
@@ -1202,7 +1204,7 @@
             else
                 $asm.puts "movsx #{x86LoadOperands(:byte, :quad)}"
             end
-        when "loadh"
+        when "loadh", "atomicloadh"
             if !isIntelSyntax
                 $asm.puts "movzwl #{x86LoadOperands(:half, :int)}"
             else

Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (270213 => 270214)


--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2020-11-28 04:31:41 UTC (rev 270214)
@@ -660,9 +660,10 @@
     ExpressionType emitAtomicBinaryRMWOp(ExtAtomicOpType, Type, ExpressionType pointer, ExpressionType value, uint32_t offset);
     ExpressionType emitAtomicCompareExchange(ExtAtomicOpType, Type, ExpressionType pointer, ExpressionType expected, ExpressionType value, uint32_t offset);
 
-    TypedTmp sanitizeAtomicResult(ExtAtomicOpType, Type, TypedTmp result);
-    TypedTmp appendGeneralAtomic(ExtAtomicOpType, Type, B3::Air::Opcode nonAtomicOpcode, B3::Commutativity, Arg input, Arg addrArg);
-    TypedTmp appendStrongCAS(ExtAtomicOpType, Type, TypedTmp expected, TypedTmp value, Arg addrArg);
+    void sanitizeAtomicResult(ExtAtomicOpType, Type, Tmp source, Tmp dest);
+    void sanitizeAtomicResult(ExtAtomicOpType, Type, Tmp result);
+    TypedTmp appendGeneralAtomic(ExtAtomicOpType, B3::Air::Opcode nonAtomicOpcode, B3::Commutativity, Arg input, Arg addrArg, TypedTmp result);
+    TypedTmp appendStrongCAS(ExtAtomicOpType, TypedTmp expected, TypedTmp value, Arg addrArg, TypedTmp result);
 
     void unify(const ExpressionType dst, const ExpressionType source);
     void unifyValuesWithBlock(const Stack& resultStack, const ResultList& stack);
@@ -1744,47 +1745,56 @@
     return newPtr;
 }
 
-TypedTmp AirIRGenerator::sanitizeAtomicResult(ExtAtomicOpType op, Type valueType, TypedTmp result)
+void AirIRGenerator::sanitizeAtomicResult(ExtAtomicOpType op, Type valueType, Tmp source, Tmp dest)
 {
     switch (valueType) {
     case Type::I64: {
         switch (accessWidth(op)) {
         case B3::Width8:
-            append(ZeroExtend8To32, result, result);
-            return result;
+            append(ZeroExtend8To32, source, dest);
+            return;
         case B3::Width16:
-            append(ZeroExtend16To32, result, result);
-            return result;
+            append(ZeroExtend16To32, source, dest);
+            return;
         case B3::Width32:
-            append(Move32, result, result);
-            return result;
+            append(Move32, source, dest);
+            return;
         case B3::Width64:
-            return result;
+            if (source == dest)
+                return;
+            append(Move, source, dest);
+            return;
         }
-        break;
+        return;
     }
     case Type::I32:
         switch (accessWidth(op)) {
         case B3::Width8:
-            append(ZeroExtend8To32, result, result);
-            return result;
+            append(ZeroExtend8To32, source, dest);
+            return;
         case B3::Width16:
-            append(ZeroExtend16To32, result, result);
-            return result;
+            append(ZeroExtend16To32, source, dest);
+            return;
         case B3::Width32:
         case B3::Width64:
-            return result;
+            if (source == dest)
+                return;
+            append(Move, source, dest);
+            return;
         }
-        break;
+        return;
     default:
         RELEASE_ASSERT_NOT_REACHED();
-        break;
+        return;
     }
+}
 
-    return result;
+void AirIRGenerator::sanitizeAtomicResult(ExtAtomicOpType op, Type valueType, Tmp result)
+{
+    sanitizeAtomicResult(op, valueType, result, result);
 }
 
-TypedTmp AirIRGenerator::appendGeneralAtomic(ExtAtomicOpType op, Type valueType, B3::Air::Opcode opcode, B3::Commutativity commutativity, Arg input, Arg address)
+TypedTmp AirIRGenerator::appendGeneralAtomic(ExtAtomicOpType op, B3::Air::Opcode opcode, B3::Commutativity commutativity, Arg input, Arg address, TypedTmp oldValue)
 {
     B3::Width accessWidth = Wasm::accessWidth(op);
 
@@ -1814,7 +1824,6 @@
         return Arg();
     };
 
-    TypedTmp oldValue = valueType == Type::I64 ? g64() : g32();
     Tmp newValue = opcode == B3::Air::Nop ? tmp(input) : newTmp();
 
     // We need a CAS loop or a LL/SC loop. Using prepare/attempt jargon, we want:
@@ -1896,7 +1905,7 @@
     return oldValue;
 }
 
-TypedTmp AirIRGenerator::appendStrongCAS(ExtAtomicOpType op, Type valueType, TypedTmp expected, TypedTmp value, Arg address)
+TypedTmp AirIRGenerator::appendStrongCAS(ExtAtomicOpType op, TypedTmp expected, TypedTmp value, Arg address, TypedTmp valueResultTmp)
 {
     B3::Width accessWidth = Wasm::accessWidth(op);
 
@@ -1914,7 +1923,6 @@
         return result;
     };
 
-    TypedTmp valueResultTmp = valueType == Type::I64 ? g64() : g32();
     Tmp successBoolResultTmp = newTmp();
 
     Tmp expectedValueTmp = tmp(expected);
@@ -1930,6 +1938,13 @@
         return valueResultTmp;
     }
 
+    if (isARM64E()) {
+        append(Move, expectedValueTmp, valueResultTmp);
+        appendEffectful(OPCODE_FOR_WIDTH(AtomicStrongCAS, accessWidth), valueResultTmp, newValueTmp, address);
+        return valueResultTmp;
+    }
+
+
     RELEASE_ASSERT(isARM64());
     // We wish to emit:
     //
@@ -1993,18 +2008,31 @@
     }
 
     Optional<B3::Air::Opcode> opcode;
-    if (isX86())
+    if (isX86() || isARM64E())
         opcode = OPCODE_FOR_WIDTH(AtomicXchgAdd, accessWidth(op));
     B3::Air::Opcode nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(Add, accessWidth(op));
 
-    if (opcode && isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
-        TypedTmp result = valueType == Type::I64 ? g64() : g32();
-        append(Move, Arg::imm(0), result);
-        appendEffectful(opcode.value(), result, addrArg);
-        return sanitizeAtomicResult(op, valueType, result);
+    TypedTmp result = valueType == Type::I64 ? g64() : g32();
+
+    if (opcode) {
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind(), Arg::Tmp)) {
+            append(Move, Arg::imm(0), result);
+            appendEffectful(opcode.value(), result, addrArg, result);
+            sanitizeAtomicResult(op, valueType, result);
+            return result;
+        }
+
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
+            append(Move, Arg::imm(0), result);
+            appendEffectful(opcode.value(), result, addrArg);
+            sanitizeAtomicResult(op, valueType, result);
+            return result;
+        }
     }
 
-    return sanitizeAtomicResult(op, valueType, appendGeneralAtomic(op, valueType, nonAtomicOpcode, B3::Commutative, Arg::imm(0), addrArg));
+    appendGeneralAtomic(op, nonAtomicOpcode, B3::Commutative, Arg::imm(0), addrArg, result);
+    sanitizeAtomicResult(op, valueType, result);
+    return result;
 }
 
 auto AirIRGenerator::atomicLoad(ExtAtomicOpType op, Type valueType, ExpressionType pointer, ExpressionType& result, uint32_t offset) -> PartialResult
@@ -2052,18 +2080,26 @@
     }
 
     Optional<B3::Air::Opcode> opcode;
-    if (isX86())
+    if (isX86() || isARM64E())
         opcode = OPCODE_FOR_WIDTH(AtomicXchg, accessWidth(op));
     B3::Air::Opcode nonAtomicOpcode = B3::Air::Nop;
 
-    if (opcode && isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
-        TypedTmp result = valueType == Type::I64 ? g64() : g32();
-        append(Move, value, result);
-        appendEffectful(opcode.value(), result, addrArg);
-        return;
+    if (opcode) {
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind(), Arg::Tmp)) {
+            TypedTmp result = valueType == Type::I64 ? g64() : g32();
+            appendEffectful(opcode.value(), value, addrArg, result);
+            return;
+        }
+
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
+            TypedTmp result = valueType == Type::I64 ? g64() : g32();
+            append(Move, value, result);
+            appendEffectful(opcode.value(), result, addrArg);
+            return;
+        }
     }
 
-    appendGeneralAtomic(op, valueType, nonAtomicOpcode, B3::Commutative, value, addrArg);
+    appendGeneralAtomic(op, nonAtomicOpcode, B3::Commutative, value, addrArg, valueType == Type::I64 ? g64() : g32());
 }
 
 auto AirIRGenerator::atomicStore(ExtAtomicOpType op, Type valueType, ExpressionType pointer, ExpressionType value, uint32_t offset) -> PartialResult
@@ -2108,7 +2144,7 @@
     case ExtAtomicOpType::I64AtomicRmw16AddU:
     case ExtAtomicOpType::I64AtomicRmw32AddU:
     case ExtAtomicOpType::I64AtomicRmwAdd:
-        if (isX86())
+        if (isX86() || isARM64E())
             opcode = OPCODE_FOR_WIDTH(AtomicXchgAdd, accessWidth(op));
         nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(Add, accessWidth(op));
         commutativity = B3::Commutative;
@@ -2120,7 +2156,7 @@
     case ExtAtomicOpType::I64AtomicRmw16SubU:
     case ExtAtomicOpType::I64AtomicRmw32SubU:
     case ExtAtomicOpType::I64AtomicRmwSub:
-        if (isX86()) {
+        if (isX86() || isARM64E()) {
             TypedTmp newValue;
             if (valueType == Type::I64) {
                 newValue = g64();
@@ -2147,6 +2183,19 @@
     case ExtAtomicOpType::I64AtomicRmw16AndU:
     case ExtAtomicOpType::I64AtomicRmw32AndU:
     case ExtAtomicOpType::I64AtomicRmwAnd:
+        if (isARM64E()) {
+            TypedTmp newValue;
+            if (valueType == Type::I64) {
+                newValue = g64();
+                append(Move, value, newValue);
+                append(Not64, newValue);
+            } else {
+                newValue = g32();
+                append(Move, value, newValue);
+                append(Not32, newValue);
+            }
+            opcode = OPCODE_FOR_WIDTH(AtomicXchgClear, accessWidth(op));
+        }
         nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(And, accessWidth(op));
         commutativity = B3::Commutative;
         break;
@@ -2157,6 +2206,8 @@
     case ExtAtomicOpType::I64AtomicRmw16OrU:
     case ExtAtomicOpType::I64AtomicRmw32OrU:
     case ExtAtomicOpType::I64AtomicRmwOr:
+        if (isARM64E())
+            opcode = OPCODE_FOR_WIDTH(AtomicXchgOr, accessWidth(op));
         nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(Or, accessWidth(op));
         commutativity = B3::Commutative;
         break;
@@ -2167,6 +2218,8 @@
     case ExtAtomicOpType::I64AtomicRmw16XorU:
     case ExtAtomicOpType::I64AtomicRmw32XorU:
     case ExtAtomicOpType::I64AtomicRmwXor:
+        if (isARM64E())
+            opcode = OPCODE_FOR_WIDTH(AtomicXchgXor, accessWidth(op));
         nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(Xor, accessWidth(op));
         commutativity = B3::Commutative;
         break;
@@ -2177,7 +2230,7 @@
     case ExtAtomicOpType::I64AtomicRmw16XchgU:
     case ExtAtomicOpType::I64AtomicRmw32XchgU:
     case ExtAtomicOpType::I64AtomicRmwXchg:
-        if (isX86())
+        if (isX86() || isARM64E())
             opcode = OPCODE_FOR_WIDTH(AtomicXchg, accessWidth(op));
         nonAtomicOpcode = B3::Air::Nop;
         break;
@@ -2186,14 +2239,26 @@
         break;
     }
 
-    if (opcode && isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
-        TypedTmp result = valueType == Type::I64 ? g64() : g32();
-        append(Move, value, result);
-        appendEffectful(opcode.value(), result, addrArg);
-        return sanitizeAtomicResult(op, valueType, result);
+    TypedTmp result = valueType == Type::I64 ? g64() : g32();
+
+    if (opcode) {
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind(), Arg::Tmp)) {
+            appendEffectful(opcode.value(), value, addrArg, result);
+            sanitizeAtomicResult(op, valueType, result);
+            return result;
+        }
+
+        if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
+            append(Move, value, result);
+            appendEffectful(opcode.value(), result, addrArg);
+            sanitizeAtomicResult(op, valueType, result);
+            return result;
+        }
     }
 
-    return sanitizeAtomicResult(op, valueType, appendGeneralAtomic(op, valueType, nonAtomicOpcode, commutativity, value, addrArg));
+    appendGeneralAtomic(op, nonAtomicOpcode, commutativity, value, addrArg, result);
+    sanitizeAtomicResult(op, valueType, result);
+    return result;
 }
 
 auto AirIRGenerator::atomicBinaryRMW(ExtAtomicOpType op, Type valueType, ExpressionType pointer, ExpressionType value, ExpressionType& result, uint32_t offset) -> PartialResult
@@ -2230,8 +2295,10 @@
 {
     TypedTmp newPtr = fixupPointerPlusOffsetForAtomicOps(op, pointer, uoffset);
     Arg addrArg = isX86() ? Arg::addr(newPtr) : Arg::simpleAddr(newPtr);
+    B3::Width valueWidth = widthForType(toB3Type(valueType));
+    B3::Width accessWidth = Wasm::accessWidth(op);
 
-    if (accessWidth(op) != B3::Width8) {
+    if (accessWidth != B3::Width8) {
         emitCheck([&] {
             return Inst(BranchTest64, nullptr, Arg::resCond(MacroAssembler::NonZero), newPtr, isX86() ? Arg::bitImm(sizeOfAtomicOpMemoryAccess(op) - 1) : Arg::bitImm64(sizeOfAtomicOpMemoryAccess(op) - 1));
         }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
@@ -2239,7 +2306,57 @@
         });
     }
 
-    return sanitizeAtomicResult(op, valueType, appendStrongCAS(op, valueType, expected, value, addrArg));
+    TypedTmp result = valueType == Type::I64 ? g64() : g32();
+
+    if (valueWidth == accessWidth) {
+        appendStrongCAS(op, expected, value, addrArg, result);
+        sanitizeAtomicResult(op, valueType, result);
+        return result;
+    }
+
+    BasicBlock* failureCase = m_code.addBlock();
+    BasicBlock* successCase = m_code.addBlock();
+    BasicBlock* continuation = m_code.addBlock();
+
+    TypedTmp truncatedExpected = valueType == Type::I64 ? g64() : g32();
+    sanitizeAtomicResult(op, valueType, expected, truncatedExpected);
+
+    append(OPCODE_FOR_CANONICAL_WIDTH(Branch, valueWidth), Arg::relCond(MacroAssembler::NotEqual), expected, truncatedExpected);
+    m_currentBlock->setSuccessors(B3::Air::FrequentedBlock(failureCase, B3::FrequencyClass::Rare), successCase);
+
+    m_currentBlock = successCase;
+    appendStrongCAS(op, expected, value, addrArg, result);
+    append(Jump);
+    m_currentBlock->setSuccessors(continuation);
+
+    m_currentBlock = failureCase;
+    ([&] {
+        Optional<B3::Air::Opcode> opcode;
+        if (isX86() || isARM64E())
+            opcode = OPCODE_FOR_WIDTH(AtomicXchgAdd, accessWidth);
+        B3::Air::Opcode nonAtomicOpcode = OPCODE_FOR_CANONICAL_WIDTH(Add, accessWidth);
+
+        if (opcode) {
+            if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind(), Arg::Tmp)) {
+                append(Move, Arg::imm(0), result);
+                appendEffectful(opcode.value(), result, addrArg, result);
+                return;
+            }
+
+            if (isValidForm(opcode.value(), Arg::Tmp, addrArg.kind())) {
+                append(Move, Arg::imm(0), result);
+                appendEffectful(opcode.value(), result, addrArg);
+                return;
+            }
+        }
+        appendGeneralAtomic(op, nonAtomicOpcode, B3::Commutative, Arg::imm(0), addrArg, result);
+    })();
+    append(Jump);
+    m_currentBlock->setSuccessors(continuation);
+
+    m_currentBlock = continuation;
+    sanitizeAtomicResult(op, valueType, result);
+    return result;
 }
 
 auto AirIRGenerator::atomicCompareExchange(ExtAtomicOpType op, Type valueType, ExpressionType pointer, ExpressionType expected, ExpressionType value, ExpressionType& result, uint32_t offset) -> PartialResult

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (270213 => 270214)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2020-11-28 04:29:08 UTC (rev 270213)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2020-11-28 04:31:41 UTC (rev 270214)
@@ -1449,12 +1449,96 @@
 {
     pointer = fixupPointerPlusOffsetForAtomicOps(op, pointer, uoffset);
 
-    if (valueType == Type::I64 && accessWidth(op) != B3::Width64) {
-        expected = m_currentBlock->appendNew<B3::Value>(m_proc, B3::Trunc, Origin(), expected);
-        value = m_currentBlock->appendNew<B3::Value>(m_proc, B3::Trunc, Origin(), value);
+    B3::Width accessWidth = Wasm::accessWidth(op);
+
+    if (widthForType(toB3Type(valueType)) == accessWidth)
+        return sanitizeAtomicResult(op, valueType, m_currentBlock->appendNew<AtomicValue>(m_proc, memoryKind(AtomicStrongCAS), origin(), accessWidth, expected, value, pointer));
+
+    Value* maximum = nullptr;
+    switch (valueType) {
+    case Type::I64: {
+        switch (accessWidth) {
+        case B3::Width8:
+            maximum = constant(Int64, UINT8_MAX);
+            break;
+        case B3::Width16:
+            maximum = constant(Int64, UINT16_MAX);
+            break;
+        case B3::Width32:
+            maximum = constant(Int64, UINT32_MAX);
+            break;
+        case B3::Width64:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        break;
     }
+    case Type::I32:
+        switch (accessWidth) {
+        case B3::Width8:
+            maximum = constant(Int32, UINT8_MAX);
+            break;
+        case B3::Width16:
+            maximum = constant(Int32, UINT16_MAX);
+            break;
+        case B3::Width32:
+        case B3::Width64:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 
-    return sanitizeAtomicResult(op, valueType, m_currentBlock->appendNew<AtomicValue>(m_proc, memoryKind(AtomicStrongCAS), origin(), accessWidth(op), expected, value, pointer));
+    BasicBlock* failureCase = m_proc.addBlock();
+    BasicBlock* successCase = m_proc.addBlock();
+    BasicBlock* continuation = m_proc.addBlock();
+
+    auto condition = m_currentBlock->appendNew<Value>(m_proc, Above, origin(), expected, maximum);
+    m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(), condition, FrequentedBlock(failureCase, FrequencyClass::Rare), FrequentedBlock(successCase, FrequencyClass::Normal));
+    failureCase->addPredecessor(m_currentBlock);
+    successCase->addPredecessor(m_currentBlock);
+
+    m_currentBlock = successCase;
+    B3::UpsilonValue* successValue = nullptr;
+    {
+        auto truncatedExpected = expected;
+        auto truncatedValue = value;
+        if (valueType == Type::I64) {
+            truncatedExpected = m_currentBlock->appendNew<B3::Value>(m_proc, B3::Trunc, Origin(), expected);
+            truncatedValue = m_currentBlock->appendNew<B3::Value>(m_proc, B3::Trunc, Origin(), value);
+        }
+
+        auto result = m_currentBlock->appendNew<AtomicValue>(m_proc, memoryKind(AtomicStrongCAS), origin(), accessWidth, truncatedExpected, truncatedValue, pointer);
+        successValue = m_currentBlock->appendNew<B3::UpsilonValue>(m_proc, origin(), result);
+        m_currentBlock->appendNewControlValue(m_proc, Jump, origin(), continuation);
+        continuation->addPredecessor(m_currentBlock);
+    }
+
+    m_currentBlock = failureCase;
+    B3::UpsilonValue* failureValue = nullptr;
+    {
+        Value* addingValue = nullptr;
+        switch (accessWidth) {
+        case B3::Width8:
+        case B3::Width16:
+        case B3::Width32:
+            addingValue = constant(Int32, 0);
+            break;
+        case B3::Width64:
+            addingValue = constant(Int64, 0);
+            break;
+        }
+        auto result = m_currentBlock->appendNew<AtomicValue>(m_proc, memoryKind(AtomicXchgAdd), origin(), accessWidth, addingValue, pointer);
+        failureValue = m_currentBlock->appendNew<B3::UpsilonValue>(m_proc, origin(), result);
+        m_currentBlock->appendNewControlValue(m_proc, Jump, origin(), continuation);
+        continuation->addPredecessor(m_currentBlock);
+    }
+
+    m_currentBlock = continuation;
+    Value* phi = continuation->appendNew<Value>(m_proc, Phi, accessWidth == B3::Width64 ? Int64 : Int32, origin());
+    successValue->setPhi(phi);
+    failureValue->setPhi(phi);
+    return sanitizeAtomicResult(op, valueType, phi);
 }
 
 auto B3IRGenerator::atomicCompareExchange(ExtAtomicOpType op, Type valueType, ExpressionType pointer, ExpressionType expected, ExpressionType value, ExpressionType& result, uint32_t offset) -> PartialResult
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to