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 }