mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-19 11:24:19 +08:00
arm64-asm.c: fix shift instruction encoding to match ARM ISA
LSL/LSR/ASR immediate shifts are UBFM/SBFM aliases with specific immr/imms field encodings: - LSL #shift: immr = (width - shift) & 0x3F, imms = width - 1 - LSR #shift: immr = shift & 0x3F, imms = width - 1 - ASR #shift: immr = shift & 0x3F, imms = width - 1 Fixes: - immr field now always masked with 0x3F (6 bits), not width-1 - imms field is constant (width-1), not calculated from shift - ROR uses EXTR format (Rm=shift, Rn=src, Rd=dest), not UBFM format Based on ARM ARM documentation for UBFM/SBFM/EXTR instructions.
This commit is contained in:
parent
1153e48335
commit
a702dcce9e
28
arm64-asm.c
28
arm64-asm.c
@ -603,42 +603,44 @@ static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm,
|
||||
if (is_imm) {
|
||||
/* Shift by immediate */
|
||||
switch (shift_type) {
|
||||
case 0: /* LSL */
|
||||
case 0: /* LSL - UBFM alias: immr = (width - shift) & 0x3F, imms = width - 1 */
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0xD3400000 : 0x53000000;
|
||||
instr |= ((width - rm_or_imm) & (width - 1)) << 16;
|
||||
instr |= (width - 1 - rm_or_imm) << 10;
|
||||
instr |= ((width - rm_or_imm) & 0x3F) << 16; /* immr */
|
||||
instr |= (width - 1) << 10; /* imms */
|
||||
break;
|
||||
case 1: /* LSR */
|
||||
case 1: /* LSR - UBFM alias: immr = shift, imms = width - 1 */
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0xD3400000 : 0x53000000;
|
||||
instr |= rm_or_imm << 16;
|
||||
instr |= (width - 1) << 10;
|
||||
instr |= (rm_or_imm & 0x3F) << 16; /* immr */
|
||||
instr |= (width - 1) << 10; /* imms */
|
||||
break;
|
||||
case 2: /* ASR */
|
||||
case 2: /* ASR - SBFM alias: immr = shift, imms = width - 1 */
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0x93400000 : 0x13000000;
|
||||
instr |= rm_or_imm << 16;
|
||||
instr |= (width - 1) << 10;
|
||||
instr |= (rm_or_imm & 0x3F) << 16; /* immr */
|
||||
instr |= (width - 1) << 10; /* imms */
|
||||
break;
|
||||
case 3: /* ROR */
|
||||
case 3: /* ROR - EXTR alias: Rm = shift, Rn = source, Rd = dest */
|
||||
if (rm_or_imm < 0 || rm_or_imm >= width) {
|
||||
tcc_error("shift immediate out of range");
|
||||
return;
|
||||
}
|
||||
instr = is_64bit ? 0x93C00000 : 0x13800000;
|
||||
instr |= (rn & 0x1F) << 16;
|
||||
instr |= (rm_or_imm & (width - 1)) << 10;
|
||||
break;
|
||||
instr |= (rm_or_imm & 0x1F) << 16; /* Rm = shift amount */
|
||||
instr |= (rn & 0x1F) << 5; /* Rn = source */
|
||||
instr |= rd & 0x1F; /* Rd = dest */
|
||||
emit_instr32(instr);
|
||||
return;
|
||||
default:
|
||||
tcc_error("unknown shift type");
|
||||
return;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user