diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/compiler/gen.go | 108 |
1 files changed, 47 insertions, 61 deletions
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index 6ba312d3c..ff9cb51e2 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -199,9 +199,8 @@ func (ctx *structGen) walkStruct(t *prog.StructType) { varlen = true } } - comp.markBitfields(t.Fields) packed, sizeAttr, alignAttr := comp.parseStructAttrs(structNode) - t.Fields = comp.addAlignment(t.Fields, varlen, packed, alignAttr) + t.Fields = comp.layoutStruct(t.Fields, varlen, packed, alignAttr) t.AlignAttr = alignAttr t.TypeSize = 0 if !varlen { @@ -259,79 +258,44 @@ func (comp *compiler) genStructDesc(res *prog.StructDesc, n *ast.Struct, dir pro } } -func (comp *compiler) markBitfields(fields []prog.Type) { - var bfOffset uint64 - for i, f := range fields { - if f.BitfieldLength() == 0 { - continue - } - off, middle := bfOffset, true - bfOffset += f.BitfieldLength() - if i == len(fields)-1 || // Last bitfield in a group, if last field of the struct... - fields[i+1].BitfieldLength() == 0 || // or next field is not a bitfield... - f.Size() != fields[i+1].Size() || // or next field is of different size... - bfOffset+fields[i+1].BitfieldLength() > f.Size()*8 { // or next field does not fit into the current group. - middle, bfOffset = false, 0 - } - setBitfieldOffset(f, off, middle) - } -} - -func setBitfieldOffset(t0 prog.Type, offset uint64, middle bool) { - size := t0.Size() - unit := size - if middle { - size = 0 - } - switch t := t0.(type) { - case *prog.IntType: - t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size - case *prog.ConstType: - t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size - case *prog.LenType: - t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size - case *prog.FlagsType: - t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size - case *prog.ProcType: - t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size - default: - panic(fmt.Sprintf("type %#v can't be a bitfield", t)) - } -} - -func (comp *compiler) addAlignment(fields []prog.Type, varlen, packed bool, alignAttr uint64) []prog.Type { +func (comp *compiler) layoutStruct(fields []prog.Type, varlen, packed bool, alignAttr uint64) []prog.Type { var newFields []prog.Type - if packed { - // If a struct is packed, statically sized and has explicitly set alignment, - // add a padding at the end. - newFields = fields - if !varlen && alignAttr != 0 { - size := uint64(0) - for _, f := range fields { - size += f.Size() - } - if tail := size % alignAttr; tail != 0 { - newFields = append(newFields, genPad(alignAttr-tail)) + var align, off, bfOffset uint64 + for i, f := range fields { + if f.IsBitfield() { + off, middle := bfOffset, true + bfOffset += f.BitfieldLength() + // Last bitfield in a group, if last field of the struct... + if i == len(fields)-1 || + // or next field is not a bitfield... + fields[i+1].BitfieldLength() == 0 || + // or next field is of different size... + f.Size() != fields[i+1].Size() || + // or next field does not fit into the current group. + bfOffset+fields[i+1].BitfieldLength() > f.Size()*8 { + middle, bfOffset = false, 0 } + setBitfieldOffset(f, off, middle) } - return newFields - } - var align, off uint64 - for i, f := range fields { - if i == 0 || fields[i-1].Size() != 0 { + needPadding := true + if i != 0 { + prev := fields[i-1] + needPadding = !prev.Varlen() && prev.Size() != 0 + } + if needPadding && !packed { a := comp.typeAlign(f) if align < a { align = a } // Append padding if the last field is not a bitfield or it's the last bitfield in a set. - if off%a != 0 { + if !packed && off%a != 0 { pad := a - off%a off += pad newFields = append(newFields, genPad(pad)) } } newFields = append(newFields, f) - if !(i == len(fields)-1 && f.Varlen()) { + if !f.Varlen() { // Increase offset if the current field except when it's // the last field in a struct and has variable length. off += f.Size() @@ -348,6 +312,28 @@ func (comp *compiler) addAlignment(fields []prog.Type, varlen, packed bool, alig return newFields } +func setBitfieldOffset(t0 prog.Type, offset uint64, middle bool) { + size := t0.Size() + unit := size + if middle { + size = 0 + } + switch t := t0.(type) { + case *prog.IntType: + t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size + case *prog.ConstType: + t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size + case *prog.LenType: + t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size + case *prog.FlagsType: + t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size + case *prog.ProcType: + t.BitfieldOff, t.BitfieldUnit, t.TypeSize = offset, unit, size + default: + panic(fmt.Sprintf("type %#v can't be a bitfield", t)) + } +} + func (comp *compiler) typeAlign(t0 prog.Type) uint64 { switch t := t0.(type) { case *prog.IntType, *prog.LenType, *prog.FlagsType, *prog.ProcType, |
