forked from Imagelibrary/seL4
bfgen: add field_ptr(align) name size
Add the new block command
field_ptr(align) name size
as an abbreviation for
padding size - canonical + align
field_high name canonical - align
The (align) part is optional. If left out, align is 0.
This is useful for removing #ifdefs for pointer storage that are trying
to achieve constant size over different canonical bit representations.
Signed-off-by: Gerwin Klein <gerwin.klein@proofcraft.systems>
This commit is contained in:
@@ -252,6 +252,100 @@ that stores 36 bits (on a 64 bit base platform with 48 significant bits).
|
||||
|
||||
[Architecture Parameters]: #architecture-parameters-and-canonical-pointers
|
||||
|
||||
### Field Ptr
|
||||
|
||||
Often we want to store a pointer with some known alignment (i.e. not all bits
|
||||
need to be stored), and pad out to a specific overall field size.
|
||||
The `field_ptr` abbreviation makes this convenient.
|
||||
|
||||
```bf_gen
|
||||
block some_block {
|
||||
...
|
||||
field_ptr(align) some_name size
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
stands for "a field `some_name` for a pointer with alignment `align` padded out
|
||||
to `size`". It is an abbreviation for
|
||||
|
||||
```bf_gen
|
||||
block some_block {
|
||||
...
|
||||
padding size - canonical_size + align
|
||||
field_high some_name canonical_size - align
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `(align)` parameter can be left out and is equivalent to `field_ptr(0)`. The
|
||||
constant `canonical_size` in the expression above stands for the number of
|
||||
significant bits (the canonical size) of a pointer according to the most recent
|
||||
`base` definition. For example the long form
|
||||
|
||||
```bf_gen
|
||||
base 64(48,1)
|
||||
|
||||
block mdb_node {
|
||||
padding 16
|
||||
field_high mdbNext 46
|
||||
field mdbRevocable 1
|
||||
field mdbFirstBadged 1
|
||||
|
||||
field mdbPrev 64
|
||||
}
|
||||
```
|
||||
|
||||
can be written more concisely as
|
||||
|
||||
```bf_gen
|
||||
base 64(48,1)
|
||||
|
||||
block mdb_node {
|
||||
field_ptr(2) mdbNext 62
|
||||
field mdbRevocable 1
|
||||
field mdbFirstBadged 1
|
||||
|
||||
field mdbPrev 64
|
||||
}
|
||||
```
|
||||
|
||||
The `field_ptr` abbreviation is especially useful for sharing the same block
|
||||
definition under different `base` declarations, e.g. for different
|
||||
architectures. For example, with a `base 64(39,1)` the `field_ptr` definition
|
||||
text remains the same, but expands to a different `field_high`/`padding`
|
||||
combination that achieves the same overall width:
|
||||
|
||||
```bf_gen
|
||||
base 64(39,1)
|
||||
|
||||
block mdb_node {
|
||||
padding 25
|
||||
field_high mdbNext 37
|
||||
field mdbRevocable 1
|
||||
field mdbFirstBadged 1
|
||||
|
||||
field mdbPrev 64
|
||||
}
|
||||
```
|
||||
|
||||
can be also be written as
|
||||
|
||||
```bf_gen
|
||||
base 64(39,1)
|
||||
|
||||
block mdb_node {
|
||||
field_ptr(2) mdbNext 62
|
||||
field mdbRevocable 1
|
||||
field mdbFirstBadged 1
|
||||
|
||||
field mdbPrev 64
|
||||
}
|
||||
```
|
||||
|
||||
This means the same block definition can produce a constant field size while
|
||||
correctly accommodating multiple different `base` configurations.
|
||||
|
||||
### Visible Field Order
|
||||
|
||||
Sometimes it is useful for the constructor to take its arguments in a particular
|
||||
@@ -624,7 +718,10 @@ canonical_spec ::= "(" expr "," ("0"|"1") ")"
|
||||
block ::= "block" IDENT visible_order_spec_opt? "{" fields "}"
|
||||
visible_order_spec_opt ::= "(" visible_order_spec? ")"
|
||||
visible_order_spec ::= IDENT ("," IDENT)*
|
||||
fields ::= ( "field" IDENT expr | "field_high" IDENT expr | "padding" expr )*
|
||||
fields ::= ( "field" IDENT expr |
|
||||
"field_high" IDENT expr |
|
||||
"field_ptr" ("(" expr ")")? IDENT expr |
|
||||
"padding" expr )*
|
||||
|
||||
tagged_union ::= "tagged_union" IDENT IDENT tag_slices? "{" masks tags "}"
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ TYPES = {
|
||||
|
||||
# Parser
|
||||
|
||||
reserved = ('BLOCK', 'BASE', 'FIELD', 'FIELD_HIGH', 'MASK', 'PADDING',
|
||||
'TAGGED_UNION', 'TAG')
|
||||
reserved = ('BLOCK', 'BASE', 'FIELD', 'FIELD_HIGH', 'FIELD_PTR', 'MASK',
|
||||
'PADDING', 'TAGGED_UNION', 'TAG')
|
||||
|
||||
tokens = reserved + ('IDENTIFIER', 'INTLIT', 'LBRACE', 'RBRACE',
|
||||
'LPAREN', 'RPAREN', 'COMMA', 'PLUS', 'MINUS',
|
||||
@@ -235,6 +235,21 @@ def p_fields_field_high(t):
|
||||
t[0] = t[1] + [(t[3], t[4], True)]
|
||||
|
||||
|
||||
def p_fields_field_ptr(t):
|
||||
"""fields : fields FIELD_PTR IDENTIFIER int_expr"""
|
||||
padding_size = ('-', t[4], "canonical_size")
|
||||
field_size = "canonical_size"
|
||||
t[0] = t[1] + [(None, padding_size, False), (t[3], field_size, True)]
|
||||
|
||||
|
||||
def p_fields_field_ptr_align(t):
|
||||
"""fields : fields FIELD_PTR LPAREN int_expr RPAREN IDENTIFIER int_expr"""
|
||||
align = t[4]
|
||||
padding_size = ('+', ('-', t[7], "canonical_size"), align) # size - canonical_size + align
|
||||
field_size = ('-', "canonical_size", align)
|
||||
t[0] = t[1] + [(None, padding_size, False), (t[6], field_size, True)]
|
||||
|
||||
|
||||
def p_fields_padding(t):
|
||||
"""fields : fields PADDING int_expr"""
|
||||
t[0] = t[1] + [(None, t[3], False)]
|
||||
@@ -2445,6 +2460,14 @@ class Block:
|
||||
offset = self.size
|
||||
|
||||
for _name, _size, _high in self.fields:
|
||||
if _name:
|
||||
if _size <= 0:
|
||||
raise ValueError(f"Fields must have positive size, but {_name} "
|
||||
f"in block {self.name} has size {_size}")
|
||||
else:
|
||||
if _size < 0:
|
||||
raise ValueError(f"Padding must be non-negative, but padding "
|
||||
f"in block {self.name} has size {_size}")
|
||||
offset -= _size
|
||||
if _name is not None:
|
||||
if visible_order is None:
|
||||
|
||||
Reference in New Issue
Block a user