diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2019-12-20 06:09:32 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2019-12-20 16:45:33 +0100 |
| commit | 9be5bbcf093c09879ebcd2dbb751168c9346d52c (patch) | |
| tree | 6241e479665e076f112b36f44ad044a7e10cc8aa /pkg/compiler | |
| parent | aa56acc6b7a97bcf5f965d8a611ee2a69e92becd (diff) | |
pkg/compiler: refactor struct layout
Combine markBitfields and addAlignment functions.
Fixing #1542 will require doing both at the same time,
they are not really independent.
Also remove the special case for packed structs,
pad them as part of the common procedure.
No functional changes.
Diffstat (limited to 'pkg/compiler')
| -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, |
