ThinkOpenly / sail-riscv

Sail RISC-V model
Other
11 stars 14 forks source link

Add pseudoinstructions #6

Open ThinkOpenly opened 7 months ago

jriyyya commented 7 months ago

Hi @ThinkOpenly, I wanted to know how this can be done. Is this about creating like a models/riscv_insts_pseudo.sail with definitions for the pseudoinstructions which RISCV might have or is this similar to adding mere definitions in a pre existing file. Can you please elaborate and guide me to understanding this issue .

ThinkOpenly commented 4 months ago

I completely missed this comment until now. Apologies.

It would be nice to have the pseudoinstructions close to where the actual instructions are defined. So, I'm thinking in the same file as the respective instruction. Implementation is an open question. Off the top of my head, I can see another scattered mapping, much like the scattered mapping assembly and associated mapping clause assembly instances for each instruction (or instruction group). A simple string <-> string mapping would suffice for most pseudoinstructions, maybe with some convention to be able to match operands. Something like:

mapping clause pseudo = "mv %rd,%rs" <-> "addi %rd,%rs,0"

[Edit]: Thinking a bit more, these strings should probably make use of the conventions of the assembly clauses and include the use of spc() and sep():

mapping clause pseudo = "mv" @ spc() @ "%rd" @ sep() @ "%rs"
    <-> "addi" @ spc() @ "%rd" @ sep() @ "%rs" @ sep() @ "0"

Unfortunately, there are a lot of odd cases where the mapping from instruction to pseudoinstruction is not straightforward (from RISC-V Unprivileged ISA V20191213, table 25.2):

pseudoinstruction Base Instruction(s) Meaning
la rd, symbol (non-PIC ) auipc rd, delta[31 : 12] + delta[11]
addi rd, rd, delta[11:0]
Load absolute address,
where delta = symbol − pc
la rd, symbol (PIC ) auipc rd, delta[31 : 12] + delta[11]
l{w|d} rd, rd, delta[11:0]
Load absolute address,
where delta = GOT[symbol] − pc

The lack of a 1:1 mapping from instruction to pseudoinstruction makes for another question: to which instruction should the pseudoinstruction be associated? Maybe the association isn't terribly important, and the pseudoinstructions should just go where they best match functionally.

ThinkOpenly commented 2 months ago

A simple string <-> string mapping would suffice for most pseudoinstructions

Sail doesn't support string <-> string mappings.

64 |mapping s2s : string <-> string = { "a" <-> "b" }
   |              ^---------------^
   | Well-formedness check failed for type
   | 
   | 64 |mapping s2s : string <-> string = { "a" <-> "b" }
   |    |              ^---------------^
   |    | Bidirectional types cannot be the same on both sides

I may have found a decent approach. Using an example from the (relatively new) RISC-V Instruction Set Manual Volume I:

zext.w rd, rs1 → add.uw rd, rs1, zero

The basic "4 stanzas" are necessary and reasonably straightforward, and they redirect to the base instruction's implementation where appropriate:

union clause ast = ZEXTW : (regidx, regidx)
mapping clause encdec = ZEXTW(rs1, rd) if extension("Zba") & sizeof(xlen) == 64
  <-> encdec(ZBA_RTYPEUW(reg_name("zero"), rs1, rd, RISCV_ADDUW)) if extension("Zba") & sizeof(xlen) == 64
mapping clause assembly = ZEXTW(rs1, rd)
  <-> "zext.w" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1)
function clause execute (ZEXTW(rs1, rd)) = execute(ZBA_RTYPEUW(reg_name("zero"), rs1, rd, RISCV_ADDUW))

I also thought adding another scattered mapping would make it much easier to associate the pseudoinstruction with its base instruction, and make it very obvious that this was a pseudoinstruction:

val pseudo_of : ast <-> string
scattered mapping pseudo_of
mapping clause pseudo_of = ZEXTW(rs1, rd) <-> "add.uw" ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ "zero"
end pseudo_of

Without this, we'd need to deconstruct whatever is in the execute expression, or maybe find the associated assembly clause, assuming one exists, while making a fair number of assumptions about the syntax of the execute expression.