Skip to content

Alpha: fix decoder bugs and add test coverage#2967

Open
mattst88 wants to merge 7 commits into
capstone-engine:nextfrom
mattst88:alpha-decoder-fixes
Open

Alpha: fix decoder bugs and add test coverage#2967
mattst88 wants to merge 7 commits into
capstone-engine:nextfrom
mattst88:alpha-decoder-fixes

Conversation

@mattst88

Copy link
Copy Markdown

This series fixes several bugs in the Alpha disassembler where the
LLVM-generated decoder tables used overly-restrictive CheckField
constraints, causing legitimate instruction encodings to fail to decode.

Commits

Alpha: fix integer register class decoding order

DecodeGPRCRegisterClass indexed into the LLVM GPRC[] allocation
priority array, which is not in architectural order. Alpha integer
registers are contiguous (Alpha_R0..Alpha_R31), so the fix is
Alpha_R0 + RegNo.

Alpha: fix BR/BSR to accept any Ra register (Refs #2582)

BR and BSR use the Ra field as a write destination for the updated PC.
The decoder required Ra=31; any other value failed to decode.

Alpha: fix CALL_PAL to decode full 26-bit function code

The decoder used format 0 (no operands) and ignored bits[25:0]. Added
format 31 (26-bit immediate) so the PALcode function field is captured.

Alpha: fix JMP/JSR to accept any Ra, Rb, and hint (Closes #2582)

All four Jump instructions (JMP/JSR/RET/JSR_COROUTINE) perform identical
operations and differ only in branch-prediction hints. The decoder
required Ra=31, Rb specific values, and hint=0 for JMP/JSR.

Alpha: fix TRAPB/EXCB/MB/WMB to decode with any Ra/Rb field (Closes #2795)

These instructions architecturally ignore Ra and Rb. Setting them to
R31 is a software convention, not a hardware requirement. The decoder
rejected any encoding where Ra/Rb ≠ 31.

Alpha: fix RET/RC/RS to decode with any register fields

RET (opcode 0x1a, bits[15:14]=10) suffered the same constraint as
JMP/JSR: decoder required Ra=31, Rb=26, hint=1 exactly.

RC and RS (opcode 0x18) have an unused Rb field. The decoder checked
Rb==0 (R0), but the software convention is R31, so real compiler output
failed to decode.

Alpha: add missing test coverage for s4addq and cvt FP variants

Testing

All 425 MC tests and 2 detail tests pass.

mattst88 added 7 commits June 17, 2026 13:15
GPRC[] is LLVM's register allocation order, not the architectural
register number order. Using it to map hardware register fields 0-31
scrambled r9-r29 (e.g. field 9 → \$16, field 23 → \$9).

Alpha_R0 through Alpha_R31 are contiguous in the enum (33-64), so
Alpha_R0 + RegNo gives the correct architectural mapping directly.

Update existing tests that encoded the wrong register names, and add
new MC tests covering the previously scrambled r9-r29 range.
The LLVM decoder table constrained BR to Ra=31 and BSR to Ra=26,
rejecting all other encodings as illegal. The Alpha ISA defines Ra
as the return address destination for BSR (any writable register
is valid) and as an unused hint field for BR (any register field
is legal in existing binaries).

Remove both CheckField constraints by zeroing the skip bytes to a
no-op, and change the decode format from 25 (disp-only) to 27
(Ra + disp21) so the Ra operand is visible to callers.

Override BR/BSR in the instruction printer, since the generated
AsmWriter hardcodes "\$31" for BR and ignores Ra entirely for BSR.

Update the placeholder BSR test (which had a malformed expected
string) and add new tests for BR/BSR with non-default Ra values.

Refs: capstone-engine#2582
The LLVM decoder mapped opcode 0x00 to COND_BRANCH_I (format 0),
which tried to interpret bits[20:0] as a register number. This
failed for any PAL function code > 31 (e.g. 0x83 gentrap, 0x1020b).

Add decode format 31 that extracts bits[25:0] as a single immediate,
switch opcode 0x00 to use it, map COND_BRANCH_I to the new public
Alpha_INS_CALL_PAL, and override the printer to emit "call_pal <imm>".
The LLVM decoder required JMP to have Ra=31 and hint=0, and JSR to
have specific Ra/Rb pairs (26/27 or 23/27) with hint=0. Real-world
code uses arbitrary combinations: JMP with Ra!=31 to save return
addresses, JSR with Ra=26 and Rb!=27, or non-zero hint fields for
branch prediction.

Remove all Ra, Rb, and hint constraints for JMP and JSR. Switch both
from decode format 17 (Rb only) and 14 (no operands) to format 18
(Ra + Rb + hint14). Add printer override to emit the three-operand
form: "jmp/jsr \$ra,(\$rb),hint".

Closes: capstone-engine#2582
The LLVM assembler emits these barrier instructions with Ra=Rb=31,
but the decoder required Ra=Rb=0 (bits[25:16]=0), causing all
canonical encodings to fail.

Remove the CheckField constraint so any Ra/Rb combination is accepted.
The instructions carry no register operands in their decode format,
so the field values do not affect the output.

Closes: capstone-engine#2795
s4addq (register and literal forms), cvttq/svc, cvtts/sui, cvtqs/sui,
and cvtqt/sui had no MC tests despite being reachable instructions.
RET (opcode 0x1a, bits[15:14]=10) shares identical operation semantics
with JMP/JSR/JSR_COROUTINE — all four differ only in branch-prediction
hints. The decoder incorrectly required Ra=31, Rb=26, hint=1 exactly;
any other encoding failed to decode.

RC and RS (opcode 0x18) have an unused Rb field. The decoder checked
Rb==0 (R0), but convention is to set unused fields to R31 (=31), so
any real-world encoding produced by a compiler would fail to decode.

Remove the restrictive CheckField constraints on RET, RC, and RS.
Update RETDAG's operand table to carry Ra+Rb+hint (format 18), and
add a ret printer in Alpha_LLVM_printInstruction matching the existing
jmp/jsr handling.

Tests added: ret $0,($1),3 (non-canonical RET); rc/rs $1 with Rb=R31.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Alpha] fail to disassembly trapb and jsr [Alpha] BSR, JMP, JSR instructions are not disassembled

1 participant