From 1695083e8100ebfda2a94b81cec1b17215fc20e7 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sun, 28 Jun 2026 18:30:32 +0200 Subject: [PATCH] Implemented mutexes --- lib/sync/Mutex.q | 14 ++++++++++++++ lib/sync/sync_linux.q | 9 +++++++++ lib/sync/sync_mac.q | 9 +++++++++ lib/sync/sync_windows.q | 9 +++++++++ lib/sync/wait_linux.q | 5 ----- src/codegen/executeBranch.go | 16 ++++++++++++++++ src/codegen/executeCas.go | 7 ------- src/codegen/needsRegister.go | 2 ++ src/ssa/Cas.go | 2 +- tests/cas.q | 9 +++------ tests/mutex.q | 16 ++++++++++++++++ tests/tests_test.go | 1 + 12 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 lib/sync/Mutex.q create mode 100644 lib/sync/sync_linux.q create mode 100644 lib/sync/sync_mac.q create mode 100644 lib/sync/sync_windows.q delete mode 100644 lib/sync/wait_linux.q create mode 100644 tests/mutex.q diff --git a/lib/sync/Mutex.q b/lib/sync/Mutex.q new file mode 100644 index 0000000..8c819ff --- /dev/null +++ b/lib/sync/Mutex.q @@ -0,0 +1,14 @@ +lock(state *uint32) { + loop { + if cas(state, 0, 1) { + return + } + + wait(state, 1) + } +} + +unlock(state *uint32) { + [state] = 0 + wake(state, 1) +} \ No newline at end of file diff --git a/lib/sync/sync_linux.q b/lib/sync/sync_linux.q new file mode 100644 index 0000000..2a81be6 --- /dev/null +++ b/lib/sync/sync_linux.q @@ -0,0 +1,9 @@ +import time + +wake(state *uint32, count int32) -> error { + return futex_wake(state, 0xFFFFFFFF, count, FUTEX2_SIZE_U32 | FUTEX2_PRIVATE) +} + +wait(address *uint32, value uint32) -> error { + return futex_wait(address, value as uint64, 0xFFFFFFFF, FUTEX2_SIZE_U32 | FUTEX2_PRIVATE, 0, time.monotonic) +} \ No newline at end of file diff --git a/lib/sync/sync_mac.q b/lib/sync/sync_mac.q new file mode 100644 index 0000000..355a636 --- /dev/null +++ b/lib/sync/sync_mac.q @@ -0,0 +1,9 @@ +wake(state *uint32, count int32) -> error { + // TODO: Not implemented. + return -1 +} + +wait(address *uint32, value uint32) -> error { + // TODO: Not implemented. + return -1 +} \ No newline at end of file diff --git a/lib/sync/sync_windows.q b/lib/sync/sync_windows.q new file mode 100644 index 0000000..355a636 --- /dev/null +++ b/lib/sync/sync_windows.q @@ -0,0 +1,9 @@ +wake(state *uint32, count int32) -> error { + // TODO: Not implemented. + return -1 +} + +wait(address *uint32, value uint32) -> error { + // TODO: Not implemented. + return -1 +} \ No newline at end of file diff --git a/lib/sync/wait_linux.q b/lib/sync/wait_linux.q deleted file mode 100644 index 185ea0b..0000000 --- a/lib/sync/wait_linux.q +++ /dev/null @@ -1,5 +0,0 @@ -import time - -wait(address *uint32, value uint32) -> error { - return futex_wait(address, value as uint64, 0xFFFFFFFF, FUTEX2_SIZE_U32, 0, time.monotonic) -} \ No newline at end of file diff --git a/src/codegen/executeBranch.go b/src/codegen/executeBranch.go index 4cd20a7..6a43596 100644 --- a/src/codegen/executeBranch.go +++ b/src/codegen/executeBranch.go @@ -2,16 +2,32 @@ package codegen import ( "git.urbach.dev/cli/q/src/asm" + "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token" + "git.urbach.dev/cli/q/src/x86" ) func (f *Function) executeBranch(step *Step, instr *ssa.Branch) { var op token.Kind binaryOp, isBinaryOp := instr.Condition.(*ssa.BinaryOp) + cas, isCas := instr.Condition.(*ssa.Cas) if isBinaryOp && binaryOp.Op.IsComparison() { op = binaryOp.Op + } else if isCas { + op = token.Equal + + dest := f.ValueToStep[cas.Arguments[1]].Register + + if f.build.Arch == config.X86 { + dest = x86.R0 + } + + f.Assembler.Append(&asm.CompareNumber{ + Destination: dest, + Number: cas.Arguments[1].(*ssa.Int).Int, + }) } else { op = token.NotEqual diff --git a/src/codegen/executeCas.go b/src/codegen/executeCas.go index 0ccb913..9c6430b 100755 --- a/src/codegen/executeCas.go +++ b/src/codegen/executeCas.go @@ -28,11 +28,4 @@ func (f *Function) executeCas(step *Step, instr *ssa.Cas) { Address: address.Register, Length: 8, }) - - if step.Register != oldValueRegister { - f.Assembler.Append(&asm.Move{ - Destination: step.Register, - Source: oldValueRegister, - }) - } } \ No newline at end of file diff --git a/src/codegen/needsRegister.go b/src/codegen/needsRegister.go index ab359c4..df66276 100644 --- a/src/codegen/needsRegister.go +++ b/src/codegen/needsRegister.go @@ -40,6 +40,8 @@ func (f *Function) needsRegister(s *Step) bool { switch instr := s.Value.(type) { case *ssa.BinaryOp: return !instr.Op.IsComparison() + case *ssa.Cas: + return false case *ssa.Int: if len(users) == 1 { // Check if we can encode single-use integers as immediates diff --git a/src/ssa/Cas.go b/src/ssa/Cas.go index 55f96af..eaf20b3 100755 --- a/src/ssa/Cas.go +++ b/src/ssa/Cas.go @@ -31,4 +31,4 @@ func (c *Cas) IsPure() bool { return false } func (c *Cas) String() string { return fmt.Sprintf("cas(%s)", c.Arguments.String()) } // Type returns the type of the CAS operation. -func (c *Cas) Type() types.Type { return types.UInt32 } \ No newline at end of file +func (c *Cas) Type() types.Type { return types.Bool } \ No newline at end of file diff --git a/tests/cas.q b/tests/cas.q index 784d1e8..c3814d7 100755 --- a/tests/cas.q +++ b/tests/cas.q @@ -2,15 +2,12 @@ main() { a := new(uint32) [a] = 1 - b := cas(a, 1, 2) - assert b == 1 + assert cas(a, 1, 2) assert [a] == 2 - b = cas(a, 1, 3) - assert b == 2 + assert !cas(a, 1, 3) assert [a] == 2 - b = cas(a, 2, 1) - assert b == 2 + assert cas(a, 2, 1) assert [a] == 1 } \ No newline at end of file diff --git a/tests/mutex.q b/tests/mutex.q new file mode 100644 index 0000000..e880b5b --- /dev/null +++ b/tests/mutex.q @@ -0,0 +1,16 @@ +import sync + +main() { + mutex := new(uint32) + + loop 0..10 { + // TODO: Spawn multiple threads once threading works on all platforms + work(mutex) + } +} + +work(mutex *uint32) { + sync.lock(mutex) + loop 0..100000 {} + sync.unlock(mutex) +} \ No newline at end of file diff --git a/tests/tests_test.go b/tests/tests_test.go index 391ca3d..498c63d 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -169,6 +169,7 @@ var tests = []run{ {"sqrt", nil, "", "", 0}, {"fold", nil, "", "", 0}, {"cas", nil, "", "", 0}, + {"mutex", nil, "", "", 0}, {"spill-call", nil, "", "", 0}, } -- 2.51.2