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  }