prog/types.go: add Type.Alignment() and TypeCommon.TypeAlign

Type.Alignment() can be used to obtain byte alignment for
correctly allocating aligned memory for the Type.
This commit is contained in:
Albert van der Linde 2020-07-14 07:44:00 +00:00 committed by Dmitry Vyukov
parent ce4c95b3a6
commit 230553f68f
3 changed files with 53 additions and 53 deletions

View File

@ -296,7 +296,7 @@ func (comp *compiler) layoutStructFields(t *prog.StructType, varlen, packed bool
f := field.Type
fieldAlign := uint64(1)
if !packed {
fieldAlign = comp.typeAlign(f)
fieldAlign = f.Alignment()
if structAlign < fieldAlign {
structAlign = fieldAlign
}
@ -424,58 +424,6 @@ func setBitfieldUnitOffset(t prog.Type, v uint64) {
*p = v
}
func (comp *compiler) typeAlign(t0 prog.Type) uint64 {
switch t0.Format() {
case prog.FormatNative, prog.FormatBigEndian:
case prog.FormatStrDec, prog.FormatStrHex, prog.FormatStrOct:
return 1
default:
panic("unknown binary format")
}
if prog.IsPad(t0) {
return 1
}
switch t := t0.(type) {
case *prog.ConstType, *prog.IntType, *prog.LenType, *prog.FlagsType, *prog.ProcType,
*prog.CsumType, *prog.PtrType, *prog.VmaType, *prog.ResourceType:
align := t0.UnitSize()
if align == 8 && comp.target.Int64Alignment != 0 {
align = comp.target.Int64Alignment
}
return align
case *prog.BufferType:
return 1
case *prog.ArrayType:
return comp.typeAlign(t.Elem)
case *prog.StructType:
n := comp.structs[t.TypeName]
attrs := comp.parseAttrs(structAttrs, n, n.Attrs)
if align := attrs[attrAlign]; align != 0 {
return align // overrided by user attribute
}
if attrs[attrPacked] != 0 {
return 1
}
align := uint64(0)
for _, f := range t.Fields {
if a := comp.typeAlign(f.Type); align < a {
align = a
}
}
return align
case *prog.UnionType:
align := uint64(0)
for _, f := range t.Fields {
if a := comp.typeAlign(f.Type); align < a {
align = a
}
}
return align
default:
panic(fmt.Sprintf("unknown type: %#v", t))
}
}
func genPad(size uint64) prog.Field {
return prog.Field{
Type: &prog.ConstType{

View File

@ -140,6 +140,7 @@ var typeInt = &typeDesc{
bitLen = t.Colon[0].Value
}
base.TypeSize = size
base.TypeAlign = getIntAlignment(comp, base)
return &prog.IntType{
IntTypeCommon: genIntCommon(base.TypeCommon, bitLen, be),
Kind: kind,
@ -150,6 +151,14 @@ var typeInt = &typeDesc{
},
}
func getIntAlignment(comp *compiler, base prog.IntTypeCommon) uint64 {
align := base.UnitSize()
if align == 8 && comp.target.Int64Alignment != 0 {
align = comp.target.Int64Alignment
}
return align
}
var typePtr = &typeDesc{
Names: []string{"ptr", "ptr64"},
CanBeArgRet: canBeArg,
@ -160,6 +169,7 @@ var typePtr = &typeDesc{
if t.Ident == "ptr64" {
base.TypeSize = 8
}
base.TypeAlign = getIntAlignment(comp, base)
return &prog.PtrType{
TypeCommon: base.TypeCommon,
Elem: comp.genType(args[1], 0),
@ -176,6 +186,7 @@ var typeVoid = &typeDesc{
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = 0 // the only type with static size 0
base.TypeAlign = 1
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: prog.BufferBlobRange,
@ -230,6 +241,7 @@ var typeArray = &typeDesc{
base.TypeSize = begin * elemType.Size()
}
}
base.TypeAlign = 1
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: bufKind,
@ -238,6 +250,7 @@ var typeArray = &typeDesc{
}
}
// TypeSize is assigned later in layoutArray.
base.TypeAlign = elemType.Alignment()
return &prog.ArrayType{
TypeCommon: base.TypeCommon,
Elem: elemType,
@ -273,6 +286,7 @@ var typeLen = &typeDesc{
for _, col := range args[0].Colon {
path = append(path, col.Ident)
}
base.TypeAlign = getIntAlignment(comp, base)
return &prog.LenType{
IntTypeCommon: base,
Path: path,
@ -298,6 +312,7 @@ var typeConst = &typeDesc{
args[0].Value = v & (uint64(1)<<bitSize - 1)
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeAlign = getIntAlignment(comp, base)
return &prog.ConstType{
IntTypeCommon: base,
Val: args[0].Value,
@ -364,6 +379,7 @@ var typeFlags = &typeDesc{
sort.Slice(values, func(i, j int) bool {
return values[i] < values[j]
})
base.TypeAlign = getIntAlignment(comp, base)
return &prog.FlagsType{
IntTypeCommon: base,
Vals: values,
@ -416,6 +432,7 @@ var typeVMA = &typeDesc{
if t.Ident == "vma64" {
base.TypeSize = 8
}
base.TypeAlign = getIntAlignment(comp, base)
return &prog.VmaType{
TypeCommon: base.TypeCommon,
RangeBegin: begin,
@ -447,6 +464,7 @@ var typeCsum = &typeDesc{
if len(args) > 2 {
proto = args[2].Value
}
base.TypeAlign = getIntAlignment(comp, base)
return &prog.CsumType{
IntTypeCommon: base,
Buf: args[0].Ident,
@ -501,6 +519,7 @@ var typeProc = &typeDesc{
}
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeAlign = getIntAlignment(comp, base)
return &prog.ProcType{
IntTypeCommon: base,
ValuesStart: args[0].Value,
@ -518,6 +537,7 @@ var typeText = &typeDesc{
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = 0
base.TypeAlign = 1
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: prog.BufferText,
@ -586,6 +606,7 @@ var typeString = &typeDesc{
return comp.stringSize(t, args) == 0
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeAlign = 1
if len(args) > 0 && args[0].Ident == "filename" {
base.TypeName = "filename"
base.TypeSize = 0
@ -723,18 +744,23 @@ var typeFmt = &typeDesc{
case *prog.ResourceType:
t.ArgFormat = format
t.TypeSize = size
t.TypeAlign = 1
case *prog.IntType:
t.ArgFormat = format
t.TypeSize = size
t.TypeAlign = 1
case *prog.LenType:
t.ArgFormat = format
t.TypeSize = size
t.TypeAlign = 1
case *prog.FlagsType:
t.ArgFormat = format
t.TypeSize = size
t.TypeAlign = 1
case *prog.ProcType:
t.ArgFormat = format
t.TypeSize = size
t.TypeAlign = 1
default:
panic(fmt.Sprintf("unexpected type: %#v", typ))
}
@ -769,6 +795,7 @@ func init() {
}
baseProgType := comp.genType(baseType, 0)
base.TypeSize = baseProgType.Size()
base.TypeAlign = getIntAlignment(comp, base)
return &prog.ResourceType{
TypeCommon: base.TypeCommon,
ArgFormat: baseProgType.Format(),
@ -836,8 +863,26 @@ func init() {
fields := comp.genFieldArray(s.Fields, make([]uint64, len(s.Fields)))
if s.IsUnion {
typ.(*prog.UnionType).Fields = fields
for _, f := range fields {
if a := f.Type.Alignment(); typ.(*prog.UnionType).TypeAlign < a {
typ.(*prog.UnionType).TypeAlign = a
}
}
} else {
typ.(*prog.StructType).Fields = fields
attrs := comp.parseAttrs(structAttrs, s, s.Attrs)
if align := attrs[attrAlign]; align != 0 {
typ.(*prog.StructType).TypeAlign = align
} else if attrs[attrPacked] != 0 {
typ.(*prog.StructType).TypeAlign = 1
} else {
for _, f := range fields {
a := f.Type.Alignment()
if typ.(*prog.StructType).TypeAlign < a {
typ.(*prog.StructType).TypeAlign = a
}
}
}
}
return typ
}

View File

@ -88,6 +88,7 @@ type Type interface {
Varlen() bool
Size() uint64
TypeBitSize() uint64
Alignment() uint64
Format() BinaryFormat
BitfieldOffset() uint64
BitfieldLength() uint64
@ -118,6 +119,7 @@ func (ti Ref) Optional() bool { panic("pr
func (ti Ref) Varlen() bool { panic("prog.Ref method called") }
func (ti Ref) Size() uint64 { panic("prog.Ref method called") }
func (ti Ref) TypeBitSize() uint64 { panic("prog.Ref method called") }
func (ti Ref) Alignment() uint64 { panic("prog.Ref method called") }
func (ti Ref) Format() BinaryFormat { panic("prog.Ref method called") }
func (ti Ref) BitfieldOffset() uint64 { panic("prog.Ref method called") }
func (ti Ref) BitfieldLength() uint64 { panic("prog.Ref method called") }
@ -151,6 +153,7 @@ type TypeCommon struct {
TypeName string
// Static size of the type, or 0 for variable size types and all but last bitfields in the group.
TypeSize uint64
TypeAlign uint64
IsOptional bool
IsVarlen bool
@ -223,6 +226,10 @@ func (t *TypeCommon) setRef(ref Ref) {
t.self = ref
}
func (t *TypeCommon) Alignment() uint64 {
return t.TypeAlign
}
type ResourceDesc struct {
Name string
Kind []string