]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/riscv: rework instruction encoding information
authorJoel Sing <joel@sing.id.au>
Wed, 14 Aug 2024 16:48:09 +0000 (02:48 +1000)
committerJoel Sing <joel@sing.id.au>
Thu, 21 Nov 2024 22:31:25 +0000 (22:31 +0000)
Currently, instruction encoding is a slice of encoding types, which
is indexed by a masked version of the riscv64 opcode. Additional
information about some instructions (for example, if an instruction
has a ternary form and if there is an immediate form for an instruction)
is manually specified in other parts of the assembler code.

Rework the instruction encoding information so that we use a table
driven form, providing additional data for each instruction where
relevant. This means that we can simplify other parts of the code
by simply looking up the instruction data and reusing minimal logic.

Change-Id: I7b3b6c61a4868647edf28bd7dbae2150e043ae00
Cq-Include-Trybots: luci.golang.try:gotip-linux-riscv64
Reviewed-on: https://go-review.googlesource.com/c/go/+/622535
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
Reviewed-by: Mark Ryan <markdryan@rivosinc.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/cmd/internal/obj/riscv/obj.go

index a78c1c63a4d62f657d70894d08112bcb75914d38..5f01c43e7bf4c388b9759525e7e9d4c89b7b061a 100644 (file)
@@ -53,18 +53,14 @@ func jalToSym(ctxt *obj.Link, p *obj.Prog, lr int16) {
 // progedit is called individually for each *obj.Prog. It normalizes instruction
 // formats and eliminates as many pseudo-instructions as possible.
 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
+       insData, err := instructionDataForAs(p.As)
+       if err != nil {
+               panic(fmt.Sprintf("failed to lookup instruction data for %v: %v", p.As, err))
+       }
 
        // Expand binary instructions to ternary ones.
        if p.Reg == obj.REG_NONE {
-               switch p.As {
-               case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI,
-                       AADDIW, ASLLIW, ASRLIW, ASRAIW, AADDW, ASUBW, ASLLW, ASRLW, ASRAW,
-                       AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA,
-                       AMUL, AMULH, AMULHU, AMULHSU, AMULW, ADIV, ADIVU, ADIVW, ADIVUW,
-                       AREM, AREMU, AREMW, AREMUW,
-                       AADDUW, ASH1ADD, ASH1ADDUW, ASH2ADD, ASH2ADDUW, ASH3ADD, ASH3ADDUW, ASLLIUW,
-                       AANDN, AORN, AXNOR, AMAX, AMAXU, AMIN, AMINU, AROL, AROLW, AROR, ARORW, ARORI, ARORIW,
-                       ABCLR, ABCLRI, ABEXT, ABEXTI, ABINV, ABINVI, ABSET, ABSETI:
+               if insData.ternary {
                        p.Reg = p.To.Reg
                }
        }
@@ -73,48 +69,14 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
        // form of the instruction.
        if p.From.Type == obj.TYPE_CONST {
                switch p.As {
-               case AADD:
-                       p.As = AADDI
                case ASUB:
                        p.As, p.From.Offset = AADDI, -p.From.Offset
-               case ASLT:
-                       p.As = ASLTI
-               case ASLTU:
-                       p.As = ASLTIU
-               case AAND:
-                       p.As = AANDI
-               case AOR:
-                       p.As = AORI
-               case AXOR:
-                       p.As = AXORI
-               case ASLL:
-                       p.As = ASLLI
-               case ASRL:
-                       p.As = ASRLI
-               case ASRA:
-                       p.As = ASRAI
-               case AADDW:
-                       p.As = AADDIW
                case ASUBW:
                        p.As, p.From.Offset = AADDIW, -p.From.Offset
-               case ASLLW:
-                       p.As = ASLLIW
-               case ASRLW:
-                       p.As = ASRLIW
-               case ASRAW:
-                       p.As = ASRAIW
-               case AROR:
-                       p.As = ARORI
-               case ARORW:
-                       p.As = ARORIW
-               case ABCLR:
-                       p.As = ABCLRI
-               case ABEXT:
-                       p.As = ABEXTI
-               case ABINV:
-                       p.As = ABINVI
-               case ABSET:
-                       p.As = ABSETI
+               default:
+                       if insData.immForm != obj.AXXX {
+                               p.As = insData.immForm
+                       }
                }
        }
 
@@ -1567,285 +1529,300 @@ var (
        badEncoding = encoding{encode: func(*instruction) uint32 { return 0 }, validate: func(*obj.Link, *instruction) {}, length: 0}
 )
 
-// encodings contains the encodings for RISC-V instructions.
-// Instructions are masked with obj.AMask to keep indices small.
-var encodings = [ALAST & obj.AMask]encoding{
+// instructionData specifies details relating to a RISC-V instruction.
+type instructionData struct {
+       enc     encoding
+       immForm obj.As // immediate form of this instruction
+       ternary bool
+}
 
+// instructions contains details of RISC-V instructions, including
+// their encoding type. Entries are masked with obj.AMask to keep
+// indices small.
+var instructions = [ALAST & obj.AMask]instructionData{
        // Unprivileged ISA
 
        // 2.4: Integer Computational Instructions
-       AADDI & obj.AMask:  iIIEncoding,
-       ASLTI & obj.AMask:  iIIEncoding,
-       ASLTIU & obj.AMask: iIIEncoding,
-       AANDI & obj.AMask:  iIIEncoding,
-       AORI & obj.AMask:   iIIEncoding,
-       AXORI & obj.AMask:  iIIEncoding,
-       ASLLI & obj.AMask:  iIIEncoding,
-       ASRLI & obj.AMask:  iIIEncoding,
-       ASRAI & obj.AMask:  iIIEncoding,
-       ALUI & obj.AMask:   uEncoding,
-       AAUIPC & obj.AMask: uEncoding,
-       AADD & obj.AMask:   rIIIEncoding,
-       ASLT & obj.AMask:   rIIIEncoding,
-       ASLTU & obj.AMask:  rIIIEncoding,
-       AAND & obj.AMask:   rIIIEncoding,
-       AOR & obj.AMask:    rIIIEncoding,
-       AXOR & obj.AMask:   rIIIEncoding,
-       ASLL & obj.AMask:   rIIIEncoding,
-       ASRL & obj.AMask:   rIIIEncoding,
-       ASUB & obj.AMask:   rIIIEncoding,
-       ASRA & obj.AMask:   rIIIEncoding,
+       AADDI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ASLTI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ASLTIU & obj.AMask: {enc: iIIEncoding, ternary: true},
+       AANDI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       AORI & obj.AMask:   {enc: iIIEncoding, ternary: true},
+       AXORI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ASLLI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ASRLI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ASRAI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ALUI & obj.AMask:   {enc: uEncoding},
+       AAUIPC & obj.AMask: {enc: uEncoding},
+       AADD & obj.AMask:   {enc: rIIIEncoding, immForm: AADDI, ternary: true},
+       ASLT & obj.AMask:   {enc: rIIIEncoding, immForm: ASLTI, ternary: true},
+       ASLTU & obj.AMask:  {enc: rIIIEncoding, immForm: ASLTIU, ternary: true},
+       AAND & obj.AMask:   {enc: rIIIEncoding, immForm: AANDI, ternary: true},
+       AOR & obj.AMask:    {enc: rIIIEncoding, immForm: AORI, ternary: true},
+       AXOR & obj.AMask:   {enc: rIIIEncoding, immForm: AXORI, ternary: true},
+       ASLL & obj.AMask:   {enc: rIIIEncoding, immForm: ASLLI, ternary: true},
+       ASRL & obj.AMask:   {enc: rIIIEncoding, immForm: ASRLI, ternary: true},
+       ASUB & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ASRA & obj.AMask:   {enc: rIIIEncoding, immForm: ASRAI, ternary: true},
 
        // 2.5: Control Transfer Instructions
-       AJAL & obj.AMask:  jEncoding,
-       AJALR & obj.AMask: iIIEncoding,
-       ABEQ & obj.AMask:  bEncoding,
-       ABNE & obj.AMask:  bEncoding,
-       ABLT & obj.AMask:  bEncoding,
-       ABLTU & obj.AMask: bEncoding,
-       ABGE & obj.AMask:  bEncoding,
-       ABGEU & obj.AMask: bEncoding,
+       AJAL & obj.AMask:  {enc: jEncoding},
+       AJALR & obj.AMask: {enc: iIIEncoding},
+       ABEQ & obj.AMask:  {enc: bEncoding},
+       ABNE & obj.AMask:  {enc: bEncoding},
+       ABLT & obj.AMask:  {enc: bEncoding},
+       ABLTU & obj.AMask: {enc: bEncoding},
+       ABGE & obj.AMask:  {enc: bEncoding},
+       ABGEU & obj.AMask: {enc: bEncoding},
 
        // 2.6: Load and Store Instructions
-       ALW & obj.AMask:  iIIEncoding,
-       ALWU & obj.AMask: iIIEncoding,
-       ALH & obj.AMask:  iIIEncoding,
-       ALHU & obj.AMask: iIIEncoding,
-       ALB & obj.AMask:  iIIEncoding,
-       ALBU & obj.AMask: iIIEncoding,
-       ASW & obj.AMask:  sIEncoding,
-       ASH & obj.AMask:  sIEncoding,
-       ASB & obj.AMask:  sIEncoding,
+       ALW & obj.AMask:  {enc: iIIEncoding},
+       ALWU & obj.AMask: {enc: iIIEncoding},
+       ALH & obj.AMask:  {enc: iIIEncoding},
+       ALHU & obj.AMask: {enc: iIIEncoding},
+       ALB & obj.AMask:  {enc: iIIEncoding},
+       ALBU & obj.AMask: {enc: iIIEncoding},
+       ASW & obj.AMask:  {enc: sIEncoding},
+       ASH & obj.AMask:  {enc: sIEncoding},
+       ASB & obj.AMask:  {enc: sIEncoding},
 
        // 2.7: Memory Ordering
-       AFENCE & obj.AMask: iIIEncoding,
+       AFENCE & obj.AMask: {enc: iIIEncoding},
 
        // 5.2: Integer Computational Instructions (RV64I)
-       AADDIW & obj.AMask: iIIEncoding,
-       ASLLIW & obj.AMask: iIIEncoding,
-       ASRLIW & obj.AMask: iIIEncoding,
-       ASRAIW & obj.AMask: iIIEncoding,
-       AADDW & obj.AMask:  rIIIEncoding,
-       ASLLW & obj.AMask:  rIIIEncoding,
-       ASRLW & obj.AMask:  rIIIEncoding,
-       ASUBW & obj.AMask:  rIIIEncoding,
-       ASRAW & obj.AMask:  rIIIEncoding,
+       AADDIW & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ASLLIW & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ASRLIW & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ASRAIW & obj.AMask: {enc: iIIEncoding, ternary: true},
+       AADDW & obj.AMask:  {enc: rIIIEncoding, immForm: AADDIW, ternary: true},
+       ASLLW & obj.AMask:  {enc: rIIIEncoding, immForm: ASLLIW, ternary: true},
+       ASRLW & obj.AMask:  {enc: rIIIEncoding, immForm: ASRLIW, ternary: true},
+       ASUBW & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       ASRAW & obj.AMask:  {enc: rIIIEncoding, immForm: ASRAIW, ternary: true},
 
        // 5.3: Load and Store Instructions (RV64I)
-       ALD & obj.AMask: iIIEncoding,
-       ASD & obj.AMask: sIEncoding,
+       ALD & obj.AMask: {enc: iIIEncoding},
+       ASD & obj.AMask: {enc: sIEncoding},
 
        // 7.1: CSR Instructions
-       ACSRRS & obj.AMask: iIIEncoding,
+       ACSRRS & obj.AMask: {enc: iIIEncoding},
 
        // 7.1: Multiplication Operations
-       AMUL & obj.AMask:    rIIIEncoding,
-       AMULH & obj.AMask:   rIIIEncoding,
-       AMULHU & obj.AMask:  rIIIEncoding,
-       AMULHSU & obj.AMask: rIIIEncoding,
-       AMULW & obj.AMask:   rIIIEncoding,
-       ADIV & obj.AMask:    rIIIEncoding,
-       ADIVU & obj.AMask:   rIIIEncoding,
-       AREM & obj.AMask:    rIIIEncoding,
-       AREMU & obj.AMask:   rIIIEncoding,
-       ADIVW & obj.AMask:   rIIIEncoding,
-       ADIVUW & obj.AMask:  rIIIEncoding,
-       AREMW & obj.AMask:   rIIIEncoding,
-       AREMUW & obj.AMask:  rIIIEncoding,
+       AMUL & obj.AMask:    {enc: rIIIEncoding, ternary: true},
+       AMULH & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AMULHU & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AMULHSU & obj.AMask: {enc: rIIIEncoding, ternary: true},
+       AMULW & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ADIV & obj.AMask:    {enc: rIIIEncoding, ternary: true},
+       ADIVU & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AREM & obj.AMask:    {enc: rIIIEncoding, ternary: true},
+       AREMU & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ADIVW & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ADIVUW & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AREMW & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AREMUW & obj.AMask:  {enc: rIIIEncoding, ternary: true},
 
        // 8.2: Load-Reserved/Store-Conditional
-       ALRW & obj.AMask: rIIIEncoding,
-       ALRD & obj.AMask: rIIIEncoding,
-       ASCW & obj.AMask: rIIIEncoding,
-       ASCD & obj.AMask: rIIIEncoding,
+       ALRW & obj.AMask: {enc: rIIIEncoding},
+       ALRD & obj.AMask: {enc: rIIIEncoding},
+       ASCW & obj.AMask: {enc: rIIIEncoding},
+       ASCD & obj.AMask: {enc: rIIIEncoding},
 
        // 8.3: Atomic Memory Operations
-       AAMOSWAPW & obj.AMask: rIIIEncoding,
-       AAMOSWAPD & obj.AMask: rIIIEncoding,
-       AAMOADDW & obj.AMask:  rIIIEncoding,
-       AAMOADDD & obj.AMask:  rIIIEncoding,
-       AAMOANDW & obj.AMask:  rIIIEncoding,
-       AAMOANDD & obj.AMask:  rIIIEncoding,
-       AAMOORW & obj.AMask:   rIIIEncoding,
-       AAMOORD & obj.AMask:   rIIIEncoding,
-       AAMOXORW & obj.AMask:  rIIIEncoding,
-       AAMOXORD & obj.AMask:  rIIIEncoding,
-       AAMOMAXW & obj.AMask:  rIIIEncoding,
-       AAMOMAXD & obj.AMask:  rIIIEncoding,
-       AAMOMAXUW & obj.AMask: rIIIEncoding,
-       AAMOMAXUD & obj.AMask: rIIIEncoding,
-       AAMOMINW & obj.AMask:  rIIIEncoding,
-       AAMOMIND & obj.AMask:  rIIIEncoding,
-       AAMOMINUW & obj.AMask: rIIIEncoding,
-       AAMOMINUD & obj.AMask: rIIIEncoding,
+       AAMOSWAPW & obj.AMask: {enc: rIIIEncoding},
+       AAMOSWAPD & obj.AMask: {enc: rIIIEncoding},
+       AAMOADDW & obj.AMask:  {enc: rIIIEncoding},
+       AAMOADDD & obj.AMask:  {enc: rIIIEncoding},
+       AAMOANDW & obj.AMask:  {enc: rIIIEncoding},
+       AAMOANDD & obj.AMask:  {enc: rIIIEncoding},
+       AAMOORW & obj.AMask:   {enc: rIIIEncoding},
+       AAMOORD & obj.AMask:   {enc: rIIIEncoding},
+       AAMOXORW & obj.AMask:  {enc: rIIIEncoding},
+       AAMOXORD & obj.AMask:  {enc: rIIIEncoding},
+       AAMOMAXW & obj.AMask:  {enc: rIIIEncoding},
+       AAMOMAXD & obj.AMask:  {enc: rIIIEncoding},
+       AAMOMAXUW & obj.AMask: {enc: rIIIEncoding},
+       AAMOMAXUD & obj.AMask: {enc: rIIIEncoding},
+       AAMOMINW & obj.AMask:  {enc: rIIIEncoding},
+       AAMOMIND & obj.AMask:  {enc: rIIIEncoding},
+       AAMOMINUW & obj.AMask: {enc: rIIIEncoding},
+       AAMOMINUD & obj.AMask: {enc: rIIIEncoding},
 
        // 11.5: Single-Precision Load and Store Instructions
-       AFLW & obj.AMask: iFEncoding,
-       AFSW & obj.AMask: sFEncoding,
+       AFLW & obj.AMask: {enc: iFEncoding},
+       AFSW & obj.AMask: {enc: sFEncoding},
 
        // 11.6: Single-Precision Floating-Point Computational Instructions
-       AFADDS & obj.AMask:   rFFFEncoding,
-       AFSUBS & obj.AMask:   rFFFEncoding,
-       AFMULS & obj.AMask:   rFFFEncoding,
-       AFDIVS & obj.AMask:   rFFFEncoding,
-       AFMINS & obj.AMask:   rFFFEncoding,
-       AFMAXS & obj.AMask:   rFFFEncoding,
-       AFSQRTS & obj.AMask:  rFFFEncoding,
-       AFMADDS & obj.AMask:  rFFFFEncoding,
-       AFMSUBS & obj.AMask:  rFFFFEncoding,
-       AFNMSUBS & obj.AMask: rFFFFEncoding,
-       AFNMADDS & obj.AMask: rFFFFEncoding,
+       AFADDS & obj.AMask:   {enc: rFFFEncoding},
+       AFSUBS & obj.AMask:   {enc: rFFFEncoding},
+       AFMULS & obj.AMask:   {enc: rFFFEncoding},
+       AFDIVS & obj.AMask:   {enc: rFFFEncoding},
+       AFMINS & obj.AMask:   {enc: rFFFEncoding},
+       AFMAXS & obj.AMask:   {enc: rFFFEncoding},
+       AFSQRTS & obj.AMask:  {enc: rFFFEncoding},
+       AFMADDS & obj.AMask:  {enc: rFFFFEncoding},
+       AFMSUBS & obj.AMask:  {enc: rFFFFEncoding},
+       AFNMSUBS & obj.AMask: {enc: rFFFFEncoding},
+       AFNMADDS & obj.AMask: {enc: rFFFFEncoding},
 
        // 11.7: Single-Precision Floating-Point Conversion and Move Instructions
-       AFCVTWS & obj.AMask:  rFIEncoding,
-       AFCVTLS & obj.AMask:  rFIEncoding,
-       AFCVTSW & obj.AMask:  rIFEncoding,
-       AFCVTSL & obj.AMask:  rIFEncoding,
-       AFCVTWUS & obj.AMask: rFIEncoding,
-       AFCVTLUS & obj.AMask: rFIEncoding,
-       AFCVTSWU & obj.AMask: rIFEncoding,
-       AFCVTSLU & obj.AMask: rIFEncoding,
-       AFSGNJS & obj.AMask:  rFFFEncoding,
-       AFSGNJNS & obj.AMask: rFFFEncoding,
-       AFSGNJXS & obj.AMask: rFFFEncoding,
-       AFMVXW & obj.AMask:   rFIEncoding,
-       AFMVWX & obj.AMask:   rIFEncoding,
+       AFCVTWS & obj.AMask:  {enc: rFIEncoding},
+       AFCVTLS & obj.AMask:  {enc: rFIEncoding},
+       AFCVTSW & obj.AMask:  {enc: rIFEncoding},
+       AFCVTSL & obj.AMask:  {enc: rIFEncoding},
+       AFCVTWUS & obj.AMask: {enc: rFIEncoding},
+       AFCVTLUS & obj.AMask: {enc: rFIEncoding},
+       AFCVTSWU & obj.AMask: {enc: rIFEncoding},
+       AFCVTSLU & obj.AMask: {enc: rIFEncoding},
+       AFSGNJS & obj.AMask:  {enc: rFFFEncoding},
+       AFSGNJNS & obj.AMask: {enc: rFFFEncoding},
+       AFSGNJXS & obj.AMask: {enc: rFFFEncoding},
+       AFMVXW & obj.AMask:   {enc: rFIEncoding},
+       AFMVWX & obj.AMask:   {enc: rIFEncoding},
 
        // 11.8: Single-Precision Floating-Point Compare Instructions
-       AFEQS & obj.AMask: rFFIEncoding,
-       AFLTS & obj.AMask: rFFIEncoding,
-       AFLES & obj.AMask: rFFIEncoding,
+       AFEQS & obj.AMask: {enc: rFFIEncoding},
+       AFLTS & obj.AMask: {enc: rFFIEncoding},
+       AFLES & obj.AMask: {enc: rFFIEncoding},
 
        // 11.9: Single-Precision Floating-Point Classify Instruction
-       AFCLASSS & obj.AMask: rFIEncoding,
+       AFCLASSS & obj.AMask: {enc: rFIEncoding},
 
        // 12.3: Double-Precision Load and Store Instructions
-       AFLD & obj.AMask: iFEncoding,
-       AFSD & obj.AMask: sFEncoding,
+       AFLD & obj.AMask: {enc: iFEncoding},
+       AFSD & obj.AMask: {enc: sFEncoding},
 
        // 12.4: Double-Precision Floating-Point Computational Instructions
-       AFADDD & obj.AMask:   rFFFEncoding,
-       AFSUBD & obj.AMask:   rFFFEncoding,
-       AFMULD & obj.AMask:   rFFFEncoding,
-       AFDIVD & obj.AMask:   rFFFEncoding,
-       AFMIND & obj.AMask:   rFFFEncoding,
-       AFMAXD & obj.AMask:   rFFFEncoding,
-       AFSQRTD & obj.AMask:  rFFFEncoding,
-       AFMADDD & obj.AMask:  rFFFFEncoding,
-       AFMSUBD & obj.AMask:  rFFFFEncoding,
-       AFNMSUBD & obj.AMask: rFFFFEncoding,
-       AFNMADDD & obj.AMask: rFFFFEncoding,
+       AFADDD & obj.AMask:   {enc: rFFFEncoding},
+       AFSUBD & obj.AMask:   {enc: rFFFEncoding},
+       AFMULD & obj.AMask:   {enc: rFFFEncoding},
+       AFDIVD & obj.AMask:   {enc: rFFFEncoding},
+       AFMIND & obj.AMask:   {enc: rFFFEncoding},
+       AFMAXD & obj.AMask:   {enc: rFFFEncoding},
+       AFSQRTD & obj.AMask:  {enc: rFFFEncoding},
+       AFMADDD & obj.AMask:  {enc: rFFFFEncoding},
+       AFMSUBD & obj.AMask:  {enc: rFFFFEncoding},
+       AFNMSUBD & obj.AMask: {enc: rFFFFEncoding},
+       AFNMADDD & obj.AMask: {enc: rFFFFEncoding},
 
        // 12.5: Double-Precision Floating-Point Conversion and Move Instructions
-       AFCVTWD & obj.AMask:  rFIEncoding,
-       AFCVTLD & obj.AMask:  rFIEncoding,
-       AFCVTDW & obj.AMask:  rIFEncoding,
-       AFCVTDL & obj.AMask:  rIFEncoding,
-       AFCVTWUD & obj.AMask: rFIEncoding,
-       AFCVTLUD & obj.AMask: rFIEncoding,
-       AFCVTDWU & obj.AMask: rIFEncoding,
-       AFCVTDLU & obj.AMask: rIFEncoding,
-       AFCVTSD & obj.AMask:  rFFEncoding,
-       AFCVTDS & obj.AMask:  rFFEncoding,
-       AFSGNJD & obj.AMask:  rFFFEncoding,
-       AFSGNJND & obj.AMask: rFFFEncoding,
-       AFSGNJXD & obj.AMask: rFFFEncoding,
-       AFMVXD & obj.AMask:   rFIEncoding,
-       AFMVDX & obj.AMask:   rIFEncoding,
+       AFCVTWD & obj.AMask:  {enc: rFIEncoding},
+       AFCVTLD & obj.AMask:  {enc: rFIEncoding},
+       AFCVTDW & obj.AMask:  {enc: rIFEncoding},
+       AFCVTDL & obj.AMask:  {enc: rIFEncoding},
+       AFCVTWUD & obj.AMask: {enc: rFIEncoding},
+       AFCVTLUD & obj.AMask: {enc: rFIEncoding},
+       AFCVTDWU & obj.AMask: {enc: rIFEncoding},
+       AFCVTDLU & obj.AMask: {enc: rIFEncoding},
+       AFCVTSD & obj.AMask:  {enc: rFFEncoding},
+       AFCVTDS & obj.AMask:  {enc: rFFEncoding},
+       AFSGNJD & obj.AMask:  {enc: rFFFEncoding},
+       AFSGNJND & obj.AMask: {enc: rFFFEncoding},
+       AFSGNJXD & obj.AMask: {enc: rFFFEncoding},
+       AFMVXD & obj.AMask:   {enc: rFIEncoding},
+       AFMVDX & obj.AMask:   {enc: rIFEncoding},
 
        // 12.6: Double-Precision Floating-Point Compare Instructions
-       AFEQD & obj.AMask: rFFIEncoding,
-       AFLTD & obj.AMask: rFFIEncoding,
-       AFLED & obj.AMask: rFFIEncoding,
+       AFEQD & obj.AMask: {enc: rFFIEncoding},
+       AFLTD & obj.AMask: {enc: rFFIEncoding},
+       AFLED & obj.AMask: {enc: rFFIEncoding},
 
        // 12.7: Double-Precision Floating-Point Classify Instruction
-       AFCLASSD & obj.AMask: rFIEncoding,
+       AFCLASSD & obj.AMask: {enc: rFIEncoding},
 
        // Privileged ISA
 
        // 3.2.1: Environment Call and Breakpoint
-       AECALL & obj.AMask:  iIIEncoding,
-       AEBREAK & obj.AMask: iIIEncoding,
+       AECALL & obj.AMask:  {enc: iIIEncoding},
+       AEBREAK & obj.AMask: {enc: iIIEncoding},
 
        //
        // RISC-V Bit-Manipulation ISA-extensions (1.0)
        //
 
        // 1.1: Address Generation Instructions (Zba)
-       AADDUW & obj.AMask:    rIIIEncoding,
-       ASH1ADD & obj.AMask:   rIIIEncoding,
-       ASH1ADDUW & obj.AMask: rIIIEncoding,
-       ASH2ADD & obj.AMask:   rIIIEncoding,
-       ASH2ADDUW & obj.AMask: rIIIEncoding,
-       ASH3ADD & obj.AMask:   rIIIEncoding,
-       ASH3ADDUW & obj.AMask: rIIIEncoding,
-       ASLLIUW & obj.AMask:   iIIEncoding,
+       AADDUW & obj.AMask:    {enc: rIIIEncoding, ternary: true},
+       ASH1ADD & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ASH1ADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true},
+       ASH2ADD & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ASH2ADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true},
+       ASH3ADD & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ASH3ADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true},
+       ASLLIUW & obj.AMask:   {enc: iIIEncoding, ternary: true},
 
        // 1.2: Basic Bit Manipulation (Zbb)
-       AANDN & obj.AMask:  rIIIEncoding,
-       ACLZ & obj.AMask:   rIIEncoding,
-       ACLZW & obj.AMask:  rIIEncoding,
-       ACPOP & obj.AMask:  rIIEncoding,
-       ACPOPW & obj.AMask: rIIEncoding,
-       ACTZ & obj.AMask:   rIIEncoding,
-       ACTZW & obj.AMask:  rIIEncoding,
-       AMAX & obj.AMask:   rIIIEncoding,
-       AMAXU & obj.AMask:  rIIIEncoding,
-       AMIN & obj.AMask:   rIIIEncoding,
-       AMINU & obj.AMask:  rIIIEncoding,
-       AORN & obj.AMask:   rIIIEncoding,
-       ASEXTB & obj.AMask: rIIEncoding,
-       ASEXTH & obj.AMask: rIIEncoding,
-       AXNOR & obj.AMask:  rIIIEncoding,
-       AZEXTH & obj.AMask: rIIEncoding,
+       AANDN & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       ACLZ & obj.AMask:   {enc: rIIEncoding},
+       ACLZW & obj.AMask:  {enc: rIIEncoding},
+       ACPOP & obj.AMask:  {enc: rIIEncoding},
+       ACPOPW & obj.AMask: {enc: rIIEncoding},
+       ACTZ & obj.AMask:   {enc: rIIEncoding},
+       ACTZW & obj.AMask:  {enc: rIIEncoding},
+       AMAX & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AMAXU & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AMIN & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AMINU & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AORN & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       ASEXTB & obj.AMask: {enc: rIIEncoding},
+       ASEXTH & obj.AMask: {enc: rIIEncoding},
+       AXNOR & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AZEXTH & obj.AMask: {enc: rIIEncoding},
 
        // 1.3: Bitwise Rotation (Zbb)
-       AROL & obj.AMask:   rIIIEncoding,
-       AROLW & obj.AMask:  rIIIEncoding,
-       AROR & obj.AMask:   rIIIEncoding,
-       ARORI & obj.AMask:  iIIEncoding,
-       ARORIW & obj.AMask: iIIEncoding,
-       ARORW & obj.AMask:  rIIIEncoding,
-       AORCB & obj.AMask:  iIIEncoding,
-       AREV8 & obj.AMask:  iIIEncoding,
+       AROL & obj.AMask:   {enc: rIIIEncoding, ternary: true},
+       AROLW & obj.AMask:  {enc: rIIIEncoding, ternary: true},
+       AROR & obj.AMask:   {enc: rIIIEncoding, immForm: ARORI, ternary: true},
+       ARORI & obj.AMask:  {enc: iIIEncoding, ternary: true},
+       ARORIW & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ARORW & obj.AMask:  {enc: rIIIEncoding, immForm: ARORIW, ternary: true},
+       AORCB & obj.AMask:  {enc: iIIEncoding},
+       AREV8 & obj.AMask:  {enc: iIIEncoding},
 
        // 1.5: Single-bit Instructions (Zbs)
-       ABCLR & obj.AMask:  rIIIEncoding,
-       ABCLRI & obj.AMask: iIIEncoding,
-       ABEXT & obj.AMask:  rIIIEncoding,
-       ABEXTI & obj.AMask: iIIEncoding,
-       ABINV & obj.AMask:  rIIIEncoding,
-       ABINVI & obj.AMask: iIIEncoding,
-       ABSET & obj.AMask:  rIIIEncoding,
-       ABSETI & obj.AMask: iIIEncoding,
+       ABCLR & obj.AMask:  {enc: rIIIEncoding, immForm: ABCLRI, ternary: true},
+       ABCLRI & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ABEXT & obj.AMask:  {enc: rIIIEncoding, immForm: ABEXTI, ternary: true},
+       ABEXTI & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ABINV & obj.AMask:  {enc: rIIIEncoding, immForm: ABINVI, ternary: true},
+       ABINVI & obj.AMask: {enc: iIIEncoding, ternary: true},
+       ABSET & obj.AMask:  {enc: rIIIEncoding, immForm: ABSETI, ternary: true},
+       ABSETI & obj.AMask: {enc: iIIEncoding, ternary: true},
 
        // Escape hatch
-       AWORD & obj.AMask: rawEncoding,
+       AWORD & obj.AMask: {enc: rawEncoding},
 
        // Pseudo-operations
-       obj.AFUNCDATA: pseudoOpEncoding,
-       obj.APCDATA:   pseudoOpEncoding,
-       obj.ATEXT:     pseudoOpEncoding,
-       obj.ANOP:      pseudoOpEncoding,
-       obj.ADUFFZERO: pseudoOpEncoding,
-       obj.ADUFFCOPY: pseudoOpEncoding,
-       obj.APCALIGN:  pseudoOpEncoding,
+       obj.AFUNCDATA: {enc: pseudoOpEncoding},
+       obj.APCDATA:   {enc: pseudoOpEncoding},
+       obj.ATEXT:     {enc: pseudoOpEncoding},
+       obj.ANOP:      {enc: pseudoOpEncoding},
+       obj.ADUFFZERO: {enc: pseudoOpEncoding},
+       obj.ADUFFCOPY: {enc: pseudoOpEncoding},
+       obj.APCALIGN:  {enc: pseudoOpEncoding},
 }
 
-// encodingForAs returns the encoding for an obj.As.
-func encodingForAs(as obj.As) (encoding, error) {
+// instructionDataForAs returns the instruction data for an obj.As.
+func instructionDataForAs(as obj.As) (*instructionData, error) {
        if base := as &^ obj.AMask; base != obj.ABaseRISCV && base != 0 {
-               return badEncoding, fmt.Errorf("encodingForAs: not a RISC-V instruction %s", as)
+               return nil, fmt.Errorf("%v is not a RISC-V instruction", as)
        }
        asi := as & obj.AMask
-       if int(asi) >= len(encodings) {
-               return badEncoding, fmt.Errorf("encodingForAs: bad RISC-V instruction %s", as)
+       if int(asi) >= len(instructions) {
+               return nil, fmt.Errorf("bad RISC-V instruction %v", as)
+       }
+       return &instructions[asi], nil
+}
+
+// encodingForAs returns the encoding for an obj.As.
+func encodingForAs(as obj.As) (*encoding, error) {
+       insData, err := instructionDataForAs(as)
+       if err != nil {
+               return &badEncoding, err
        }
-       enc := encodings[asi]
-       if enc.validate == nil {
-               return badEncoding, fmt.Errorf("encodingForAs: no encoding for instruction %s", as)
+       if insData.enc.validate == nil {
+               return &badEncoding, fmt.Errorf("no encoding for instruction %s", as)
        }
-       return enc, nil
+       return &insData.enc, nil
 }
 
 type instruction struct {