aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-12-20 06:09:32 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-12-20 16:45:33 +0100
commit9be5bbcf093c09879ebcd2dbb751168c9346d52c (patch)
tree6241e479665e076f112b36f44ad044a7e10cc8aa
parentaa56acc6b7a97bcf5f965d8a611ee2a69e92becd (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.
-rw-r--r--pkg/compiler/gen.go108
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,