Repository: tetratelabs/wazero
Pull request #2110 (2024-03-04 02:30:51)

wazevo(amd64): support for atomic loads

mathetake: cc @anuraaga
mathetake: the fuzzing failure is unrelated and will fix in another PR.


Patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine.go b/internal/engine/wazevo/backend/isa/amd64/machine.go
index 26985995..a22f29e2 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine.go
@@ -933,6 +933,29 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) {
 		}
 		m.insert(m.allocateInstr().asMovzxRmR(extModeLQ, rn, rd))
 
+	case ssa.OpcodeAtomicLoad:
+		ptr := instr.Arg()
+		size := instr.AtomicTargetSize()
+		dst := m.c.VRegOf(instr.Return())
+
+		// At this point, the ptr is ensured to be aligned, so using a normal load is atomic.
+		// https://github.com/golang/go/blob/adead1a93f472affa97c494ef19f2f492ee6f34a/src/runtime/internal/atomic/atomic_amd64.go#L30
+		mem := newOperandMem(m.lowerToAddressMode(ptr, 0))
+		load := m.allocateInstr()
+		switch size {
+		case 8:
+			load.asMov64MR(mem, dst)
+		case 4:
+			load.asMovzxRmR(extModeLQ, mem, dst)
+		case 2:
+			load.asMovzxRmR(extModeWQ, mem, dst)
+		case 1:
+			load.asMovzxRmR(extModeBQ, mem, dst)
+		default:
+			panic("BUG")
+		}
+		m.insert(load)
+
 	default:
 		panic("TODO: lowering " + op.String())
 	}


Test patch:
diff --git a/internal/engine/wazevo/e2e_test.go b/internal/engine/wazevo/e2e_test.go
index c0605a41..ff2ec773 100644
--- a/internal/engine/wazevo/e2e_test.go
+++ b/internal/engine/wazevo/e2e_test.go
@@ -600,10 +600,9 @@ func TestE2E(t *testing.T) {
 			},
 		},
 		{
-			name:      "memory_wait32",
-			m:         testcases.MemoryWait32.Module,
-			features:  api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
-			skipAMD64: true,
+			name:     "memory_wait32",
+			m:        testcases.MemoryWait32.Module,
+			features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
 			calls: []callCase{
 				{params: []uint64{0x0, 0xbeef, 0xffffffff}, expResults: []uint64{1}}, // exp not equal, returns 1
 				{params: []uint64{0x1, 0xbeef, 0xffffffff}, expErr: "unaligned atomic"},
@@ -615,10 +614,9 @@ func TestE2E(t *testing.T) {
 			},
 		},
 		{
-			name:      "memory_wait64",
-			m:         testcases.MemoryWait64.Module,
-			features:  api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
-			skipAMD64: true,
+			name:     "memory_wait64",
+			m:        testcases.MemoryWait64.Module,
+			features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
 			calls: []callCase{
 				{params: []uint64{0x0, 0xbeef, 0xffffffff}, expResults: []uint64{1}}, // exp not equal, returns 1
 				{params: []uint64{0x1, 0xbeef, 0xffffffff}, expErr: "unaligned atomic"},
@@ -634,10 +632,9 @@ func TestE2E(t *testing.T) {
 			},
 		},
 		{
-			name:      "memory_notify",
-			m:         testcases.MemoryNotify.Module,
-			features:  api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
-			skipAMD64: true,
+			name:     "memory_notify",
+			m:        testcases.MemoryNotify.Module,
+			features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
 			calls: []callCase{
 				{params: []uint64{0x0, 0x1}, expResults: []uint64{0}}, // no waiters, returns 0
 				{params: []uint64{0x1, 0x1}, expErr: "unaligned atomic"},