aboutsummaryrefslogtreecommitdiffstats
path: root/sys/align.go
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2017-01-10 16:45:52 +0100
committerAndrey Konovalov <andreyknvl@google.com>2017-01-17 13:25:33 +0100
commit54e0cede4384b7c1655f9183577bfccc11d9a7d5 (patch)
tree68e1f734a5e82ac7ecbe2968942d9983650ed8f8 /sys/align.go
parentf6c7b90523285663e51fc6804ae2c0c171bb390c (diff)
prog: add bitfields to templates
Now it's possible to use `int32:18` to denote a bitfield of size 18 as a struct field. This fixes #72.
Diffstat (limited to 'sys/align.go')
-rw-r--r--sys/align.go69
1 files changed, 60 insertions, 9 deletions
diff --git a/sys/align.go b/sys/align.go
index 1b1ea66ac..8b9e1a3c2 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -3,6 +3,10 @@
package sys
+import (
+ "fmt"
+)
+
func initAlign() {
var rec func(t Type)
rec = func(t Type) {
@@ -17,6 +21,7 @@ func initAlign() {
for _, f := range t1.Fields {
rec(f)
}
+ markBitfields(t1)
addAlignment(t1)
}
case *UnionType:
@@ -31,6 +36,46 @@ func initAlign() {
}
}
+func setBitfieldOffset(t Type, offset uintptr, last bool) {
+ switch t1 := t.(type) {
+ case *IntType:
+ t1.BitfieldOff = offset
+ t1.BitfieldLst = last
+ case *ConstType:
+ t1.BitfieldOff = offset
+ t1.BitfieldLst = last
+ case *LenType:
+ t1.BitfieldOff = offset
+ t1.BitfieldLst = last
+ case *FlagsType:
+ t1.BitfieldOff = offset
+ t1.BitfieldLst = last
+ case *ProcType:
+ t1.BitfieldOff = offset
+ t1.BitfieldLst = last
+ default:
+ panic(fmt.Sprintf("type %+v can't be a bitfield", t1))
+ }
+}
+
+func markBitfields(t *StructType) {
+ var bfOffset uintptr
+ for i, f := range t.Fields {
+ if f.BitfieldLength() == 0 {
+ continue
+ }
+ off, last := bfOffset, false
+ bfOffset += f.BitfieldLength()
+ if i == len(t.Fields)-1 || // Last bitfield in a group, if last field of the struct...
+ t.Fields[i+1].BitfieldLength() == 0 || // or next field is not a bitfield...
+ f.Size() != t.Fields[i+1].Size() || // or next field is of different size...
+ bfOffset+t.Fields[i+1].BitfieldLength() > f.Size()*8 { // or next field does not fit into the current group.
+ last, bfOffset = true, 0
+ }
+ setBitfieldOffset(f, off, last)
+ }
+}
+
func addAlignment(t *StructType) {
if t.packed {
return
@@ -43,10 +88,13 @@ func addAlignment(t *StructType) {
if align < a {
align = a
}
- if off%a != 0 {
- pad := a - off%a
- off += pad
- fields = append(fields, makePad(pad))
+ if i > 0 && (t.Fields[i-1].BitfieldLength() == 0 || t.Fields[i-1].BitfieldLast()) {
+ // Append padding if the last field is not a bitfield or it's the last bitfield in a set.
+ if off%a != 0 {
+ pad := a - off%a
+ off += pad
+ fields = append(fields, makePad(pad))
+ }
}
fields = append(fields, f)
if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
@@ -58,7 +106,8 @@ func addAlignment(t *StructType) {
if varLen && i != len(t.Fields)-1 {
panic("embed array in middle of a struct")
}
- if !varLen {
+ if (f.BitfieldLength() == 0 || f.BitfieldLast()) && !varLen {
+ // Increase offset if the current field is not a bitfield or it's the last bitfield in a set.
off += f.Size()
}
}
@@ -72,9 +121,11 @@ func addAlignment(t *StructType) {
func makePad(sz uintptr) Type {
return &ConstType{
- TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
- TypeSize: sz,
- Val: 0,
- IsPad: true,
+ IntTypeCommon: IntTypeCommon{
+ TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
+ TypeSize: sz,
+ },
+ Val: 0,
+ IsPad: true,
}
}