diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2017-01-10 16:45:52 +0100 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@google.com> | 2017-01-17 13:25:33 +0100 |
| commit | 54e0cede4384b7c1655f9183577bfccc11d9a7d5 (patch) | |
| tree | 68e1f734a5e82ac7ecbe2968942d9983650ed8f8 /sys/align.go | |
| parent | f6c7b90523285663e51fc6804ae2c0c171bb390c (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.go | 69 |
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, } } |
