commit a093cd3a04ccea2aff751e618e07ff77befa396c
parent 4f9d8c341c11e0ed72c7621b6517c47a9159d25f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 01:01:12 -0700
arm32 as: cmp/mov accept a modified-immediate second operand
The standalone assembler resolved `cmp`/`mov` to their hi-register forms and
parsed a fixed two registers, so `cmp rn, #imm` / `mov rd, #imm` (and the
IT-predicated `moveq rd, #imm`) errored 'bad core register' on the immediate.
Peek the operand shape: cmp emits the 16-bit DPI8 compare (rn<=r7, imm8) or
32-bit cmp.w; mov emits mov.w (no-flags, IT-conditionalizable). This is what the
hand-written coroutine register-switch asm (rt/lib/coro/arm32.c) needs to build
with kit's own assembler — it now does, end to end.
Diffstat:
1 file changed, 24 insertions(+), 0 deletions(-)
diff --git a/src/arch/arm32/asm.c b/src/arch/arm32/asm.c
@@ -649,6 +649,15 @@ static void assemble_one(AsmDriver* d, const Arm32InsnDesc* desc, u32 cond) {
case ARM_FMT_MOVHI16: {
u32 rd = parse_reg(d), rm;
expect_comma(d);
+ /* `mov rd, #imm` selects the 32-bit mov.w (preserving mov's no-flags
+ * semantics; conditionalizable inside an IT block as `moveq`/etc.). */
+ if (!peek_is_reg(d)) {
+ u32 out12;
+ if (!thumb_expand_imm_encode((u32)parse_imm(d), &out12))
+ asm_driver_panic(d, "arm32 asm: mov immediate not encodable");
+ emit_t32(d, arm_mov_imm(rd, out12));
+ return;
+ }
rm = parse_reg(d);
emit_t16(d, arm_mov_hi(rd, rm));
return;
@@ -721,6 +730,21 @@ static void assemble_one(AsmDriver* d, const Arm32InsnDesc* desc, u32 cond) {
case ARM_FMT_HIREG_16: {
u32 rdn = parse_reg(d), rm;
expect_comma(d);
+ /* `cmp` resolves to this hi-register compare first; an immediate second
+ * operand (`cmp rn, #imm`) selects the modified-immediate compare — the
+ * 16-bit DPI8 form when rn<=r7 and imm8 fits, else the 32-bit cmp.w. */
+ if (!peek_is_reg(d) && slice_eq_cstr(mn, "cmp")) {
+ i64 imm = parse_imm(d);
+ if (rdn <= 7u && imm >= 0 && imm <= 255)
+ emit_t16(d, (u16)(0x2800u | (rdn << 8) | (u32)(imm & 0xffu)));
+ else {
+ u32 out12;
+ if (!thumb_expand_imm_encode((u32)imm, &out12))
+ asm_driver_panic(d, "arm32 asm: cmp immediate not encodable");
+ emit_t32(d, arm_cmp_imm(rdn, out12));
+ }
+ return;
+ }
rm = parse_reg(d);
emit_t16(d, (u16)((desc->match & 0xff00u) | (((rdn >> 3) & 1u) << 7) |
((rm & 0xfu) << 3) | (rdn & 7u)));