modernc.org/qbe@v0.0.9/c.go (about) 1 // Copyright 2021 The QBE 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 /*TODO 6 7 char x[42]; 8 intptr_t v42 = &x; 9 v43 = *(char*)(v42); 10 11 -> 12 13 char x[42]; 14 15 v43 = *(char*)(&x); 16 17 */ 18 19 package qbe // import "modernc.org/qbe" 20 21 import ( 22 "bytes" 23 "fmt" 24 "io" 25 "math" 26 "sort" 27 "strings" 28 ) 29 30 const ( 31 typePrefix = "__qbe_t" 32 ) 33 34 var ( 35 // TraceC enables printing the generated C code to stdout. 36 TraceC bool // testing 37 ) 38 39 // C renders an AST as the body of compilable C code prepended with includes. 40 func (a *AST) C(out io.Writer, includes, os, arch string) error { 41 g, err := newCGen(out, a, os, arch) 42 if err != nil { 43 return err 44 } 45 46 g.ptr = a.ptr 47 g.w("%s", includes) 48 return g.main() 49 } 50 51 type cgen struct { 52 arch string 53 ast *AST 54 declaredExternPrototypes map[string]struct{} 55 errs msgList 56 os string 57 out io.Writer 58 ptr Type 59 vaInfo *VaInfo 60 61 isClosed bool 62 allErrors bool 63 } 64 65 func newCGen(out io.Writer, ast *AST, os, arch string) (*cgen, error) { 66 vaInfo, err := VaInfoFor(os, arch) 67 if err != nil { 68 return nil, err 69 } 70 71 r := &cgen{ 72 arch: arch, 73 ast: ast, 74 declaredExternPrototypes: map[string]struct{}{}, 75 os: os, 76 out: out, 77 vaInfo: vaInfo, 78 } 79 return r, nil 80 } 81 82 func (g *cgen) err(off int32, skip int, msg string, args ...interface{}) { 83 if len(g.errs) == 10 && !g.allErrors { 84 return 85 } 86 87 g.errs.err(off, skip+1, msg, args...) 88 } 89 90 func (g *cgen) w(s string, args ...interface{}) { 91 if g.isClosed { 92 return 93 } 94 95 if TraceC { 96 fmt.Printf(s, args...) 97 } 98 if _, err := fmt.Fprintf(g.out, s, args...); err != nil { 99 g.err(0, 1, "error writing output: %v", err) 100 g.isClosed = true 101 } 102 } 103 104 func (g *cgen) main() error { 105 ctx := &ctx{types: g.types()} 106 g.w("\n") 107 g.extern(ctx) 108 g.funcForwardDefs(ctx) 109 g.dataForwardDefs() 110 for _, v := range g.ast.Defs { 111 switch x := v.(type) { 112 case *FuncDef: 113 g.funcDef(ctx, x) 114 } 115 } 116 g.w("\n") 117 return g.errs.Err(g.ast.source) 118 } 119 120 func (g *cgen) extern(ctx *ctx) { 121 prototypes := map[string]string{} 122 a := strings.Split(string(g.ast.FirstSeparator()), "\n") 123 for _, v := range a { 124 v = strings.TrimSpace(v) 125 const tag = "#qbec:prototype " 126 if strings.HasPrefix(v, tag) { 127 v = v[len(tag):] 128 x := strings.IndexByte(v, ' ') 129 prototypes[v[:x]] = v[x+1:] 130 } 131 } 132 a = a[:0] 133 for k := range g.ast.ExternFuncs { 134 a = append(a, k) 135 } 136 sort.Strings(a) 137 for _, v := range a { 138 if strings.HasPrefix(v, "__builtin_") || 139 v == "__qbe_va_end" || v == "__qbe_va_copy" || 140 g.os == "windows" && (v == "alloca" || v == "_alloca") { 141 continue 142 } 143 144 if s, ok := prototypes[v]; ok { 145 g.declaredExternPrototypes[v] = struct{}{} 146 g.w("\n%s", s) 147 continue 148 } 149 150 s := "void" 151 if typ := g.ast.ExternFuncs[v]; typ != nil { 152 s = g.typ(ctx, typ, true) 153 } 154 g.w("\nextern %s %s();", s, v) 155 } 156 a = a[:0] 157 for k := range g.ast.ExternData { 158 a = append(a, k) 159 } 160 sort.Strings(a) 161 for _, v := range a { 162 if s, ok := prototypes[v]; ok { 163 g.declaredExternPrototypes[v] = struct{}{} 164 g.w("\n%s", s) 165 continue 166 } 167 168 g.w("\nextern char %s;", v) 169 } 170 } 171 172 type global struct { 173 global GlobalInitializer 174 name Name 175 x uintptr 176 177 isIndex bool 178 } 179 180 func (g *cgen) dataForwardDefs() { 181 done := map[*DataDef]struct{}{} 182 first := true 183 for _, def := range g.ast.Defs { 184 switch x := def.(type) { 185 case *DataDef: 186 if x.Type == nil { 187 continue 188 } 189 190 if len(x.Items) != 2 || x.Type != b { 191 continue 192 } 193 194 if first { 195 g.w("\n") 196 first = false 197 } 198 g.w("\n") 199 done[x] = struct{}{} 200 g.singleTypeData(x, nil) 201 } 202 } 203 var globals []global 204 for _, def := range g.ast.Defs { 205 switch x := def.(type) { 206 case *DataDef: 207 if _, ok := done[x]; !ok { 208 globals = append(globals, g.dataDef(x, globals)...) 209 } 210 } 211 } 212 if len(globals) == 0 { 213 return 214 } 215 216 g.w("\n\n__attribute__ ((constructor)) static void __qbe_init() {") 217 for _, v := range globals { 218 switch { 219 case v.isIndex: 220 g.w("\n\t%s[%d] = (intptr_t)(&%s)", v.name.cname(), v.x, v.global.Name.cname()) 221 if v.global.Offset != 0 { 222 g.w("+%d", v.global.Offset) 223 } 224 g.w(";") 225 default: 226 panic(todo("%v:", v.name.Position())) 227 } 228 } 229 g.w("\n}") 230 } 231 232 func (g *cgen) dataDef(n *DataDef, globals []global) []global { 233 g.w("\n\n") 234 switch { 235 case n.Type != nil: 236 return g.singleTypeData(n, globals) 237 default: 238 return g.mixedTypeData(n, globals) 239 } 240 } 241 242 func (g *cgen) mixedTypeData(n *DataDef, globals []global) (r []global) { 243 if !n.IsExported { 244 g.w("static ") 245 } 246 g.w("struct {") 247 for i, v := range n.Items { 248 switch x := v.(type) { 249 case IntInitializer: 250 g.w("\n\t%s\tf%d;", g.typ(nil, x.Type, true), i) 251 case ZeroInitializer: 252 g.w("\n\t%s\tf%d[%d];", g.typ(nil, b, true), i, IntLit(x).Value()) 253 case GlobalInitializer: 254 g.w("\n\tvoid\t*f%d;", i) 255 case LongDoubleLitInitializer: 256 g.w("\n\t%s\tf%d;", g.typ(nil, x.Type, true), i) 257 default: 258 panic(todo("%v: %T", v.Position(), x)) 259 } 260 } 261 g.w("\n} %s%s", n.Name.cname(), g.aligned(n.Align)) 262 loop: 263 for _, v := range n.Items { 264 switch v.(type) { 265 case 266 IntInitializer, 267 GlobalInitializer, 268 LongDoubleLitInitializer: 269 270 g.w(" = {") 271 for i, v := range n.Items { 272 switch x := v.(type) { 273 case IntInitializer: 274 g.w("\n\t.f%d = ", i) 275 g.operand(nil, x.IntLit, x.Type, true) 276 g.w(",") 277 case ZeroInitializer: 278 // nop 279 case GlobalInitializer: 280 switch { 281 case x.Offset != 0: 282 g.w("\n\t.f%d = (void*)((char*)(&%s)+%d),", i, x.Global.cname(), x.Offset) 283 default: 284 g.w("\n\t.f%d = &%s,", i, x.Global.cname()) 285 } 286 case LongDoubleLitInitializer: 287 g.w("\n\t.f%d = ", i) 288 g.operand(nil, x.LongDoubleLit, x.Type, true) 289 g.w(",") 290 default: 291 panic(todo("%v: %T", v.Position(), x)) 292 } 293 } 294 g.w("\n}") 295 break loop 296 } 297 } 298 g.w(";") 299 return r 300 } 301 302 func (g *cgen) aligned(n uintptr) string { 303 if n > 1 { 304 return fmt.Sprintf(" __attribute__((aligned(%d)))", n) 305 } 306 307 return "" 308 } 309 310 func (g *cgen) singleTypeData(n *DataDef, globals []global) (r []global) { 311 if !n.IsExported { 312 g.w("static ") 313 } 314 if len(n.Items) == 2 && n.Type == b { 315 if s, ok := n.Items[0].(StringInitializer); ok { 316 ok = false 317 switch x := n.Items[1].(type) { 318 case ZeroInitializer: 319 ok = true 320 case IntInitializer: 321 ok = x.IntLit.Value() == 0 322 } 323 if ok { 324 switch { 325 case n.IsReadOnly: 326 g.w("char *%s = %s;", n.cname(), safeQuoteToASCII(string(s.Value()))) 327 default: 328 g.w("char %s[] = %s;", n.cname(), safeQuoteToASCII(string(s.Value()))) 329 } 330 return 331 } 332 } 333 } 334 335 g.w("%s %s[%d]%s", g.typ(nil, n.Type, true), n.cname(), n.Size/n.Type.size(g.ast.abi), g.aligned(n.Align)) 336 for _, v := range n.Attributes { 337 g.w(" __attribute__((%s))", v) 338 } 339 loop: 340 for _, v := range n.Items { 341 switch v.(type) { 342 case 343 IntInitializer, 344 StringInitializer, 345 GlobalInitializer, 346 LongDoubleLitInitializer: 347 348 g.w(" = {") 349 var ix uintptr 350 for _, v := range n.Items { 351 switch x := v.(type) { 352 case StringInitializer: 353 val := x.Value() 354 for _, v := range val { 355 g.w("\n\t[%d] = %d,\t// %#U", ix, int8(v), v) 356 ix++ 357 } 358 case ZeroInitializer: 359 val := IntLit(x).Value() 360 ix += uintptr(val) 361 case IntInitializer: 362 g.w("\n\t[%d] = ", ix) 363 ix++ 364 g.operand(nil, x.IntLit, x.Type, true) 365 g.w(",") 366 case GlobalInitializer: 367 r = append(r, global{name: n.Name, global: x, x: ix, isIndex: true}) 368 ix++ 369 case LongDoubleLitInitializer: 370 g.w("\n\t[%d] = ", ix) 371 ix++ 372 g.operand(nil, x.LongDoubleLit, x.Type, true) 373 g.w(",") 374 default: 375 panic(todo("%v: %T", v.Position(), x)) 376 } 377 } 378 g.w("\n}") 379 break loop 380 } 381 } 382 g.w(";") 383 return r 384 } 385 386 func longDoubleCString(s string) string { 387 switch s { 388 case "nan": 389 panic(todo("")) 390 case "inf": 391 panic(todo("")) 392 case "-inf": 393 panic(todo("")) 394 default: 395 return s + "L" 396 } 397 } 398 399 var mainCName = []byte("main") 400 401 type ctx struct { 402 f *FuncDef 403 types map[string]int 404 globalIDs map[string]uint32 405 } 406 407 func (ctx *ctx) isMain() bool { 408 return ctx.f != nil && ctx.f.IsExported && bytes.Equal(ctx.f.Name.cname(), mainCName) 409 } 410 411 func (ctx *ctx) globalID(n Global) uint32 { 412 if ctx.globalIDs == nil { 413 ctx.globalIDs = map[string]uint32{} 414 } 415 nm := n.cname() 416 if id, ok := ctx.globalIDs[string(nm)]; ok { 417 return id 418 } 419 420 id := uint32(len(ctx.globalIDs)) 421 ctx.globalIDs[string(nm)] = id 422 return id 423 } 424 425 func (g *cgen) funcForwardDefs(ctx *ctx) { 426 g.w("\n") 427 for _, def := range g.ast.Defs { 428 switch x := def.(type) { 429 case *FuncDef: 430 ctx.f = x 431 g.w("\n") 432 g.funcSignature(ctx, x) 433 g.w(";") 434 } 435 } 436 ctx.f = nil 437 } 438 439 func (g *cgen) funcDef(ctx *ctx, n *FuncDef) { 440 ctx.f = n 441 g.w("\n\n") 442 g.funcSignature(ctx, n) 443 g.w(" {") 444 var locals []*LocalInfo 445 for _, v := range n.Scope.Nodes { 446 if x, ok := v.(*LocalInfo); ok { 447 if x.IsParameter { 448 continue 449 } 450 451 locals = append(locals, x) 452 } 453 } 454 sort.Slice(locals, func(a, b int) bool { return locals[a].N < locals[b].N }) 455 for _, v := range locals { 456 g.w("\n\t%s __v%d; // %s", g.typ(ctx, v.Type, true), v.N, v.Name.Name()) 457 } 458 labels := make(map[*Block]int, len(n.Blocks)) 459 for _, v := range n.Blocks { 460 labels[v] = len(labels) + 1 461 } 462 produced := make(map[*Block]struct{}, len(n.Blocks)) 463 graph := n.NewCFG() 464 g.block(ctx, graph, produced, labels, true) 465 g.w("\n}") 466 //TODO- f := newFunction(ctx, n, nil) //TODO- 467 //TODO- vm := newVM() //TODO- 468 //TODO- budget := 1 << 16 //TODO- 469 //TODO- v, ok := vm.runFunc(&budget, f, nil) //TODO- 470 //TODO- trc("%T(%[1]v), ok %v", v, ok) 471 } 472 473 func (g *cgen) funcSignature(ctx *ctx, n *FuncDef) { 474 // trc("%v: %s, IsExported: %v", n.Position(), n.Name.Src(), n.IsExported) 475 if !n.IsExported { 476 g.w("static ") 477 } 478 isMain := ctx.isMain() 479 pos := n.Position() 480 g.w("\n#line %d %q\n", pos.Line, pos.Filename) 481 for _, v := range n.Attributes { 482 g.w("__attribute__((%s)) ", v) 483 } 484 switch { 485 case n.Result == nil && isMain: 486 g.w("int ") 487 case n.Result == nil: 488 g.w("void ") 489 default: 490 g.w("%s ", g.typ(ctx, n.Result, true)) 491 } 492 g.w("\n%s(", n.Name.cname()) 493 for i, v := range n.Params { 494 switch x := v.(type) { 495 case *RegularParameter: 496 info := n.Scope.node(x.Name).(*LocalInfo) 497 if y, ok := info.Type.(TypeName); ok { 498 if string(y.Name.Src()) == ":"+VaList { 499 g.w("va_list __v%d", info.N) 500 break 501 } 502 } 503 504 switch { 505 case isMain && i == 1: 506 g.w("char** __v%d", info.N) 507 default: 508 g.w("%s __v%d", g.typ(ctx, x.Type, true), info.N) 509 } 510 default: 511 panic(todo("%v: %T", v.Position(), x)) 512 } 513 if i != len(n.Params)-1 { 514 g.w(", ") 515 } 516 } 517 if n.IsVariadic { 518 g.w(", ...") 519 } 520 g.w(")") 521 } 522 523 func (g *cgen) typ(ctx *ctx, t Type, signed bool) string { 524 switch x := t.(type) { 525 case Int32: 526 switch { 527 case signed: 528 return "int32_t" 529 default: 530 return "uint32_t" 531 } 532 case Int64: 533 switch { 534 case signed: 535 return "int64_t" 536 default: 537 return "uint64_t" 538 } 539 case Int16: 540 switch { 541 case signed: 542 return "int16_t" 543 default: 544 return "uint16_t" 545 } 546 case Int8: 547 switch { 548 case signed: 549 return "int8_t" 550 default: 551 return "uint8_t" 552 } 553 case CharPointer: 554 return "char*" 555 case VoidPointer: 556 return "void*" 557 case Float64: 558 return "double" 559 case Float32: 560 return "float" 561 case LongDouble: 562 return "long double" 563 case TypeName: 564 s := string(x.Name.Name()) 565 if id, ok := ctx.types[string(x.Name.Name())]; ok { 566 return fmt.Sprintf("%s%d", typePrefix, id) 567 } 568 569 switch s[1:] { 570 case VaList: 571 return "va_list" 572 case VaListPtr: 573 return "*va_list" 574 default: 575 panic(todo("")) 576 } 577 case nil: 578 return "void" 579 default: 580 panic(todo("%T", x)) 581 } 582 } 583 584 func (g *cgen) block(ctx *ctx, n *CFGNode, produced map[*Block]struct{}, labels map[*Block]int, isEntryBlock bool) { 585 block := n.Block 586 if _, ok := produced[block]; ok { 587 return 588 } 589 590 produced[block] = struct{}{} 591 g.w("\n") 592 if !isEntryBlock { 593 g.w("l%d: ", labels[block]) 594 } 595 g.w("// %s", block.Name.Name()) 596 for _, inst := range block.Insts { 597 g.inst(ctx, inst, isEntryBlock) 598 } 599 switch x := block.Jump.(type) { 600 case Jmp, nil: 601 g.setPhis(ctx, n, n.Out1, "") 602 switch _, isProduced := produced[n.Out1.Block]; { 603 case isProduced: 604 g.w("\n\tgoto l%d;", labels[n.Out1.Block]) 605 default: 606 g.block(ctx, n.Out1, produced, labels, false) 607 } 608 case Jnz: 609 _, nzProduced := produced[n.Out1.Block] 610 _, zProduced := produced[n.Out2.Block] 611 switch { 612 case nzProduced && zProduced: 613 g.w("\n\tif (") 614 g.operand(ctx, x.Value, nil, false) 615 g.w(") {") 616 g.setPhis(ctx, n, n.Out1, "\t") 617 g.w("\n\t\tgoto l%d;\n\t} else {", labels[n.Out1.Block]) 618 g.setPhis(ctx, n, n.Out2, "\t") 619 g.w("\n\t\tgoto l%d;\n\t}", labels[n.Out2.Block]) 620 case nzProduced && !zProduced: 621 g.w("\n\tif (") 622 g.operand(ctx, x.Value, nil, false) 623 g.w(") {") 624 g.setPhis(ctx, n, n.Out1, "\t") 625 g.w("\n\t\tgoto l%d;\n\t}", labels[n.Out1.Block]) 626 g.setPhis(ctx, n, n.Out2, "") 627 g.block(ctx, n.Out2, produced, labels, false) 628 case !nzProduced && zProduced: 629 g.w("\n\tif (!") 630 g.operand(ctx, x.Value, nil, false) 631 g.w(") {") 632 g.setPhis(ctx, n, n.Out2, "\t") 633 g.w("\n\t\tgoto l%d;\n\t}", labels[n.Out2.Block]) 634 g.setPhis(ctx, n, n.Out1, "") 635 g.block(ctx, n.Out1, produced, labels, false) 636 case !nzProduced && !zProduced: 637 g.w("\n\tif (") 638 g.operand(ctx, x.Value, nil, false) 639 g.w(") {") 640 g.setPhis(ctx, n, n.Out1, "\t") 641 g.w("\n\t\tgoto l%d;\n\t}", labels[n.Out1.Block]) 642 g.setPhis(ctx, n, n.Out2, "") 643 g.block(ctx, n.Out2, produced, labels, false) 644 g.block(ctx, n.Out1, produced, labels, false) 645 } 646 case Ret: 647 g.w("\n\treturn") 648 switch { 649 case x.Value != nil: 650 g.w(" ") 651 switch y := ctx.f.Result.(type) { 652 case TypeName: 653 switch z := x.Value.(type) { 654 case Global: 655 g.w("*((%s*)(&%s))", g.typ(ctx, ctx.f.Result, false), z.cname()) 656 case Local: 657 info := ctx.f.Scope.node(z.Name).(*LocalInfo) 658 if info.IsParameter { 659 g.w("__v%d", info.N) 660 break 661 } 662 663 switch { 664 case info.IsStruct: 665 g.w("__v%d", info.N) 666 default: 667 g.w("*((%s*)(__v%d))", g.typ(ctx, ctx.f.Result, false), info.N) 668 } 669 default: 670 panic(todo("%v: %T %T", x.Position(), y, z)) 671 } 672 default: 673 g.operand(ctx, x.Value, ctx.f.Result, true) 674 } 675 case ctx.isMain(): 676 g.w(" 0") 677 } 678 g.w(";") 679 default: 680 panic(todo("%v: %T", block.Position(), x)) 681 } 682 } 683 684 func (g *cgen) setPhis(ctx *ctx, n, m *CFGNode, indent string) { 685 for _, phi := range m.Block.Phis { 686 g.setPhi(ctx, phi, n, indent) 687 } 688 } 689 690 func (g *cgen) setPhi(ctx *ctx, n *Phi, from *CFGNode, indent string) { 691 nm := from.Name.Name() 692 for _, arg := range n.Args { 693 if in := arg.Name.Name(); bytes.Equal(nm, in) { 694 g.w("\n\t%s", indent) 695 g.local(ctx, n.Dst) 696 g.w(" = ") 697 g.operand(ctx, arg.Value, n.DstType, true) 698 g.w(";") 699 } 700 } 701 } 702 703 func (g *cgen) inst(ctx *ctx, inst Node, isEntryBlock bool) { 704 pos := inst.Position() 705 var t Type 706 var rparen string 707 indent := true 708 switch inst.(type) { 709 case *Alloc4, *Alloc8, *Alloc16: 710 // nop 711 case *Call, *VaArg: 712 x := inst.(definer) 713 g.w("\n#line %d %q\n\t", pos.Line, pos.Filename) 714 indent = false 715 t = x.preamble().DstType 716 if _, ok := t.(TypeName); ok { 717 info := ctx.f.Scope.node(x.dst().Name).(*LocalInfo) 718 if _, ok := info.Type.(TypeName); !ok { 719 g.w("*((%s*)__v%d) = ", g.typ(ctx, t, false), info.N) 720 break 721 } 722 } 723 724 g.local(ctx, x.dst()) 725 g.w(" = ") 726 case *Copy: 727 x := inst.(definer) 728 t = x.preamble().DstType 729 info := ctx.f.Scope.node(x.dst().Name).(*LocalInfo) 730 g.w("\n#line %d %q\n\t", pos.Line, pos.Filename) 731 indent = false 732 g.local(ctx, x.dst()) 733 g.w(" = ") 734 if g.isPtr(info.Type) { 735 g.w("(void*)(") 736 rparen = ")" 737 } 738 case *Declare: 739 return 740 default: 741 if x, ok := inst.(definer); ok { 742 g.w("\n#line %d %q\n\t", pos.Line, pos.Filename) 743 indent = false 744 t = x.preamble().DstType 745 g.local(ctx, x.dst()) 746 g.w(" = ") 747 info := ctx.f.Scope.node(x.dst().Name).(*LocalInfo) 748 if g.isPtr(info.Type) { 749 g.w("(void*)(") 750 rparen = ")" 751 } 752 } 753 } 754 if indent { 755 g.w("\n#line %d %q\n\t", pos.Line, pos.Filename) 756 } 757 switch x := inst.(type) { 758 case *Copy: 759 g.operand(ctx, x.Value, t, true) 760 case *Sub: 761 g.binary(ctx, x, "-", t, false) 762 case *Add: 763 g.binary(ctx, x, "+", t, false) 764 case *And: 765 g.binary(ctx, x, "&", t, false) 766 case *Xor: 767 g.binary(ctx, x, "^", t, false) 768 case *Or: 769 g.binary(ctx, x, "|", t, false) 770 case *Mul: 771 g.binary(ctx, x, "*", t, false) 772 case *Div: 773 g.binary(ctx, x, "/", t, true) 774 case *Udiv: 775 g.binary(ctx, x, "/", t, false) 776 case *Rem: 777 g.binary(ctx, x, "%", t, true) 778 case *Urem: 779 g.binary(ctx, x, "%", t, false) 780 case *Alloc4: 781 g.alloc(ctx, 4, &x.InstPreamble, x.Value, isEntryBlock) 782 case *Alloc8: 783 g.alloc(ctx, 8, &x.InstPreamble, x.Value, isEntryBlock) 784 case *Alloc16: 785 g.alloc(ctx, 16, &x.InstPreamble, x.Value, isEntryBlock) 786 case *Call: 787 g.call(ctx, &x.VoidCall, t) 788 case *VoidCall: 789 g.call(ctx, x, nil) 790 case *Loadd: 791 g.load(ctx, x.Value, d, false) 792 case *Loadld: 793 g.load(ctx, x.Value, ld, false) 794 case *Loads: 795 g.load(ctx, x.Value, s, false) 796 case *Loadsb: 797 g.load(ctx, x.Value, b, true) 798 case *Loadsh: 799 g.load(ctx, x.Value, h, true) 800 case *Loadsw: 801 g.load(ctx, x.Value, w, true) 802 case *Loadl: 803 g.load(ctx, x.Value, l, true) 804 case *Loadub: 805 g.load(ctx, x.Value, b, false) 806 case *Loaduh: 807 g.load(ctx, x.Value, h, false) 808 case *Loaduw: 809 g.load(ctx, x.Value, w, false) 810 case *Storel: 811 g.store(ctx, x.Dst, x.Src, l) 812 case *Storeb: 813 g.store(ctx, x.Dst, x.Src, b) 814 case *Storeh: 815 g.store(ctx, x.Dst, x.Src, h) 816 case *Storew: 817 g.store(ctx, x.Dst, x.Src, w) 818 case *Stored: 819 g.store(ctx, x.Dst, x.Src, d) 820 case *Storeld: 821 g.store(ctx, x.Dst, x.Src, ld) 822 case *Stores: 823 g.store(ctx, x.Dst, x.Src, s) 824 case *Ceqd: 825 g.binary(ctx, x, "==", d, true) 826 case *Ceqld: 827 g.binary(ctx, x, "==", ld, true) 828 case *Ceql: 829 g.binary(ctx, x, "==", l, true) 830 case *Ceqs: 831 g.binary(ctx, x, "==", s, false) 832 case *Ceqw: 833 g.binary(ctx, x, "==", w, false) 834 case *Cged: 835 g.binary(ctx, x, ">=", d, true) 836 case *Cgeld: 837 g.binary(ctx, x, ">=", ld, true) 838 case *Cges: 839 g.binary(ctx, x, ">=", s, false) 840 case *Cgtd: 841 g.binary(ctx, x, ">", d, true) 842 case *Cgtld: 843 g.binary(ctx, x, ">", ld, true) 844 case *Cgts: 845 g.binary(ctx, x, ">", s, false) 846 case *Cled: 847 g.binary(ctx, x, "<=", d, true) 848 case *Cleld: 849 g.binary(ctx, x, "<=", ld, true) 850 case *Cles: 851 g.binary(ctx, x, "<=", s, false) 852 case *Cltd: 853 g.binary(ctx, x, "<", d, false) 854 case *Cltld: 855 g.binary(ctx, x, "<", ld, false) 856 case *Clts: 857 g.binary(ctx, x, "<", s, false) 858 case *Cned: 859 g.binary(ctx, x, "!=", d, false) 860 case *Cneld: 861 g.binary(ctx, x, "!=", ld, false) 862 case *Cnel: 863 g.binary(ctx, x, "!=", l, false) 864 case *Cnes: 865 g.binary(ctx, x, "!=", s, false) 866 case *Cnew: 867 g.binary(ctx, x, "!=", w, false) 868 case *Csgel: 869 g.binary(ctx, x, ">=", l, true) 870 case *Csgew: 871 g.binary(ctx, x, ">=", w, true) 872 case *Csgtl: 873 g.binary(ctx, x, ">", l, true) 874 case *Csgtw: 875 g.binary(ctx, x, ">", w, true) 876 case *Cslel: 877 g.binary(ctx, x, "<=", l, true) 878 case *Cslew: 879 g.binary(ctx, x, "<=", w, true) 880 case *Csltl: 881 g.binary(ctx, x, "<", l, true) 882 case *Csltw: 883 g.binary(ctx, x, "<", w, true) 884 case *Cugel: 885 g.binary(ctx, x, ">=", l, false) 886 case *Cugew: 887 g.binary(ctx, x, ">=", w, false) 888 case *Cugtl: 889 g.binary(ctx, x, ">", l, false) 890 case *Cugtw: 891 g.binary(ctx, x, ">", w, false) 892 case *Culel: 893 g.binary(ctx, x, "<=", l, false) 894 case *Culew: 895 g.binary(ctx, x, "<=", w, false) 896 case *Cultl: 897 g.binary(ctx, x, "<", l, false) 898 case *Cultw: 899 g.binary(ctx, x, "<", w, false) 900 case *Cuod: 901 panic(todo("")) 902 case *Cuos: 903 panic(todo("")) 904 case *Cod: 905 panic(todo("")) 906 case *Cos: 907 panic(todo("")) 908 case *Exts: 909 g.ext(ctx, x.Value, t, s, false) 910 case *Extd: 911 g.ext(ctx, x.Value, t, d, false) 912 case *Extsb: 913 g.ext(ctx, x.Value, t, b, true) 914 case *Extsh: 915 g.ext(ctx, x.Value, t, h, true) 916 case *Extsw: 917 g.ext(ctx, x.Value, t, w, true) 918 case *Extub: 919 g.ext(ctx, x.Value, t, b, false) 920 case *Extuh: 921 g.ext(ctx, x.Value, t, h, false) 922 case *Extuw: 923 g.ext(ctx, x.Value, t, w, false) 924 case *Sar: 925 g.operand(ctx, x.A, t, true) 926 g.w(" >> ") 927 g.operand(ctx, x.B, nil, false) 928 case *Shr: 929 g.operand(ctx, x.A, t, false) 930 g.w(" >> ") 931 g.operand(ctx, x.B, nil, false) 932 case *Shl: 933 g.operand(ctx, x.A, t, false) 934 g.w(" << ") 935 g.operand(ctx, x.B, nil, false) 936 case *Swtof: 937 g.w("(%s)(", g.typ(ctx, t, false)) 938 g.operand(ctx, x.Value, w, true) 939 g.w(")") 940 case *Uwtof: 941 g.w("(%s)(", g.typ(ctx, t, false)) 942 g.operand(ctx, x.Value, w, false) 943 g.w(")") 944 case *Sltof: 945 g.w("(%s)(", g.typ(ctx, t, false)) 946 g.operand(ctx, x.Value, l, true) 947 g.w(")") 948 case *Ultof: 949 g.w("(%s)(", g.typ(ctx, t, false)) 950 g.operand(ctx, x.Value, l, false) 951 g.w(")") 952 case *Stosi: 953 g.w("(%s)(", g.typ(ctx, t, true)) 954 g.operand(ctx, x.Value, s, true) 955 g.w(")") 956 case *Stoui: 957 g.w("(%s)(", g.typ(ctx, t, false)) 958 g.operand(ctx, x.Value, s, false) 959 g.w(")") 960 case *Dtosi: 961 g.w("(%s)(", g.typ(ctx, t, true)) 962 g.operand(ctx, x.Value, d, true) 963 g.w(")") 964 case *Ldtosi: 965 g.w("(%s)(", g.typ(ctx, t, true)) 966 g.operand(ctx, x.Value, d, true) 967 g.w(")") 968 case *Dtoui: 969 g.w("(%s)(", g.typ(ctx, t, false)) 970 g.operand(ctx, x.Value, d, false) 971 g.w(")") 972 case *Ldtoui: 973 g.w("(%s)(", g.typ(ctx, t, false)) 974 g.operand(ctx, x.Value, d, false) 975 g.w(")") 976 case *Cast: 977 g.cast(ctx, x, t) 978 case *Truncd: 979 g.w("(float)(") 980 g.operand(ctx, x.Value, d, true) 981 g.w(")") 982 case *Truncld: 983 g.w("(%s)(", g.typ(ctx, t, true)) 984 g.operand(ctx, x.Value, ld, true) 985 g.w(")") 986 case *VaStart: 987 if !ctx.f.IsVariadic { 988 g.err(x.off, 0, "not a variadic function: %s", ctx.f.Name.Name()) 989 break 990 } 991 992 params := ctx.f.Params 993 last := params[len(params)-1] 994 lastInfo := ctx.f.Scope.node(last.(*RegularParameter).Name).(*LocalInfo) 995 switch k, x := g.vaListType(ctx, x.Value); k { 996 case vaListLocalPtr: 997 g.w("va_start(*(va_list*)(__v%d), __v%d)", x.(*LocalInfo).N, lastInfo.N) 998 case vaListLocal: 999 g.w("va_start(__v%d, __v%d)", x.(*LocalInfo).N, lastInfo.N) 1000 case vaListGlobal: 1001 g.w("va_start(*(va_list*)(&%s), __v%d)", x.(Global).cname(), lastInfo.N) 1002 default: 1003 panic(todo("%v: %v %T", inst.Position(), k, x)) 1004 } 1005 1006 //TODO- params := ctx.f.Params 1007 //TODO- last := params[len(params)-1] 1008 //TODO- lastInfo := ctx.f.Scope.node(last.(*RegularParameter).Name).(*LocalInfo) 1009 //TODO- switch y := x.Value.(type) { 1010 //TODO- case Local: 1011 //TODO- switch info := ctx.f.Scope.node(y.Name).(*LocalInfo); { 1012 //TODO- case info.IsVaList: 1013 //TODO- g.w("va_start(__v%d, __v%d)", info.N, lastInfo.N) 1014 //TODO- case info.IsVaListPtr: 1015 //TODO- g.w("va_start(*(va_list*)(__v%d), __v%d)", info.N, lastInfo.N) 1016 //TODO- default: 1017 //TODO- panic(todo("")) 1018 //TODO- } 1019 //TODO- default: 1020 //TODO- panic(todo("%v: %T", x.Position(), y)) 1021 //TODO- } 1022 case *VaArg: 1023 switch k, x := g.vaListType(ctx, x.Value); k { 1024 case vaListLocalPtr: 1025 g.w("va_arg(*(va_list*)(__v%d), %s)", x.(*LocalInfo).N, g.typ(ctx, t, true)) 1026 case vaListLocal: 1027 g.w("va_arg(__v%d, %s)", x.(*LocalInfo).N, g.typ(ctx, t, true)) 1028 case vaListGlobal: 1029 g.w("va_arg(*(va_list*)(&%s), %s)", x.(Global).cname(), g.typ(ctx, t, true)) 1030 default: 1031 panic(todo("%v: %v %T", inst.Position(), k, x)) 1032 } 1033 1034 //TODO- switch y := x.Value.(type) { 1035 //TODO- case Local: 1036 //TODO- switch info := ctx.f.Scope.node(y.Name).(*LocalInfo); { 1037 //TODO- case info.IsVaList: 1038 //TODO- g.w("va_arg(__v%d, %s)", info.N, g.typ(ctx, t, true)) 1039 //TODO- case info.IsVaListPtr: 1040 //TODO- g.w("va_arg(*(va_list*)(__v%d), %s)", info.N, g.typ(ctx, t, true)) 1041 //TODO- default: 1042 //TODO- panic(todo("")) 1043 //TODO- } 1044 //TODO- case Global: 1045 //TODO- panic(todo("%v: %T", x.Position(), y)) 1046 //TODO- default: 1047 //TODO- panic(todo("%v: %T", x.Position(), y)) 1048 //TODO- } 1049 default: 1050 panic(todo("%v: %T", inst.Position(), x)) 1051 } 1052 g.w("%s;", rparen) 1053 } 1054 1055 const ( 1056 vaListLocalPtr = iota 1057 vaListLocal 1058 vaListGlobal 1059 ) 1060 1061 func (g *cgen) vaListType(ctx *ctx, n Node) (int, interface{}) { 1062 switch x := n.(type) { 1063 case Local: 1064 info := ctx.f.Scope.node(x.Name).(*LocalInfo) 1065 switch y := info.Type.(type) { 1066 case Int32, Int64: 1067 return vaListLocalPtr, info 1068 case TypeName: 1069 switch string(y.Src()[1:]) { 1070 case VaList: 1071 if info.IsParameter { 1072 return vaListLocal, info 1073 } 1074 1075 panic(todo("%v: %q", n.Position(), string(y.Src()[1:]))) 1076 default: 1077 panic(todo("%v: %q", n.Position(), string(y.Src()[1:]))) 1078 } 1079 case VoidPointer: 1080 return vaListLocalPtr, info 1081 default: 1082 panic(todo("%v: %T", n.Position(), y)) 1083 } 1084 case Global: 1085 return vaListGlobal, x 1086 default: 1087 panic(todo("%v: %T", n.Position(), x)) 1088 } 1089 } 1090 1091 func (g *cgen) isPtr(t Type) (r bool) { 1092 switch t.(type) { 1093 case CharPointer, VoidPointer: 1094 return true 1095 } 1096 1097 return false 1098 } 1099 1100 func (g *cgen) cast(ctx *ctx, n *Cast, t Type) { 1101 dst := ctx.f.Scope.node(n.Dst.Name).(*LocalInfo) 1102 switch x := n.Value.(type) { 1103 case Local: 1104 src := ctx.f.Scope.node(x.Name).(*LocalInfo) 1105 switch y := src.Type.(type) { 1106 case Float64: 1107 switch z := dst.Type.(type) { 1108 case Int64: 1109 g.w("(union {double d; int64_t i;}){__v%d}.i", src.N) 1110 default: 1111 panic(todo("%v: %T", n.Position(), z)) 1112 } 1113 case Float32: 1114 switch z := dst.Type.(type) { 1115 case Int32: 1116 g.w("(union {float f; int32_t i;}){__v%d}.i", src.N) 1117 default: 1118 panic(todo("%v: %T", n.Position(), z)) 1119 } 1120 case Int64: 1121 switch z := dst.Type.(type) { 1122 case Float64: 1123 g.w("(union {int64_t i; double d;}){__v%d}.d", src.N) 1124 default: 1125 panic(todo("%v: %T", n.Position(), z)) 1126 } 1127 case Int32: 1128 switch z := dst.Type.(type) { 1129 case Float32: 1130 g.w("(union {int32_t i; float f;}){__v%d}.f", src.N) 1131 default: 1132 panic(todo("%v: %T", n.Position(), z)) 1133 } 1134 default: 1135 panic(todo("%v: %T", n.Position(), y)) 1136 } 1137 default: 1138 panic(todo("%v: %T", n.Position(), x)) 1139 } 1140 } 1141 1142 func (g *cgen) ext(ctx *ctx, val Node, to, t Type, signed bool) { 1143 g.w("(%s)(", g.typ(ctx, to, true)) 1144 g.operand(ctx, val, t, signed) 1145 g.w(")") 1146 } 1147 1148 func (g *cgen) alloc(ctx *ctx, n int, pre *InstPreamble, val Node, isEntryBlock bool) { 1149 info := ctx.f.Scope.node(pre.Dst.Name).(*LocalInfo) 1150 switch { 1151 case isEntryBlock && info.Written == 1 && g.isNumericConstant(val): 1152 g.w("int8_t m") 1153 g.w("__v%d[", info.N) 1154 g.operand(ctx, val, nil, true) 1155 g.w("] __attribute__ ((aligned (%d)));", n) 1156 g.w("\n\t") 1157 g.local(ctx, pre.Dst) 1158 g.w(" = (intptr_t)&m") 1159 g.local(ctx, pre.Dst) 1160 default: 1161 g.local(ctx, pre.Dst) 1162 g.w(" = (intptr_t)alloca((size_t)(") 1163 g.operand(ctx, val, nil, true) 1164 g.w(" + %d));", n-1) 1165 g.w("\n\t") 1166 g.local(ctx, pre.Dst) 1167 g.w(" = ") 1168 g.local(ctx, pre.Dst) 1169 g.w("&%d ? ", n-1) 1170 g.local(ctx, pre.Dst) 1171 g.w(" + %d - (", n) 1172 g.local(ctx, pre.Dst) 1173 g.w("&%d) : ", n-1) 1174 g.local(ctx, pre.Dst) 1175 } 1176 } 1177 1178 func (g *cgen) isNumericConstant(n Node) bool { 1179 switch n.(type) { 1180 case IntLit, Float32Lit, Float64Lit, LongDoubleLit: 1181 return true 1182 default: 1183 panic(todo("%v: %T", n.Position(), n)) 1184 } 1185 } 1186 1187 func (g *cgen) store(ctx *ctx, dst, src Node, t Type) { 1188 if local, ok := src.(Local); ok { 1189 info := ctx.f.Scope.node(local.Name).(*LocalInfo) 1190 if _, ok := info.Type.(TypeName); ok { 1191 g.w("*(intptr_t*)(") 1192 g.operand(ctx, dst, nil, true) 1193 g.w(") = ") 1194 g.operand(ctx, src, t, true) 1195 return 1196 } 1197 } 1198 1199 g.w("*(%s*)((intptr_t)", g.typ(ctx, t, true)) 1200 g.operand(ctx, dst, nil, true) 1201 g.w(") = ") 1202 g.operand(ctx, src, t, true) 1203 } 1204 1205 func (g *cgen) load(ctx *ctx, mem Node, t Type, signed bool) { 1206 if local, ok := mem.(Local); ok { 1207 info := ctx.f.Scope.node(local.Name).(*LocalInfo) 1208 if _, ok := info.Type.(TypeName); ok { 1209 g.w("*(%s*)(&__v%d)", g.typ(ctx, t, false), info.N) 1210 return 1211 } 1212 } 1213 1214 g.w("*(%s*)((intptr_t)", g.typ(ctx, t, signed)) 1215 g.operand(ctx, mem, nil, false) 1216 g.w(")") 1217 } 1218 1219 func (g *cgen) call(ctx *ctx, n *VoidCall, t Type) { 1220 args := g.callArgs(ctx, n) 1221 switch x := n.Value.(type) { 1222 case Global: 1223 nm := x.cname() 1224 s := string(nm) 1225 if g.os == "windows" && (s == "alloca" || s == "_alloca") { 1226 s = "__builtin_alloca" 1227 } 1228 if _, ok := g.declaredExternPrototypes[s]; ok { 1229 g.w("%s", nm) 1230 break 1231 } 1232 1233 if strings.HasPrefix(s, "__builtin_") { 1234 g.w("%s", nm) 1235 break 1236 } 1237 1238 if s == "__qbe_va_end" { 1239 g.w("va_end") 1240 break 1241 } 1242 1243 if s == "__qbe_va_copy" { 1244 g.w("va_copy") 1245 break 1246 } 1247 1248 if rt, ok := g.ast.ExternFuncs[s]; ok { 1249 g.w("((%s(*)(%s))(%s))", g.typ(ctx, rt, true), args, nm) 1250 break 1251 } 1252 1253 if _, ok := g.ast.Funcs[s]; ok { 1254 g.w("%s", nm) 1255 break 1256 } 1257 1258 g.w("((%s(*)(%s))(%s))", g.typ(ctx, t, true), args, nm) 1259 case Local: 1260 info := ctx.f.Scope.node(x.Name).(*LocalInfo) 1261 g.w("((%s(*)(%s))(__v%d))", g.typ(ctx, t, false), args, info.N) 1262 default: 1263 panic(todo("%v: %T", n.Position(), x)) 1264 } 1265 g.w("(") 1266 for i, arg := range n.Args { 1267 switch x := arg.(type) { 1268 case *RegularArg: 1269 switch y := x.Type.(type) { 1270 case TypeName: 1271 var isValist, isValistPtr bool 1272 switch y.String()[1:] { 1273 case VaList: 1274 isValist = true 1275 case VaListPtr: 1276 isValistPtr = true 1277 } 1278 switch z := x.Value.(type) { 1279 case Global: 1280 switch { 1281 case isValist: 1282 g.w("*(va_list*)(&%s)", z.cname()) 1283 case isValistPtr: 1284 panic(todo("")) 1285 default: 1286 g.w("*((%s*)(&%s))", g.typ(ctx, x.Type, false), z.cname()) 1287 } 1288 case Local: 1289 info := ctx.f.Scope.node(z.Name).(*LocalInfo) 1290 switch { 1291 case isValist: 1292 g.w("__v%d", info.N) 1293 case isValistPtr: 1294 g.w("*(va_list*)(__v%d)", info.N) 1295 default: 1296 if id, ok := ctx.types[string(y.Name.Name())]; ok { 1297 switch info.Type.(type) { 1298 case TypeName: 1299 g.w("__v%d", info.N) 1300 default: 1301 g.w("*((%s%d*)(__v%d))", typePrefix, id, info.N) 1302 } 1303 break 1304 } 1305 1306 switch { 1307 case info.IsStruct: 1308 g.w("__v%d", info.N) 1309 case info.Type == c: 1310 panic(todo("", n.Position())) 1311 case g.isPtr(info.Type): 1312 g.w("(void*)(__v%d)", info.N) 1313 default: 1314 g.w("*((%s*)(__v%d))", g.typ(ctx, x.Type, false), info.N) 1315 } 1316 } 1317 default: 1318 panic(todo("")) 1319 } 1320 default: 1321 g.operand(ctx, x.Value, x.Type, true) 1322 } 1323 default: 1324 panic(todo("%v: %T", arg.Position(), x)) 1325 } 1326 if i != len(n.Args)-1 { 1327 g.w(", ") 1328 } 1329 } 1330 g.w(")") 1331 } 1332 1333 func (g *cgen) callArgs(ctx *ctx, n *VoidCall) string { 1334 if len(n.Args) == 0 { 1335 return "void" 1336 } 1337 1338 var a []string 1339 for _, v := range n.Args { 1340 switch x := v.(type) { 1341 case *RegularArg: 1342 a = append(a, g.typ(ctx, x.Type, true)) 1343 default: 1344 panic(todo("%v: %T", v.Position(), x)) 1345 } 1346 } 1347 if n.IsVariadic { 1348 a = append(a, "...") 1349 } 1350 return strings.Join(a, ", ") 1351 } 1352 1353 func (g *cgen) binary(ctx *ctx, n binaryOp, op string, t Type, signed bool) { 1354 a := g.operand(ctx, n.a(), t, signed) 1355 g.w(" %s ", op) 1356 b := g.operand(ctx, n.b(), t, signed) 1357 if a != nil && b != nil && !a.isCompatible(b) { 1358 g.err(n.off(), 0, "operand types don't match: %v, %v", a, b) 1359 return 1360 } 1361 } 1362 1363 func (g *cgen) operand(ctx *ctx, n Node, t Type, signed bool) (localType Type) { 1364 switch x := n.(type) { 1365 case IntLit: 1366 v := x.Value() 1367 switch y := t.(type) { 1368 case Int32: 1369 switch { 1370 case signed: 1371 g.w("(int32_t)(%du)", uint32(v)) 1372 default: 1373 g.w("%du", uint32(v)) 1374 } 1375 case Int64: 1376 switch { 1377 case signed: 1378 g.w("(int64_t)(%dull)", v) 1379 default: 1380 g.w("%dull", v) 1381 } 1382 case Int16: 1383 switch { 1384 case signed: 1385 g.w("(int16_t)(%du)", uint16(v)) 1386 default: 1387 g.w("(uint16_t)(%du)", uint16(v)) 1388 } 1389 case Int8: 1390 switch { 1391 case signed: 1392 g.w("(int8_t)(%du)", uint8(v)) 1393 default: 1394 g.w("(uint8_t)(%du)", uint8(v)) 1395 } 1396 case CharPointer: 1397 g.w("(char*)(%du)", uint64(v)) 1398 case VoidPointer: 1399 g.w("(void*)(%du)", uint64(v)) 1400 case nil: 1401 g.w("%d", v) 1402 case Float64: 1403 g.doubleCString(math.Float64frombits(v)) 1404 case Float32: 1405 g.floatCString(math.Float32frombits(uint32(v))) 1406 case LongDouble: 1407 g.w("%d", v) 1408 default: 1409 panic(todo("%v: %T %q", n.Position(), y, v)) 1410 } 1411 case Local: 1412 nm := x.Name.Name() 1413 info := ctx.f.Scope.node(x.Name).(*LocalInfo) 1414 switch t.(type) { 1415 case TypeName: 1416 switch x := info.Type.(type) { 1417 case Int32, Int64: 1418 panic(todo("", n.Position())) 1419 g.w("*((%s*)(__v%d))", g.typ(ctx, t, false), info.N) 1420 case TypeName: 1421 panic(todo("", n.Position())) 1422 g.w("__v%d", info.N) 1423 default: 1424 panic(todo("%v: %T -> %T", n.Position(), x, t)) 1425 } 1426 panic(todo("%v: %T -> %T", n.Position(), x, t)) 1427 return 1428 } 1429 1430 switch x := info.Type.(type) { 1431 case TypeName: 1432 switch y := t.(type) { 1433 case Int32, Int64: 1434 g.w("(intptr_t)(&__v%d)", info.N) 1435 return g.ptr 1436 case TypeName: 1437 panic(todo("", n.Position())) 1438 g.w("__v%d", info.N) 1439 return g.ptr 1440 case nil: // lhs 1441 g.w("(intptr_t)(&__v%d)", info.N) 1442 return g.ptr 1443 case VoidPointer, CharPointer: 1444 g.w("(void*)(&__v%d)", info.N) 1445 return g.ptr 1446 default: 1447 panic(todo("%v: %T -> %T", n.Position(), x, y)) 1448 } 1449 } 1450 1451 switch { 1452 case signed: 1453 switch { 1454 case t == nil: 1455 g.w("__v%d", info.N) 1456 case t != info.Type: 1457 g.w("(%s)(__v%d)", g.typ(ctx, t, true), info.N) 1458 default: 1459 g.w("__v%d", info.N) 1460 } 1461 default: 1462 switch { 1463 case t == nil: 1464 g.w("__v%d", info.N) 1465 case t != info.Type: 1466 g.w("(%s)(__v%d)", g.typ(ctx, t, false), info.N) 1467 default: 1468 g.w("(%s)(__v%d)", g.typ(ctx, info.Type, false), info.N) 1469 } 1470 } 1471 g.w(" /* %s */", nm) 1472 return info.Type 1473 case Global: 1474 switch { 1475 case t != nil: 1476 g.w("(%s)(&%s)", g.typ(ctx, t, true), x.cname()) 1477 default: 1478 g.w("(&%s)", x.cname()) 1479 } 1480 case Float64Lit: 1481 g.doubleCString(x.Value()) 1482 case Float32Lit: 1483 g.floatCString(x.Value()) 1484 case LongDoubleLit: 1485 g.w("%s", longDoubleCString(x.Value())) 1486 case StringLit: 1487 switch t.(type) { 1488 case Int32, Int64: 1489 g.w("(%s)", g.typ(ctx, t, false)) 1490 case VoidPointer, CharPointer, nil: 1491 // ok 1492 default: 1493 panic(todo("%T", t)) 1494 } 1495 g.w("%s", safeQuoteToASCII(string(x.Value()))) 1496 default: 1497 panic(todo("%v: %T", n.Position(), x)) 1498 } 1499 return nil 1500 } 1501 1502 func (g *cgen) doubleCString(v float64) { 1503 switch { 1504 case math.IsInf(v, -1): 1505 g.w("(-1.0/0.0)") 1506 case math.IsInf(v, 1): 1507 g.w("(1.0/0.0)") 1508 case math.IsNaN(v): 1509 g.w("(1.0/0.0 - 1.0/0.0)") 1510 default: 1511 g.w("%x", v) 1512 } 1513 } 1514 1515 func (g *cgen) floatCString(v float32) { 1516 switch v64 := float64(v); { 1517 case math.IsInf(v64, -1): 1518 g.w("(-1.0f/0.0f)") 1519 case math.IsInf(v64, 1): 1520 g.w("(1.0f/0.0f)") 1521 case math.IsNaN(v64): 1522 g.w("(1.0f/0.0f - 1.0f/0.0f)") 1523 default: 1524 g.w("%x", v) 1525 } 1526 } 1527 1528 func (g *cgen) local(ctx *ctx, n Local) { 1529 nm := n.Name.Name() 1530 info := ctx.f.Scope.node(n.Name).(*LocalInfo) 1531 g.w("__v%d /* %s */", info.N, nm) 1532 } 1533 1534 func (g *cgen) types() (r map[string]int) { 1535 ctx := &ctx{} 1536 for _, def := range g.ast.Defs { 1537 switch x := def.(type) { 1538 case *TypeDef: 1539 if r == nil { 1540 r = make(map[string]int, len(g.ast.Defs)) 1541 ctx.types = r 1542 } 1543 r[string(x.Name.Name())] = len(r) + 1 1544 if len(x.Fields) == 1 { 1545 if y, ok := x.Fields[0].(UnionField); ok { 1546 g.w("\n\ntypedef struct { int8_t f[%d]; } %s%d", IntLit(y).Value(), typePrefix, len(r)) 1547 if x.Align != 0 { 1548 g.w(" __attribute__ ((aligned (%d)))", x.Align) 1549 } 1550 g.w(";") 1551 continue 1552 } 1553 } 1554 1555 g.w("\n\ntypedef ") 1556 g.structType(ctx, x.Fields) 1557 g.w(" %s%d", typePrefix, len(r)) 1558 if x.Align != 0 { 1559 g.w(" __attribute__ ((aligned (%d)))", x.Align) 1560 } 1561 g.w(";") 1562 } 1563 } 1564 return r 1565 } 1566 1567 func (g *cgen) structType(ctx *ctx, fields []Node) { 1568 g.w("struct {") 1569 for i, v := range fields { 1570 switch x := v.(type) { 1571 case Field: 1572 g.w("\n\t%s f%d;", g.typ(ctx, x.Type, true), i) 1573 case StructField: 1574 g.w("\n\t") 1575 g.structType(ctx, x.Fields) 1576 g.w(" f%d;", i) 1577 case ArrayField: 1578 g.w("\n\t%s f%d[%d];", g.typ(ctx, x.Type, true), i, x.Len) 1579 default: 1580 panic(todo("%v: %T", v.Position(), x)) 1581 } 1582 } 1583 g.w("\n}") 1584 }