modernc.org/cc@v1.0.1/v2/model.go (about)

     1  // Copyright 2017 The CC Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cc // import "modernc.org/cc/v2"
     6  
     7  import (
     8  	"fmt"
     9  	"runtime"
    10  
    11  	"modernc.org/ir"
    12  	"modernc.org/mathutil"
    13  )
    14  
    15  // Model describes properties of scalar Types.
    16  type Model map[TypeKind]ModelItem
    17  
    18  // ModelItem describers properties of a particular Type.
    19  type ModelItem struct {
    20  	Size        int
    21  	Align       int
    22  	StructAlign int
    23  }
    24  
    25  // NewModel returns the model appropriate for the current OS and architecture
    26  // or according to the environment variables GOOS and GOARCH, if set.
    27  func NewModel() (m Model, err error) {
    28  	switch arch := env("GOARCH", runtime.GOARCH); arch {
    29  	case "arm":
    30  		return Model{
    31  			Bool:      {1, 1, 1},
    32  			Char:      {1, 1, 1},
    33  			Int:       {4, 4, 4},
    34  			Long:      {4, 4, 4},
    35  			LongLong:  {8, 4, 4},
    36  			SChar:     {1, 1, 1},
    37  			Short:     {2, 2, 2},
    38  			UChar:     {1, 1, 1},
    39  			UInt:      {4, 4, 4},
    40  			ULong:     {4, 4, 4},
    41  			ULongLong: {8, 4, 4},
    42  			UShort:    {2, 2, 2},
    43  
    44  			Float:      {4, 4, 4},
    45  			Double:     {8, 4, 4},
    46  			LongDouble: {8, 4, 4},
    47  
    48  			FloatImaginary:      {4, 4, 4},
    49  			DoubleImaginary:     {8, 4, 4},
    50  			LongDoubleImaginary: {8, 4, 4},
    51  
    52  			FloatComplex:      {8, 4, 4},
    53  			DoubleComplex:     {16, 4, 4},
    54  			LongDoubleComplex: {16, 4, 4},
    55  
    56  			Void: {1, 1, 1},
    57  			Ptr:  {4, 4, 4},
    58  		}, nil
    59  	case "386":
    60  		return Model{
    61  			Bool:      {1, 1, 1},
    62  			Char:      {1, 1, 1},
    63  			Int:       {4, 4, 4},
    64  			Long:      {4, 4, 4},
    65  			LongLong:  {8, 8, 4},
    66  			SChar:     {1, 1, 1},
    67  			Short:     {2, 2, 2},
    68  			UChar:     {1, 1, 1},
    69  			UInt:      {4, 4, 4},
    70  			ULong:     {4, 4, 4},
    71  			ULongLong: {8, 8, 4},
    72  			UShort:    {2, 2, 2},
    73  
    74  			Float:      {4, 4, 4},
    75  			Double:     {8, 8, 4},
    76  			LongDouble: {8, 8, 4},
    77  
    78  			FloatImaginary:      {4, 4, 4},
    79  			DoubleImaginary:     {8, 8, 4},
    80  			LongDoubleImaginary: {8, 8, 4},
    81  
    82  			FloatComplex:      {8, 8, 4},
    83  			DoubleComplex:     {16, 8, 4},
    84  			LongDoubleComplex: {16, 8, 4},
    85  
    86  			Void: {1, 1, 1},
    87  			Ptr:  {4, 4, 4},
    88  		}, nil
    89  	case "amd64":
    90  		var longLength = 8
    91  		if env("GOOS", runtime.GOOS) == "windows" {
    92  			longLength = 4
    93  		}
    94  
    95  		model := Model{
    96  			Bool:      {1, 1, 1},
    97  			Char:      {1, 1, 1},
    98  			Int:       {4, 4, 4},
    99  			Long:      {longLength, longLength, longLength},
   100  			LongLong:  {8, 8, 8},
   101  			SChar:     {1, 1, 1},
   102  			Short:     {2, 2, 2},
   103  			UChar:     {1, 1, 1},
   104  			UInt:      {4, 4, 4},
   105  			ULong:     {longLength, longLength, longLength},
   106  			ULongLong: {8, 8, 8},
   107  			UShort:    {2, 2, 2},
   108  
   109  			Float:      {4, 4, 4},
   110  			Double:     {8, 8, 8},
   111  			LongDouble: {8, 8, 8},
   112  
   113  			FloatImaginary:      {4, 4, 4},
   114  			DoubleImaginary:     {8, 8, 8},
   115  			LongDoubleImaginary: {8, 8, 8},
   116  
   117  			FloatComplex:      {8, 8, 4},
   118  			DoubleComplex:     {16, 8, 4},
   119  			LongDoubleComplex: {16, 8, 4},
   120  
   121  			Void: {1, 1, 1},
   122  			Ptr:  {8, 8, 8},
   123  		}
   124  
   125  		return model, nil
   126  	default:
   127  		return nil, fmt.Errorf("unknown/unsupported architecture %s", arch)
   128  	}
   129  }
   130  
   131  // Equal returns whether m equals n.
   132  func (m Model) Equal(n Model) bool {
   133  	if len(m) != len(n) {
   134  		return false
   135  	}
   136  
   137  	for k, v := range m {
   138  		if v != n[k] {
   139  			return false
   140  		}
   141  	}
   142  	return true
   143  }
   144  
   145  // Sizeof returns the size in bytes of a variable of type t.
   146  func (m Model) Sizeof(t Type) int64 {
   147  	switch x := UnderlyingType(t).(type) {
   148  	case *ArrayType:
   149  		if x.Size.Value != nil { // T[42]
   150  			return m.Sizeof(x.Item) * x.Size.Value.(*ir.Int64Value).Value
   151  		}
   152  
   153  		if x.Length != nil {
   154  			panic(fmt.Errorf("Sizeof(%v): variable length array", t))
   155  		}
   156  
   157  		panic(fmt.Errorf("Sizeof(%v): incomplete array", t))
   158  	case *EnumType:
   159  		return m.Sizeof(x.Enums[0].Operand.Type)
   160  	case *NamedType:
   161  		return m.Sizeof(x.Type)
   162  	case
   163  		*FunctionType,
   164  		*PointerType:
   165  
   166  		return int64(m[Ptr].Size)
   167  	case *StructType:
   168  		layout := m.Layout(x)
   169  		if len(layout) == 0 {
   170  			return 0
   171  		}
   172  
   173  		lf := layout[len(layout)-1]
   174  		return lf.Offset + lf.Size + int64(lf.Padding)
   175  	case *TaggedStructType:
   176  		u := x.getType()
   177  		if u == x {
   178  			panic("TODO")
   179  		}
   180  
   181  		return m.Sizeof(u)
   182  	case TypeKind:
   183  		return int64(m[x].Size)
   184  	case *UnionType:
   185  		var sz int64
   186  		for _, v := range m.Layout(x) {
   187  			if v.Size > sz {
   188  				sz = v.Size
   189  			}
   190  		}
   191  		return roundup(sz, int64(m.Alignof(x)))
   192  	case nil:
   193  		panic("internal error")
   194  	default:
   195  		panic(x)
   196  	}
   197  }
   198  
   199  // FieldProperties describe a struct/union field.
   200  type FieldProperties struct {
   201  	Bitoff     int // Zero based bit number of a bitfield
   202  	Bits       int // Width of a bit field or zero otherwise.
   203  	Declarator *Declarator
   204  	Offset     int64 // Byte offset relative to start of the struct/union.
   205  	PackedType Type  // Bits != 0: Storage type holding the bit field.
   206  	Padding    int   // Adjustment to enforce proper alignment.
   207  	Size       int64 // Field size for copying.
   208  	Type       Type
   209  
   210  	Anonymous       bool
   211  	IsFlexibleArray bool
   212  }
   213  
   214  // Mask returns the bit mask of bit field described by f.
   215  func (f *FieldProperties) Mask() uint64 {
   216  	if f.Bits == 0 {
   217  		return 1<<64 - 1
   218  	}
   219  
   220  	return (1<<uint(f.Bits) - 1) << uint(f.Bitoff)
   221  }
   222  
   223  // Layout computes the memory layout of t.
   224  func (m Model) Layout(t Type) (r []FieldProperties) {
   225  	//TODO memoize
   226  	switch x := UnderlyingType(t).(type) {
   227  	case *StructType:
   228  		if len(x.Fields) == 0 {
   229  			return nil
   230  		}
   231  
   232  		if x.layout != nil {
   233  			return x.layout
   234  		}
   235  
   236  		defer func() { x.layout = r }()
   237  
   238  		r = make([]FieldProperties, len(x.Fields))
   239  		var off int64
   240  		bitoff := 0
   241  		for i, v := range x.Fields {
   242  			switch {
   243  			case v.Bits != 0:
   244  				switch {
   245  				case bitoff == 0 && v.Bits > 0:
   246  					r[i] = FieldProperties{Offset: off, Bitoff: bitoff, Bits: v.Bits, Declarator: v.Declarator, Type: v.Type}
   247  					bitoff = v.Bits
   248  				default:
   249  					if v.Bits < 0 {
   250  						if n := m.packBits(bitoff, i-1, off, r); bitoff != 0 {
   251  							off = n
   252  						}
   253  						r[i] = FieldProperties{Offset: off, Bits: -1, Declarator: v.Declarator, Type: v.Type}
   254  						bitoff = 0
   255  						break
   256  					}
   257  
   258  					n := bitoff + v.Bits
   259  					if n > 32 {
   260  						off = m.packBits(bitoff, i-1, off, r)
   261  						r[i] = FieldProperties{Offset: off, Bits: v.Bits, Declarator: v.Declarator, Type: v.Type}
   262  						bitoff = v.Bits
   263  						break
   264  					}
   265  
   266  					r[i] = FieldProperties{Offset: off, Bitoff: bitoff, Bits: v.Bits, Declarator: v.Declarator, Type: v.Type}
   267  					bitoff = n
   268  				}
   269  			default:
   270  				if bitoff != 0 {
   271  					off = m.packBits(bitoff, i-1, off, r)
   272  					bitoff = 0
   273  				}
   274  				var sz int64
   275  				if !v.IsFlexibleArray {
   276  					sz = m.Sizeof(v.Type)
   277  				}
   278  				a := m.StructAlignof(v.Type)
   279  				z := off
   280  				if a != 0 {
   281  					off = roundup(off, int64(a))
   282  				}
   283  				if off != z {
   284  					r[i-1].Padding = int(off - z)
   285  				}
   286  				r[i] = FieldProperties{Offset: off, Size: sz, Declarator: v.Declarator, Type: v.Type, Anonymous: v.Anonymous, IsFlexibleArray: v.IsFlexibleArray}
   287  				off += sz
   288  			}
   289  		}
   290  		i := len(r) - 1
   291  		if bitoff != 0 {
   292  			off = m.packBits(bitoff, i, off, r)
   293  		}
   294  		for i, v := range r {
   295  			if v.Bits > 0 {
   296  				x.Fields[i].PackedType = v.PackedType
   297  			}
   298  		}
   299  		align := 0
   300  		for i, v := range x.Fields {
   301  			if r[i].Bits < 0 {
   302  				continue
   303  			}
   304  
   305  			t := v.Type
   306  			if v.PackedType != nil {
   307  				t = v.PackedType
   308  			}
   309  			align = mathutil.Max(align, m.StructAlignof(t))
   310  		}
   311  		z := off
   312  		off = roundup(off, int64(align))
   313  		if off != z {
   314  			r[len(r)-1].Padding = int(off - z)
   315  		}
   316  		return r
   317  	case *UnionType:
   318  		if len(x.Fields) == 0 {
   319  			return nil
   320  		}
   321  
   322  		if x.layout != nil {
   323  			return x.layout
   324  		}
   325  
   326  		defer func() { x.layout = r }()
   327  
   328  		r = make([]FieldProperties, len(x.Fields))
   329  		for i, v := range x.Fields {
   330  			switch {
   331  			case v.Bits < 0:
   332  				m.packBits(v.Bits, i, 0, r)
   333  			case v.Bits > 0:
   334  				r[i] = FieldProperties{Bits: v.Bits, Declarator: v.Declarator, Type: v.Type}
   335  				m.packBits(v.Bits, i, 0, r)
   336  				x.Fields[i].PackedType = r[i].PackedType
   337  			default:
   338  				sz := m.Sizeof(v.Type)
   339  				r[i] = FieldProperties{Size: sz, Bits: v.Bits, Declarator: v.Declarator, Type: v.Type}
   340  			}
   341  		}
   342  		for i, v := range r {
   343  			if v.Bits != 0 {
   344  				x.Fields[i].PackedType = v.PackedType
   345  			}
   346  		}
   347  		return r
   348  	case nil:
   349  		panic("internal error")
   350  	default:
   351  		panic(x)
   352  	}
   353  }
   354  
   355  func (m *Model) packBits(bitoff, i int, off int64, r []FieldProperties) int64 {
   356  	var t Type
   357  	switch {
   358  	case bitoff <= 8:
   359  		t = UChar
   360  	case bitoff <= 16:
   361  		t = UShort
   362  	case bitoff <= 32:
   363  		t = UInt
   364  	case bitoff <= 64:
   365  		t = ULongLong
   366  	default:
   367  		panic("internal error")
   368  	}
   369  	sz := m.Sizeof(t)
   370  	a := m.StructAlignof(t)
   371  	z := off
   372  	if a != 0 {
   373  		off = roundup(off, int64(a))
   374  	}
   375  	var first int
   376  	for first = i; first >= 0 && r[first].Bits > 0 && r[first].PackedType == nil; first-- {
   377  	}
   378  	first++
   379  	if off != z {
   380  		r[first-1].Padding = int(off - z)
   381  	}
   382  	for j := first; j <= i; j++ {
   383  		r[j].Offset = off
   384  		r[j].Size = sz
   385  		r[j].PackedType = t
   386  	}
   387  	return off + sz
   388  }
   389  
   390  // Alignof computes the memory alignment requirements of t. One is returned
   391  // for a struct/union type with no fields.
   392  func (m Model) Alignof(t Type) int {
   393  	switch x := t.(type) {
   394  	case *ArrayType:
   395  		return m.Alignof(x.Item)
   396  	case *EnumType:
   397  		return m.Alignof(x.Enums[0].Operand.Type)
   398  	case *NamedType:
   399  		return m.Alignof(x.Type)
   400  	case *PointerType:
   401  		return m[Ptr].Align
   402  	case *StructType:
   403  		m.Layout(x)
   404  		r := 1
   405  		for _, v := range x.Fields {
   406  			t := v.Type
   407  			if v.Bits < 0 {
   408  				continue
   409  			}
   410  
   411  			if v.Bits > 0 {
   412  				t = v.PackedType
   413  			}
   414  			if a := m.StructAlignof(t); a > r {
   415  				r = a
   416  			}
   417  		}
   418  		return r
   419  	case *TaggedEnumType:
   420  		u := x.getType()
   421  		if u == x {
   422  			panic("TODO")
   423  		}
   424  		return m.Alignof(u)
   425  	case *TaggedStructType:
   426  		u := x.getType()
   427  		if u == x {
   428  			panic("TODO")
   429  		}
   430  		return m.Alignof(u)
   431  	case *TaggedUnionType:
   432  		u := x.getType()
   433  		if u == x {
   434  			panic("TODO")
   435  		}
   436  		return m.Alignof(u)
   437  	case TypeKind:
   438  		return m[x].Align
   439  	case *UnionType:
   440  		m.Layout(x)
   441  		r := 1
   442  		for _, v := range x.Fields {
   443  			t := v.Type
   444  			if v.Bits < 0 {
   445  				continue
   446  			}
   447  
   448  			if v.Bits > 0 {
   449  				t = v.PackedType
   450  			}
   451  			if a := m.StructAlignof(t); a > r {
   452  				r = a
   453  			}
   454  		}
   455  		return r
   456  	case nil:
   457  		panic("internal error")
   458  	default:
   459  		panic(x)
   460  	}
   461  }
   462  
   463  // StructAlignof computes the memory alignment requirements of t when its
   464  // instance is a struct field. One is returned for a struct/union type with no
   465  // fields.
   466  func (m Model) StructAlignof(t Type) int {
   467  	switch x := t.(type) {
   468  	case *ArrayType:
   469  		return m.StructAlignof(x.Item)
   470  	case *EnumType:
   471  		return m.StructAlignof(x.Enums[0].Operand.Type)
   472  	case *NamedType:
   473  		return m.StructAlignof(x.Type)
   474  	case *PointerType:
   475  		return m[Ptr].StructAlign
   476  	case *StructType:
   477  		m.Layout(x)
   478  		r := 1
   479  		for _, v := range x.Fields {
   480  			t := v.Type
   481  			if v.Bits < 0 {
   482  				continue
   483  			}
   484  
   485  			if v.Bits > 0 {
   486  				t = v.PackedType
   487  			}
   488  			if a := m.StructAlignof(t); a > r {
   489  				r = a
   490  			}
   491  		}
   492  		return r
   493  	case *TaggedEnumType:
   494  		u := x.getType()
   495  		if u == x {
   496  			panic("TODO")
   497  		}
   498  		return m.StructAlignof(u)
   499  	case *TaggedStructType:
   500  		u := x.getType()
   501  		if u == x {
   502  			panic("TODO")
   503  		}
   504  		return m.StructAlignof(u)
   505  	case *TaggedUnionType:
   506  		u := x.getType()
   507  		if u == x {
   508  			panic("TODO")
   509  		}
   510  		return m.StructAlignof(u)
   511  	case TypeKind:
   512  		return m[x].StructAlign
   513  	case *UnionType:
   514  		m.Layout(x)
   515  		r := 1
   516  		for _, v := range x.Fields {
   517  			t := v.Type
   518  			if v.Bits < 0 {
   519  				continue
   520  			}
   521  
   522  			if v.Bits > 0 {
   523  				t = v.PackedType
   524  			}
   525  			if a := m.StructAlignof(t); a > r {
   526  				r = a
   527  			}
   528  		}
   529  		return r
   530  	default:
   531  		panic(fmt.Errorf("%T", x))
   532  	}
   533  }
   534  
   535  func roundup(n, to int64) int64 {
   536  	if r := n % to; r != 0 {
   537  		return n + to - r
   538  	}
   539  
   540  	return n
   541  }
   542  
   543  func (m Model) defaultArgumentPromotion(op Operand) (r Operand) {
   544  	u := op.Type
   545  	for {
   546  		switch x := u.(type) {
   547  		case *EnumType:
   548  			u = x.Enums[0].Operand.Type
   549  		case *NamedType:
   550  			u = x.Type
   551  		case
   552  			*PointerType,
   553  			*StructType,
   554  			*TaggedStructType,
   555  			*TaggedUnionType,
   556  			*UnionType:
   557  
   558  			op.Type = x
   559  			return op
   560  		case *TaggedEnumType:
   561  			u = x.getType()
   562  		case TypeKind:
   563  			op.Type = x
   564  			switch x {
   565  			case Float:
   566  				return op.ConvertTo(m, Double)
   567  			case
   568  				Double,
   569  				LongDouble:
   570  
   571  				return op
   572  			case
   573  				Char,
   574  				Int,
   575  				Long,
   576  				LongLong,
   577  				SChar,
   578  				Short,
   579  				UChar,
   580  				UInt,
   581  				ULong,
   582  				ULongLong,
   583  				UShort:
   584  
   585  				return op.integerPromotion(m)
   586  			default:
   587  				panic(x)
   588  			}
   589  		default:
   590  			panic(x)
   591  		}
   592  	}
   593  }