modernc.org/qbe@v0.0.9/cc/init.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  package cc // import "modernc.org/qbe/cc"
     6  
     7  import (
     8  	"math"
     9  
    10  	"modernc.org/cc/v3"
    11  )
    12  
    13  type ptrInitializer struct {
    14  	op  operand
    15  	off uintptr
    16  }
    17  
    18  type initializer struct {
    19  	b    []byte
    20  	g    *gen
    21  	lds  map[uintptr]cc.Value
    22  	more []*initializer
    23  	nm   string
    24  	ptrs map[uintptr]*ptrInitializer
    25  	t    cc.Type
    26  }
    27  
    28  func (g *gen) newInitializer(t cc.Type, nm string) *initializer {
    29  	return &initializer{
    30  		b:  make([]byte, t.Size()),
    31  		g:  g,
    32  		nm: nm,
    33  		t:  t,
    34  	}
    35  }
    36  
    37  func (c *initializer) initializerArithmetic(t cc.Type, f cc.Field, n *cc.AssignmentExpression, off uintptr) {
    38  	if n.Operand.IsZero() && n.Operand.Type().IsIntegerType() {
    39  		return
    40  	}
    41  
    42  	if t.IsIntegerType() {
    43  		var v uint64
    44  		switch x := n.Operand.Value().(type) {
    45  		case cc.Int64Value:
    46  			v = uint64(x)
    47  		case cc.Uint64Value:
    48  			v = uint64(x)
    49  		case cc.Float64Value:
    50  			v = uint64(int64(x))
    51  		default:
    52  			panic(todo(""))
    53  		}
    54  		c.initializerUint64(t, f, n, v, off)
    55  		return
    56  	}
    57  
    58  	switch t.Kind() {
    59  	case cc.Float:
    60  		switch x := n.Operand.Value().(type) {
    61  		case cc.Float64Value:
    62  			c.initializerUint64(t, f, n, uint64(math.Float32bits(float32(x))), off)
    63  		case cc.Float32Value:
    64  			c.initializerUint64(t, f, n, uint64(math.Float32bits(float32(x))), off)
    65  		case cc.Int64Value:
    66  			c.initializerUint64(t, f, n, uint64(math.Float32bits(float32(x))), off)
    67  		case cc.Uint64Value:
    68  			c.initializerUint64(t, f, n, uint64(math.Float32bits(float32(x))), off)
    69  		default:
    70  			panic(todo("%T", x))
    71  		}
    72  	case cc.Double:
    73  		switch x := n.Operand.Value().(type) {
    74  		case cc.Float64Value:
    75  			c.initializerUint64(t, f, n, math.Float64bits(float64(x)), off)
    76  		case cc.Float32Value:
    77  			c.initializerUint64(t, f, n, math.Float64bits(float64(x)), off)
    78  		case cc.Int64Value:
    79  			c.initializerUint64(t, f, n, math.Float64bits(float64(x)), off)
    80  		case cc.Uint64Value:
    81  			c.initializerUint64(t, f, n, math.Float64bits(float64(x)), off)
    82  		default:
    83  			panic(todo("%T", x))
    84  		}
    85  	case cc.LongDouble:
    86  		c.setLongDouble(off, n.Operand.Value())
    87  	default:
    88  		panic(todo("%v: %v, %v, %T(%[4]v)", n.Position(), t, t.Kind(), n.Operand.Value()))
    89  	}
    90  }
    91  
    92  func (c *initializer) setLongDouble(off uintptr, v cc.Value) {
    93  	if c.lds == nil {
    94  		c.lds = map[uintptr]cc.Value{}
    95  	}
    96  	c.lds[off] = v
    97  	// Must set the target bytes to be non zero b/c of how .emit() works
    98  	// when finding any trailing zeros.
    99  	for i := 0; i < int(c.g.cLongDouble.Size()); i++ {
   100  		c.b[off+uintptr(i)] = ^byte(0)
   101  	}
   102  }
   103  
   104  func (c *initializer) initializerUint64(t cc.Type, f cc.Field, n cc.Node, v uint64, off uintptr) {
   105  	if v == 0 {
   106  		return
   107  	}
   108  
   109  	sz := t.Size()
   110  	if t.IsBitFieldType() {
   111  		if l := uintptr(len(c.b)); off+sz > l {
   112  			sz = l - off
   113  		}
   114  		var raw uint64
   115  		switch sz {
   116  		case 1:
   117  			raw = uint64(c.b[off])
   118  		case 2:
   119  			raw = uint64(c.g.abi.ByteOrder.Uint16(c.b[off:]))
   120  		case 4:
   121  			raw = uint64(c.g.abi.ByteOrder.Uint32(c.b[off:]))
   122  		case 8:
   123  			raw = c.g.abi.ByteOrder.Uint64(c.b[off:])
   124  		default:
   125  			c.g.errList.err(n, "unexpected/invalid sizeof(%s): %v -> %v, off %#x, len(c.b) %v", t, t.Size(), sz, off, len(c.b))
   126  			return
   127  		}
   128  		raw &^= f.Mask()
   129  		v <<= uint(f.BitFieldOffset())
   130  		v &= f.Mask()
   131  		v |= raw
   132  	}
   133  
   134  	switch sz {
   135  	case 1:
   136  		c.b[off] = byte(v)
   137  	case 2:
   138  		c.g.abi.ByteOrder.PutUint16(c.b[off:], uint16(v))
   139  	case 4:
   140  		c.g.abi.ByteOrder.PutUint32(c.b[off:], uint32(v))
   141  	case 8:
   142  		c.g.abi.ByteOrder.PutUint64(c.b[off:], v)
   143  	default:
   144  		panic(todo(""))
   145  	}
   146  }
   147  
   148  func (c *initializer) emit() {
   149  	g := c.g
   150  	sz := len(c.b)
   151  	for n := sz; n > 0; n-- {
   152  		if c.b[n-1] != 0 {
   153  			break
   154  		}
   155  
   156  		c.b = c.b[:n-1]
   157  	}
   158  	switch {
   159  	case len(c.b) == 0:
   160  		g.w(" z %d", sz)
   161  	default:
   162  		typ := ""
   163  		for off := uintptr(0); off < uintptr(len(c.b)); {
   164  			if ptr, ok := c.ptrs[off]; ok {
   165  				if typ != "" {
   166  					g.w(",")
   167  				}
   168  				g.w(` %s %s`, g.ptr, ptr.op)
   169  				if ptr.off != 0 {
   170  					g.w("%+d", ptr.off)
   171  				}
   172  				typ = g.ptr
   173  				off += c.g.cPtr.Size()
   174  				continue
   175  			}
   176  
   177  			if ld, ok := c.lds[off]; ok {
   178  				if typ != "" {
   179  					g.w(",")
   180  				}
   181  				g.w(` ld %s`, c.g.longDoubleString(nil, ld))
   182  				typ = "ld"
   183  				off += c.g.cLongDouble.Size()
   184  				continue
   185  			}
   186  
   187  			v := c.b[off]
   188  			switch typ {
   189  			case "l", "w", "ld":
   190  				g.w(", b")
   191  				typ = "b"
   192  			case "":
   193  				g.w(" b")
   194  				typ = "b"
   195  			}
   196  			g.w(" %d", v)
   197  			off++
   198  		}
   199  		if len(c.b) != sz {
   200  			g.w(", z %d ", sz-len(c.b))
   201  		}
   202  	}
   203  }
   204  
   205  func (c *initializer) initializerArrayWideString(t cc.Type, n cc.Node, sid cc.StringID, off uintptr) {
   206  	s := []rune(sid.String())
   207  	if uintptr(len(s)) > t.Len() {
   208  		panic(todo(""))
   209  	}
   210  
   211  	sz := t.Elem().Size()
   212  	for i, r := range s {
   213  		c.initializerUint64(t.Elem(), nil, n, uint64(r), off+uintptr(i)*sz)
   214  	}
   215  }
   216  
   217  func (c *initializer) initializerPointer(t cc.Type, f cc.Field, n *cc.AssignmentExpression, off uintptr) {
   218  	if n.Operand.IsZero() {
   219  		return
   220  	}
   221  
   222  	switch x := n.Operand.Value().(type) {
   223  	case cc.StringValue:
   224  		switch t.Elem().Kind() {
   225  		case cc.Char, cc.SChar, cc.UChar, cc.Void:
   226  			c.setPtr(off, c.g.stringLit(n, x), n.Operand.Offset())
   227  		default:
   228  			panic(todo("", n.Position()))
   229  		}
   230  	case nil:
   231  		if d := n.Operand.Declarator(); d != nil {
   232  			switch d.Linkage {
   233  			case cc.External, cc.Internal:
   234  				c.setPtr(off, c.g.tldDeclarator(d, d.Type()), n.Operand.Offset())
   235  				return
   236  			default:
   237  				if info := c.g.declaratorInfos[d]; info != nil && info.static {
   238  					c.setPtr(off, info.op, n.Operand.Offset())
   239  					return
   240  				}
   241  
   242  				panic(todo("%v: %v: %s, link %v", n.Position(), d.Position(), d.Name(), d.Linkage))
   243  			}
   244  		}
   245  
   246  		panic(todo("%v:", n.Position()))
   247  	case *cc.InitializerValue:
   248  		op := c.g.newStaticGlobal()
   249  		c.setPtr(off, op, 0)
   250  		in := c.g.newInitializer(n.Operand.Type().Elem(), op.String())
   251  		c.g.initializer(in, x.List(), 0)
   252  		c.more = append(c.more, in)
   253  	case cc.Uint64Value:
   254  		c.initializerUint64(t, f, n, uint64(x), off)
   255  	default:
   256  		panic(todo("%v: %T", n.Position(), n.Operand.Value()))
   257  	}
   258  }
   259  
   260  func (c *initializer) setPtr(off uintptr, ptr operand, delta uintptr) {
   261  	if c.ptrs == nil {
   262  		c.ptrs = map[uintptr]*ptrInitializer{}
   263  	}
   264  	c.ptrs[off] = &ptrInitializer{ptr, delta}
   265  	// Must set the target bytes to be non zero b/c of how .emit() works
   266  	// when finding any trailing zeros.
   267  	for i := 0; i < int(c.g.cPtr.Size()); i++ {
   268  		c.b[off+uintptr(i)] = ^byte(0)
   269  	}
   270  }
   271  
   272  func (g *gen) initializer(w *initializer, list []*cc.Initializer, off0 uintptr) {
   273  	for _, n := range list {
   274  		expr := n.AssignmentExpression
   275  		t := n.Type()
   276  		off := off0 + n.Offset
   277  		if t.IsArithmeticType() {
   278  			w.initializerArithmetic(t, n.Field, expr, off)
   279  			continue
   280  		}
   281  
   282  		switch t.Kind() {
   283  		case cc.Ptr:
   284  			w.initializerPointer(t, n.Field, expr, off)
   285  		case cc.Array:
   286  			switch e := t.Elem(); e.Kind() {
   287  			case cc.Char, cc.SChar, cc.UChar:
   288  				w.initializerArrayString(t, n, cc.StringID(expr.Operand.Value().(cc.StringValue)), off)
   289  			case g.wchar.Kind():
   290  				w.initializerArrayWideString(t, n, cc.StringID(expr.Operand.Value().(cc.WideStringValue)), off)
   291  			default:
   292  				panic(todo(""))
   293  			}
   294  		case cc.Struct, cc.Union:
   295  			w.initializerArithmetic(t, n.Field, expr, off)
   296  		default:
   297  			panic(todo("%v: %v, %v", n.Position(), t, t.Kind()))
   298  		}
   299  	}
   300  }
   301  
   302  func (c *initializer) initializerArrayString(t cc.Type, n cc.Node, sid cc.StringID, off uintptr) {
   303  	s := sid.String()
   304  	if t.IsIntegerType() {
   305  		panic(todo("", n.Position(), t))
   306  	}
   307  
   308  	if uintptr(len(s)) > t.Len() {
   309  		s = s[:t.Len()]
   310  	}
   311  	for i := 0; i < len(s); i++ {
   312  		c.initializerUint64(t.Elem(), nil, n, uint64(s[i]), off+uintptr(i))
   313  	}
   314  }
   315  
   316  func (g *gen) isConstInitializer(n *cc.Initializer) bool {
   317  	if n.IsConst() {
   318  		return true
   319  	}
   320  
   321  	if e := n.AssignmentExpression; e != nil {
   322  		if e.Operand == nil {
   323  			panic(todo("", n.Position()))
   324  		}
   325  
   326  		if x, ok := e.Operand.Value().(*cc.InitializerValue); ok && x.IsConst() {
   327  			return true
   328  		}
   329  	}
   330  
   331  	for list := n.InitializerList; list != nil; list = list.InitializerList {
   332  		if !g.isConstInitializer(list.Initializer) {
   333  			return false
   334  		}
   335  	}
   336  
   337  	e := n.AssignmentExpression
   338  	if e == nil {
   339  		return true
   340  	}
   341  
   342  	switch t := e.Operand.Type().Decay(); t.Kind() {
   343  	case cc.Function:
   344  		return true
   345  	case cc.Ptr:
   346  		if d := e.Operand.Declarator(); d != nil && d.StorageClass == cc.Static {
   347  			return true
   348  		}
   349  	}
   350  
   351  	return false
   352  }