Skip to content

Commit 5291a50

Browse files
authored
feat(idl): add widening operators in IDL (#736)
Adds four widening `Bits<N>` operators in IDL: * `` `<< `` : widening shift left. If the shift amount is a constant, the result is `Bits<N + shamt>`. Otherwise, the result type is `Bits<Infinite>`. * `` `* ``: widening multiply. The result type when multiplying `Bits<N>` * `Bits<M>` is `Bits<N + M>` * `` `+ ``: widening add. The result type when adding `Bits<N>` + `Bits<M>` is `Bits<max(M, N) + 1>` * `` `- ``: widening sub. The result type when subtracting `Bits<N> + Bits<M>` is `Bits<max(M, N) + 1>`.
1 parent 34157aa commit 5291a50

File tree

10 files changed

+391
-98
lines changed

10 files changed

+391
-98
lines changed

arch/csr/H/vsatp.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ fields:
9898
}
9999
} else {
100100
XReg shamt = ((xlen() == 32) || (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32))) ? 9 : 16;
101-
XReg all_ones = ((1 << shamt) - 1);
102-
XReg largest_allowed_asid = (1 << shamt) - 1;
101+
XReg all_ones = ((MXLEN'1 << shamt) - 1);
102+
XReg largest_allowed_asid = (MXLEN'1 << shamt) - 1;
103103
104104
if (csr_value.ASID == all_ones) {
105105
# the specification states that if all 1's are written to the ASID field, then

arch/csr/satp.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ fields:
125125
}
126126
} else {
127127
XReg shamt = (xlen() == 32 || (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32))) ? 9 : 16;
128-
XReg all_ones = ((1 << shamt) - 1);
129-
XReg largest_allowed_asid = (1 << shamt) - 1;
128+
XReg all_ones = ((MXLEN'1 << shamt) - 1);
129+
XReg largest_allowed_asid = (MXLEN'1 << shamt) - 1;
130130
131131
if (csr_value.ASID == all_ones) {
132132
# the specification states that if all 1's are written to the ASID field, then

arch/inst/F/fclass.s.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,24 @@ operation(): |
5454
if (is_sp_neg_inf?(sp_value)) {
5555
X[rd] = 1 << 0;
5656
} else if (is_sp_neg_norm?(sp_value)) {
57-
X[rd] = 1 << 1;
57+
X[rd] = 1 `<< 1;
5858
} else if (is_sp_neg_subnorm?(sp_value)) {
59-
X[rd] = 1 << 2;
59+
X[rd] = 1 `<< 2;
6060
} else if (is_sp_neg_zero?(sp_value)) {
61-
X[rd] = 1 << 3;
61+
X[rd] = 1 `<< 3;
6262
} else if (is_sp_pos_zero?(sp_value)) {
63-
X[rd] = 1 << 4;
63+
X[rd] = 1 `<< 4;
6464
} else if (is_sp_pos_subnorm?(sp_value)) {
65-
X[rd] = 1 << 5;
65+
X[rd] = 1 `<< 5;
6666
} else if (is_sp_pos_norm?(sp_value)) {
67-
X[rd] = 1 << 6;
67+
X[rd] = 1 `<< 6;
6868
} else if (is_sp_pos_inf?(sp_value)) {
69-
X[rd] = 1 << 7;
69+
X[rd] = 1 `<< 7;
7070
} else if (is_sp_signaling_nan?(sp_value)) {
71-
X[rd] = 1 << 8;
71+
X[rd] = 1 `<< 8;
7272
} else {
7373
assert(is_sp_quiet_nan?(sp_value), "Unexpected SP value");
74-
X[rd] = 1 << 9;
74+
X[rd] = 1 `<< 9;
7575
}
7676
7777
# SPDX-SnippetBegin

arch/inst/M/mulh.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ operation(): |
4141
4242
# enlarge and sign extend the sources
4343
Bits<1> rs1_sign_bit = X[rs1][xlen()-1];
44-
Bits<MXLEN*2> src1 = {{xlen(){rs1_sign_bit}}, X[rs1]};
44+
Bits<MXLEN `* 2> src1 = {{xlen(){rs1_sign_bit}}, X[rs1]};
4545
4646
Bits<1> rs2_sign_bit = X[rs2][xlen()-1];
47-
Bits<MXLEN*2> src2 = {{xlen(){rs2_sign_bit}}, X[rs2]};
47+
Bits<MXLEN `* 2> src2 = {{xlen(){rs2_sign_bit}}, X[rs2]};
4848
4949
# grab the high half of the result, and put it in rd
5050
X[rd] = (src1 * src2)[(xlen()*8'd2)-1:xlen()];

arch/isa/globals.isa

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,15 @@ function exception_handling_mode {
314314
# mode is M, the value of medeleg is irrelevant
315315
return PrivilegeMode::M;
316316
} else if (implemented?(ExtensionName::S) && ((mode() == PrivilegeMode::HS) || (mode() == PrivilegeMode::U))) {
317-
if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
317+
if (($bits(CSR[medeleg]) & (MXLEN'1 << $bits(exception_code))) != 0) {
318318
return PrivilegeMode::HS;
319319
} else {
320320
return PrivilegeMode::M;
321321
}
322322
} else {
323323
assert(implemented?(ExtensionName::H) && ((mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::VU)), "Unexpected mode");
324-
if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) {
325-
if (($bits(CSR[hedeleg]) & (1 << $bits(exception_code))) != 0) {
324+
if (($bits(CSR[medeleg]) & (MXLEN'1 << $bits(exception_code))) != 0) {
325+
if (($bits(CSR[hedeleg]) & (MXLEN'1 << $bits(exception_code))) != 0) {
326326
return PrivilegeMode::VS;
327327
} else {
328328
return PrivilegeMode::HS;
@@ -830,7 +830,7 @@ function valid_interrupt_code? {
830830
Returns true if _code_ is a legal interrupt number.
831831
}
832832
body {
833-
if (code > ((1 << $enum_element_size(InterruptCode)) - 1)) {
833+
if (code > ((1 `<< $enum_element_size(InterruptCode)) - 1)) {
834834
# code is too large
835835
return false;
836836
}
@@ -849,7 +849,7 @@ function valid_exception_code? {
849849
Returns true if _code_ is a legal exception number.
850850
}
851851
body {
852-
if (code > ((1 << $enum_element_size(ExceptionCode)) - 1)) {
852+
if (code > ((1 `<< $enum_element_size(ExceptionCode)) - 1)) {
853853
# code is too large
854854
return false;
855855
}
@@ -2083,7 +2083,7 @@ function stage1_page_walk {
20832083
}
20842084

20852085
for (U32 i = (LEVELS - 1); i >= 0; i--) {
2086-
U32 vpn = (vaddr >> (12 + VPN_SIZE*i)) & ((1 << VPN_SIZE) - 1);
2086+
U32 vpn = (vaddr >> (12 + VPN_SIZE*i)) & ((1 `<< VPN_SIZE) - 1);
20872087

20882088
Bits<PA_SIZE> pte_gpaddr = (ppn << 12) + (vpn * (PTESIZE/8));
20892089

backends/cpp_hart_gen/lib/gen_cpp.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,16 +599,20 @@ class BinaryExpressionAst
599599
def gen_cpp(symtab, indent = 0, indent_spaces: 2)
600600
if op == ">>>"
601601
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.sra(#{rhs.gen_cpp(symtab, 0, indent_spaces:)}))"
602-
elsif op == "<<"
602+
elsif op == "`<<"
603603
if rhs.constexpr?(symtab)
604604
# use template form of shift
605605
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.template sll<#{rhs.value(symtab)}>())"
606-
elsif rhs.type(symtab).const?
606+
else
607607
# use widening shift
608608
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.widening_sll(#{rhs.gen_cpp(symtab, 0, indent_spaces:)}))"
609-
else
610-
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)} << #{rhs.gen_cpp(symtab, 0, indent_spaces:)})"
611609
end
610+
elsif op == "`+"
611+
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.widening_add(#{rhs.gen_cpp(symtab, 0, indent_spaces:)}))"
612+
elsif op == "`-"
613+
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.widening_sub(#{rhs.gen_cpp(symtab, 0, indent_spaces:)}))"
614+
elsif op == "`*"
615+
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.widening_mul(#{rhs.gen_cpp(symtab, 0, indent_spaces:)}))"
612616
else
613617
"#{' '*indent}(#{lhs.gen_cpp(symtab, 0, indent_spaces:)} #{op} #{rhs.gen_cpp(symtab, 0, indent_spaces:)})"
614618
end

doc/idl.adoc

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ Binary operators between operands of different bit widths will extend the smalle
414414

415415
The result of a binary operation is signed if both operands are signed; otherwise, the result is unsigned.
416416

417+
[#operators]
417418
.IDL operators in precedence order, with 0 being highest. For an operand `i` (which may be an expression), `L(i)` is the number of bits in `i` and `typeof(i)` is the exact type of `i`
418419
[cols="1,2,3,4"]
419420
|===
@@ -445,9 +446,11 @@ The result of a binary operation is signed if both operands are signed; otherwis
445446
`i` must be a `Bits<N>` type. +
446447
N must be a literal or compile-time constant.
447448

448-
.3+| 6 | `i * j` | `Bits<max(L(i), L(j))>` | Multiply `i` times `j`. +
449+
.4+| 6 | `i * j` | `Bits<max(L(i), L(j))>` | Multiply `i` times `j`. +
449450
The result is the same width as the widest operand. +
450-
The upper half of the multiplication result is discarded (if the upper half is needed, the operands can be widened ahead of the multiplication).
451+
The upper half of the multiplication result is discarded.
452+
453+
| `i \`* j` | `Bits<L(i) + L(j)>` | Widening multiply `i` times `j`.
451454

452455
| `i / j` | `Bits<max(L(i), L(j))>` | Divide `i` by `j`. +
453456
The result is the same width as the widest operand. +
@@ -461,25 +464,22 @@ The result of a binary operation is signed if both operands are signed; otherwis
461464
Division by zero is undefined, and must be avoided.
462465
When `i` and `j` are signed, signed overflow is undefined, and must be avoided.
463466

464-
.2+| 7 | `i + j` | `Bits<max(L(i), L(j))>` | Addition +
467+
.4+| 7 | `i + j` | `Bits<max(L(i), L(j))>` | Addition +
465468
The carry bit is discarded. +
466469
If the carry bit is needed, the operands can be widened prior to addition.
467470

471+
| `i \`+ j` | `Bits<max(L(i), L(j)) + 1>` | Widening Addition
472+
468473
| `i - j` | `Bits<max(L(i), L(j))>` | Subtraction +
469474
The carry bit is discarded. +
470475
If the carry bit is needed, the operands can be widened prior to subtraction.
471476

472-
.3+| 8 | `i << j` a|
473-
[%autowidth]
474-
!===
475-
! When ! Then
476-
! `j` is literal ! `Bits<L(i) + j>`
477-
! `j` is variable ! `typeof(i)`
478-
!===
479-
| Left logical shift. +
480-
When the shift amount is known at compile time, the result is widened to not lose any data. +
481-
When the shift amount is not known at compile time, the shifted bits are discarded.
477+
| `i \`- j` | `Bits<max(L(i), L(j)) + 1>` | Widening Subtraction
482478

479+
.4+| 8 | `i << j` | `typeof(i)` | Left logical shift
480+
| `i \`<< j` | `Bits<L(i) + value(j)>` | Widening left logic shift. +
481+
`j` *must* be known at compile time -- +
482+
otherwise, this is a type error
483483
| `i >> j` | `typeof(i)` | Right logical shift.
484484
| `i >>> j` | `typeof(i)` | Right arithmetic shift.
485485

@@ -607,6 +607,8 @@ Bitfields can be converted to a `Bits<N>` type, where N is the width of the bitf
607607

608608
== Casting
609609

610+
=== Explicit casting
611+
610612
There are four explicit cast operators in IDL: `$signed`, `$bits`, `$enum`, and `$enum_to_a`.
611613

612614
Unsigned Bits<N> values may be cast to signed values using the `$signed` cast operator.
@@ -622,7 +624,7 @@ XReg cmp1 = ($signed(src1) < $signed(src2)) ? 1 : 0; # cmp = 1
622624

623625
The '$bits' cast can convert Enumeration references, Bitfields, and CSRs into a Bits<N> type.
624626
When the casted value is an enumeration reference, the resulting type will be large enough to hold the largest value in the enumeration type, regardless of the specific reference value.
625-
When the casted value is a CSR, the resulting type will the width of the CSR, or the maximum width when a CSR width is dynamic.
627+
When the casted value is a CSR, the resulting type will the width of the CSR, or the maximum width when a CSR width is dynamic (changable at runtime).
626628
When the casted value is a bitfield, the resulting type will be the width of the bitfield.
627629

628630
[source,idl]
@@ -659,6 +661,30 @@ The `$enum_to_a` cast will convert an enumeration type into an array of the enum
659661
$enum_to_a(RoundingMode) # => [0, 1, 2, 3, 4]
660662
----
661663

664+
=== Implicit casting
665+
666+
Operations involving Bits<N> type with different N involve an implicit cast to the larger bitwidth according to xref:operators[xrefstyle=short].
667+
668+
When the Bits<N> type is unsigned, it zero-extends to the larger width.
669+
670+
When the Bits<N> type is signed, it sign-extends to the larger width.
671+
672+
[source,idl]
673+
----
674+
675+
Bits<4> a = 1;
676+
Bits<2> b = 3;
677+
678+
Bits<4> c = a | b; # c = 3
679+
Bits<4> d = a | $signed(b); # d = 0xf
680+
681+
Bits<4> e = a + b; # e = 4
682+
Bits<4> f = a + $signed(b); # f = 0
683+
684+
Bits<4> g = $signed(a) | b; # g = 3
685+
686+
----
687+
662688
== Builtins
663689

664690
IDL provides a several builtins to access implicit machine state or query data structure properties.

0 commit comments

Comments
 (0)