kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 6ddf35a70674161ac4cccecf126763cc566e8c50
parent 05bca5fe8e103711afaf75836d6aa5af3b483fe1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 29 May 2026 14:22:09 -0700

aa64 asm: encode bitfield (sbfm/ubfm/bfm) and DP1 (clz/rbit/rev/rev16)

The kTable lacked these even though codegen emits them (sign/zero-extend and
shifts via sbfm/ubfm; clz/ctz/bswap builtins via clz/rbit/rev) and the
disassembler decodes them. Add the encode side via isa.h encoders
aa64_bitfield/aa64_dp1 (shared bit-knowledge with the decode rows; rev picks
opcode2 by width). Byte-identical to clang; adds aa64_bitfield_dp1 corpus case.

Diffstat:
Msrc/arch/aa64/asm.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/arch/aa64/isa.h | 21+++++++++++++++++++++
Atest/asm/encode/aa64_bitfield_dp1.expected.hex | 1+
Atest/asm/encode/aa64_bitfield_dp1.s | 12++++++++++++
Atest/asm/encode/aa64_bitfield_dp1.targets | 2++
5 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/src/arch/aa64/asm.c b/src/arch/aa64/asm.c @@ -1261,6 +1261,47 @@ static void p_ucvtf(AsmDriver* d) { p_cvtf(d, AA64_FP_ICVT_UCVTF); } static void p_fcvtzs(AsmDriver* d) { p_fcvtz(d, AA64_FP_ICVT_FCVTZS); } static void p_fcvtzu(AsmDriver* d) { p_fcvtz(d, AA64_FP_ICVT_FCVTZU); } +/* Data-processing (1 source): clz/rbit/rev16, and rev (whose opcode2 is the + * width: 2 for 32-bit, 3 for 64-bit). */ +static void p_dp1_op(AsmDriver* d, u32 opcode2) { + AA64Reg rd = parse_reg(d); + AA64Reg rn; + expect_comma(d, "dp1"); + rn = parse_reg(d); + if (rd.is64 != rn.is64) asm_driver_panic(d, "asm: dp1: width mismatch"); + emit32(d, aa64_dp1(rd.is64, opcode2, rd.num, rn.num)); +} +static void p_clz(AsmDriver* d) { p_dp1_op(d, AA64_DP1_CLZ); } +static void p_rbit(AsmDriver* d) { p_dp1_op(d, AA64_DP1_RBIT); } +static void p_rev16(AsmDriver* d) { p_dp1_op(d, AA64_DP1_REV16); } +static void p_rev(AsmDriver* d) { + AA64Reg rd = parse_reg(d); + AA64Reg rn; + expect_comma(d, "rev"); + rn = parse_reg(d); + if (rd.is64 != rn.is64) asm_driver_panic(d, "asm: rev: width mismatch"); + emit32(d, aa64_dp1(rd.is64, rd.is64 ? AA64_DP1_REV64 : AA64_DP1_REV32, rd.num, + rn.num)); +} + +/* Bitfield move (opc: 0=sbfm, 1=bfm, 2=ubfm): Rd, Rn, #immr, #imms. */ +static void p_bitfield(AsmDriver* d, u32 opc) { + AA64Reg rd = parse_reg(d); + AA64Reg rn; + i64 immr, imms; + expect_comma(d, "bitfield"); + rn = parse_reg(d); + expect_comma(d, "bitfield"); + immr = parse_imm_const(d); + expect_comma(d, "bitfield"); + imms = parse_imm_const(d); + if (rd.is64 != rn.is64) asm_driver_panic(d, "asm: bitfield: width mismatch"); + emit32(d, aa64_bitfield(rd.is64, opc, (u32)immr, (u32)imms, rd.num, rn.num)); +} +static void p_sbfm(AsmDriver* d) { p_bitfield(d, 0u); } +static void p_bfm(AsmDriver* d) { p_bitfield(d, 1u); } +static void p_ubfm(AsmDriver* d) { p_bitfield(d, 2u); } + /* fmov: Vd,Vn (FP reg move) | Rd,Vn (fp->gpr) | Vd,Rn (gpr->fp). */ static void p_fmov(AsmDriver* d) { FpOrGpr a = parse_fp_or_gpr(d); @@ -1297,6 +1338,13 @@ static const AA64Mn kTable[] = { {"ucvtf", p_ucvtf, 0}, {"fcvtzs", p_fcvtzs, 0}, {"fcvtzu", p_fcvtzu, 0}, + {"clz", p_clz, 0}, + {"rbit", p_rbit, 0}, + {"rev", p_rev, 0}, + {"rev16", p_rev16, 0}, + {"sbfm", p_sbfm, 0}, + {"ubfm", p_ubfm, 0}, + {"bfm", p_bfm, 0}, {"nop", p_nop, 0}, {"dmb", p_dmb, 0}, {"dsb", p_dsb, 0}, diff --git a/src/arch/aa64/isa.h b/src/arch/aa64/isa.h @@ -832,6 +832,27 @@ static inline u32 aa64_fp_int_cvt(u32 sf, u32 ftype, u32 opcode, u32 Rd, ((opcode & 0x1fu) << 16) | ((Rn & 0x1fu) << 5) | (Rd & 0x1fu); } +/* Bitfield move (opc: 0=SBFM, 1=BFM, 2=UBFM). The N bit tracks sf for the + * 32-/64-bit forms. Matches native.c aa_sbfm/aa_ubfm and the BITFIELD row. */ +static inline u32 aa64_bitfield(u32 sf, u32 opc, u32 immr, u32 imms, u32 Rd, + u32 Rn) { + return ((sf & 1u) << 31) | ((opc & 3u) << 29) | 0x13000000u | + ((sf & 1u) << 22) | ((immr & 0x3fu) << 16) | ((imms & 0x3fu) << 10) | + ((Rn & 0x1fu) << 5) | (Rd & 0x1fu); +} + +/* Data-processing (1 source). opcode2 (bits[15:10]): RBIT=0, REV16=1, + * REV(32)=2, REV(64)=3, CLZ=4. Matches native.c aa_clz/aa_rbit/aa_rev. */ +#define AA64_DP1_RBIT 0x00u +#define AA64_DP1_REV16 0x01u +#define AA64_DP1_REV32 0x02u +#define AA64_DP1_REV64 0x03u +#define AA64_DP1_CLZ 0x04u +static inline u32 aa64_dp1(u32 sf, u32 opcode2, u32 Rd, u32 Rn) { + return ((sf & 1u) << 31) | 0x5AC00000u | ((opcode2 & 0x3fu) << 10) | + ((Rn & 0x1fu) << 5) | (Rd & 0x1fu); +} + /* ==================================================================== * Load/store register pair, pre-indexed (STP / LDP, 64-bit form) * opc(2) 101 V(1) 010 L(1) imm7(7) Rt2(5) Rn(5) Rt(5) diff --git a/test/asm/encode/aa64_bitfield_dp1.expected.hex b/test/asm/encode/aa64_bitfield_dp1.expected.hex @@ -0,0 +1 @@ +2010c0da6210c05aa400c0dae60cc0da2809c05a6a05c0da2050449362280253a44048b3c0035fd6 diff --git a/test/asm/encode/aa64_bitfield_dp1.s b/test/asm/encode/aa64_bitfield_dp1.s @@ -0,0 +1,12 @@ +.text +t: + clz x0, x1 + clz w2, w3 + rbit x4, x5 + rev x6, x7 + rev w8, w9 + rev16 x10, x11 + sbfm x0, x1, #4, #20 + ubfm w2, w3, #2, #10 + bfm x4, x5, #8, #16 + ret diff --git a/test/asm/encode/aa64_bitfield_dp1.targets b/test/asm/encode/aa64_bitfield_dp1.targets @@ -0,0 +1 @@ +aa64 +\ No newline at end of file