feat: optimize C extensions#1814
Conversation
Add 2 new attributes to instruction schema: 1. `add`: Used to adjust operand value by adding an integer to binary value. Useful for describing x8-x15 registers in C extensions. 2. `implicit`: Used to hint that the instruction is using an operand without explicitly allocating a field in the encoding. Useful for describing sp-/ra-relative instructions in C extensions.
ed1337f to
d1b4718
Compare
|
This has some commonalities with #1532. @ThinkOpenly, take a look and see what you think about any overlap. |
|
Didn't notice about the ongoing refactor in #1527. Feel free to close this one. |
ThinkOpenly
left a comment
There was a problem hiding this comment.
Thank you for submitting this PR!
I suggest creating a separate PR with the bug fixes. That's an easy objective review which I expect would be merged quickly.
Aliases are probably fine and could go in a separate PR to get them reviewed/merged relatively quickly.
I have reservations for "add" described in a review comment.
I think "implicit" is probably needed, but associating it with operands instead of opcode fields is perhaps a better approach, and maybe it should be carried in #1527.
| "add": { | ||
| "type": "integer", | ||
| "default": 0, | ||
| "description": "Amount the field should be added before use, e.g., source register is ranged between 8 to 15, add is 8" | ||
| }, |
There was a problem hiding this comment.
IMHO, while this is useful in isolation, it presents some challenges by only solving one arithmetic issue, and leaves others (like additional operators and "precedence") unresolved. In #1527, I'm trying to lump all of the operand<->field transformations into new, general encode() and decode() methods. These are IDL, which allows most any transformation, but also complicates their use. Would these methods accommodate your use-case well enough?
There was a problem hiding this comment.
True. encode() and decode() should be enough for this. With these 2 functions, I think left_shift() could be merged into them, too.
There was a problem hiding this comment.
I think
left_shift()could be merged into them, too.
True.
| "implicit": { | ||
| "type": "integer", | ||
| "description": "Implicitly use an operand with the value" | ||
| }, |
There was a problem hiding this comment.
I think we do need something like this. You've applied it to opcode fields, but the variable fields are by definition, variable, and "implicit" by definition is not really variable, so it's not a great fit.
The implicit content seems to be more closely associated with operands (which is the approach in #1527): the input to the instruction.
It is a bit subjective.
Either way, I think it needs to be generalized to at least cover:
- stack pointer (as you do here)
- program counter (which can't be represented as an "integer" as is done here)
- the unmentioned register in register pair usage (this is awkward because it depends on one of the non-implicit operands, so we'll need a way to represent that). I guess this case is sort of implicit and variable.
There was a problem hiding this comment.
I'm fine with moving it to the fields other than variable. To integrate with new operand field, I have some ideas:
- Implicit operand (with new implicit attribute)
$schema: "operand_schema.json#"
kind: operand
name: sp-implicit
data:
$inherits: operand/xs.yaml#/data
possible_values: [2]
implicit: true- Name with multiple of actual registers
- Introduce name to values mapping
- The name could be an array for ABI name swapping
- The values can be an array with all included values
$schema: "operand_schema.json#"
kind: operand
name: xs-pair
data:
type: reg_pair
name: reg_pair_xs
possible_values:
- $inherits: operand/xs.yaml#/data
name: ["x0", "zero"]
values: [0, 1]
- $inherits: operand/xs.yaml#/data
name: ["x2", "sp"]
values: [2, 3]
- $inherits: operand/xs.yaml#/data
name: ["x4", "tp"]
values: [4, 5]
...There was a problem hiding this comment.
Good ideas. Feel free to post them in #1527. (Or, I'll copy them there if you wish.)
There was a problem hiding this comment.
Thanks! I'll copy them to the PR.
| - name: xd | ||
| location: 11-7 | ||
| not: 0 | ||
| alias: xs1 |
There was a problem hiding this comment.
I didn't even know UDB had this feature. Are you adding this just to match the ISA manual? Do you have a use-case for it? Just curious. It seems pretty harmless, so no objections.
There was a problem hiding this comment.
Yes, just to match ISA manual. But I think it also beneficial for someone who wants to use this database for compiler scheduling or RTL decoder generation. For these purposes, you must know these operands are used for both source and destination. I think with new operand system. We could just create a new xsdc operand for this purpose.
$schema: "operand_schema.json#"
kind: operand
name: xsdc
data:
$inherits: operand/xdc.yaml#/data
source: trueThere was a problem hiding this comment.
Agree. I didn't yet model a source/destination register, but I think the capability is already there (as in your example).
| - name: imm | ||
| location: 12|6-2 | ||
| not: 0 | ||
| sign_extend: true |
There was a problem hiding this comment.
These sign_extend fixes should probably go in their own PR, since they are not subjective and we could get them merged much faster.
There was a problem hiding this comment.
Sure. I'll file another PR for this in a few days.
Edit: A few minutes actually 😅
| - name: xd | ||
| location: 11-7 |
There was a problem hiding this comment.
I'm guessing this fails to validate properly, as this new "variable" is hardcoded to 2 ("00010") in the "match" string just above. Try running ./do gen:resolved_arch.
An open question, perhaps: where is the syntax defined for c.addi16sp? Is is c.addi16sp sp, imm or c.addi16sp imm? (Why would "sp" need to be an actual operand when it's attached to the mnemonic?
There was a problem hiding this comment.
I forget to change mask "00010" to "-----". I think two approaches are valid:
- Keep mask as is, but add implicit operand to this instruction
- Change mask to "-----" and add a new operand which only has 1 possible value, i.e., 2.
I don't think c.addi16sp is defined in any official document. I think we use this syntax because official GCC is using it: riscv-collab/riscv-gnu-toolchain#372
There was a problem hiding this comment.
Oh. Thanks for digging up that (very sad) reference. 😕 Not a choice I would've made.
There was a problem hiding this comment.
This is a strange case, indeed. Making the field a "variable with only one possible value" seems a little odd. Making "sp" an implicit operand when it is explicitly there also seems odd. This instruction is odd.
I could be swayed either way, but prefer the "variable with one possible value", if you want to update the mask.
There was a problem hiding this comment.
I prefer the "variable with one possible value", too. But I want to use new operand system to do it instead of handcoding 0-31 exclude 2.
There was a problem hiding this comment.
I think we should do both the field and the operand. We do want to properly constrain the field so that simple decode won't match (if the purpose of the decode was to execute rather than disassemble, for example).
| description: | | ||
| C.MV (move register) performs copy of the data in register xs2 to register xd | ||
| C.MV expands to addi xd, x0, xs2. | ||
| C.MV expands to add xd, x0, xs2. |
There was a problem hiding this comment.
Another bug fix for a separate PR.
| if effective_xlen.nil? | ||
| if defined_in_base?(32) | ||
| encoding(32).decode_variables.each do |d| | ||
| next if d.size.zero? |
There was a problem hiding this comment.
I'm not a Ruby expert... is this ignoring variables which are "implicit"?
There was a problem hiding this comment.
Yes, otherwise the execution of Ruby script will fail. If the implicit will be added to operands instead of fields, I think this change should be discarded.
| # implicitly use an operand with the value | ||
| attr_reader :implicit | ||
|
|
||
| def implicit? = @implicit != 0 |
There was a problem hiding this comment.
You have an use of implicit: 0, in c.beqz above. What does this do?
There was a problem hiding this comment.
I want to use this field to skip references to variable with implicit attribute. However, I eventually used checks like if @encoding_fields.empty? and if !field_data["location"].nil?. These lines should be removed.
| return [] if @encoding_fields.empty? | ||
|
|
There was a problem hiding this comment.
is this needed because of the changes in this PR?
There was a problem hiding this comment.
Yes. @encoding_fields may be empty for implicit variables. If we have consensuses that implicit should be add in operand instead of variable, all the changes in this Ruby file can be discarded.
|
If everything is addressed, I would like to close this PR and wait for the new operand system. What do you think? |
How did you want to handle the operand alias names that you added here? |
Extract bug fixes from riscv#1814 .
Add 2 new attributes to instruction schema:
add: Used to adjust operand value by adding an integer to binary value. Useful for describing x8-x15 registers in C extensions.implicit: Used to hint that the instruction is using an operand without explicitly allocating a field in the encoding. Useful for describing sp-/ra-relative instructions in C extensions.Though
implicitis not used by current riscv-unified-db, it may be useful for the library relied on it.Other notable changes:
inst_schema.jsonversion is bumped to v0.3sign_extenddefault to false, I have added it to C instructions required signed-extend.aliasforrd'/rs1'operands.notarray size is more than its reversion, use it instead.