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 }