commit cedc6e279cc8d9847ee4fa43c9d9010b7ec1b6bb
parent 5a0e24dcba8784c652d4be3e3b6640564fcf52b4
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 16 Jun 2026 22:38:01 -0700
arm32: atomic addr via pointer reg; toy @target_arch arm32; test applicability
- arm_atomic_addr_reg: use the pointer's own register when the address already is
one (the -O1 case) instead of always materializing into LR — LR may hold an
atomic value operand the optimizer staged there, so the old code emitted e.g.
'strex r4, lr, [lr]' storing the base instead of the desired value.
- toy_target_code: map KIT_ARCH_ARM_32 -> 5 (the .arm32 selector) so
@target_arch() switches resolve on arm32; add the .arm32 arm to
47_target_arch_switch.
- 145_baremetal_privileged_aa64: add a .arm32.skip (aarch64-only DAIF/wfe/sev,
no M-profile lowering).
Diffstat:
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/lang/toy/expr.c b/lang/toy/expr.c
@@ -536,6 +536,8 @@ int toy_target_code(ToyParser* p) {
return 3;
case KIT_ARCH_RV32:
return 6;
+ case KIT_ARCH_ARM_32:
+ return 5; /* matches the `.arm32` dot-constant selector */
case KIT_ARCH_WASM:
return 7;
default:
diff --git a/src/arch/arm32/native.c b/src/arch/arm32/native.c
@@ -2187,9 +2187,18 @@ static int arm_order_release(KitCgMemOrder o) {
* may be a frame slot or a register; load_addr lands the pointer in lr, which
* the LDREX/STREX sequence then uses as the base. */
static u32 arm_atomic_addr_reg(Arm32NativeTarget* a, NativeAddr addr) {
- NativeLoc dst =
- native_loc_reg(builtin_id(KIT_CG_BUILTIN_I32), NATIVE_REG_INT, ARM_TMP);
- arm_load_addr(&a->base, dst, addr);
+ /* Use the pointer's own register when the address already is one (the -O1
+ * case: the optimizer collapses &x into a register distinct from the atomic
+ * value operands). Materializing into LR would collide with a value operand
+ * the optimizer staged in LR (an emit scratch). Otherwise (a FRAME/GLOBAL
+ * address, e.g. -O0) materialize into LR, which holds no operand there. */
+ if (addr.base_kind == NATIVE_ADDR_BASE_REG && addr.offset == 0 &&
+ addr.index_kind == NATIVE_ADDR_INDEX_NONE)
+ return addr.base.reg & 0xfu;
+ arm_load_addr(&a->base,
+ native_loc_reg(builtin_id(KIT_CG_BUILTIN_I32), NATIVE_REG_INT,
+ ARM_TMP),
+ addr);
return ARM_TMP;
}
diff --git a/test/toy/cases/145_baremetal_privileged_aa64.arm32.skip b/test/toy/cases/145_baremetal_privileged_aa64.arm32.skip
@@ -0,0 +1 @@
+aarch64-only: exercises DAIF irq-mask + wfe/sev intrinsics that have no M-profile (PRIMASK/WFE differ) lowering; the case is gated to aarch64 by name.
diff --git a/test/toy/cases/47_target_arch_switch.toy b/test/toy/cases/47_target_arch_switch.toy
@@ -12,6 +12,9 @@ fn __user_main(): i64 {
.rv32 {
40
}
+ .arm32 {
+ 40
+ }
.wasm {
40
}