alloc.mx raw
1 package emit
2
3 import (
4 "git.smesh.lol/moxie/pkg/syntax"
5 "git.smesh.lol/moxie/pkg/ssa"
6 "git.smesh.lol/moxie/pkg/token"
7 "git.smesh.lol/moxie/pkg/types"
8 )
9
10 func (e *irEmitter) emitInstr(instr ssa.SSAInstruction) {
11 switch i := instr.(type) {
12 case *ssa.SSAAlloc:
13 if e.hoisted != nil && e.hoisted[i] {
14 break
15 }
16 e.emitAlloc(i)
17 case *ssa.SSAStore:
18 e.emitStore(i)
19 case *ssa.SSABinOp:
20 e.emitBinOp(i)
21 case *ssa.SSAUnOp:
22 e.emitUnOp(i)
23 case *ssa.SSACall:
24 e.emitCall(i)
25 case *ssa.SSAPhi:
26 e.emitPhi(i)
27 case *ssa.SSAReturn:
28 e.emitReturn(i)
29 case *ssa.SSAJump:
30 e.emitJump(i)
31 case *ssa.SSAIf:
32 e.emitIf(i)
33 case *ssa.SSAConvert:
34 e.emitConvert(i)
35 case *ssa.SSAChangeType:
36 e.emitChangeType(i)
37 case *ssa.SSAFieldAddr:
38 e.emitFieldAddr(i)
39 case *ssa.SSAIndexAddr:
40 e.emitIndexAddr(i)
41 case *ssa.SSAExtract:
42 e.emitExtract(i)
43 case *ssa.SSAMakeSlice:
44 e.emitMakeSlice(i)
45 case *ssa.SSASlice:
46 e.emitSliceOp(i)
47 case *ssa.SSAMakeInterface:
48 e.emitMakeInterface(i)
49 case *ssa.SSAInvoke:
50 e.emitInvoke(i)
51 case *ssa.SSATypeAssert:
52 e.emitTypeAssert(i)
53 case *ssa.SSAMakeMap:
54 e.emitMakeMap(i)
55 case *ssa.SSAMapUpdate:
56 e.emitMapUpdate(i)
57 case *ssa.SSALookup:
58 e.emitLookup(i)
59 case *ssa.SSAMakeClosure:
60 e.emitMakeClosure(i)
61 case *ssa.SSAPanic:
62 e.emitPanic(i)
63 case *ssa.SSARunDefers:
64 e.emitRunDefers()
65 case *ssa.SSADefer:
66 e.emitDefer(i)
67 case *ssa.SSASend:
68 e.emitChanSend(i)
69 case *ssa.SSAGo:
70 e.w(" ; go\n")
71 case *ssa.SSASelect:
72 e.w(" ; select\n")
73 case *ssa.SSARange:
74 e.emitRange(i)
75 case *ssa.SSANext:
76 e.emitNext(i)
77 case *ssa.SSAMakeChan:
78 e.emitMakeChan(i)
79 }
80 }
81
82 func (e *irEmitter) emitAlloc(a *ssa.SSAAlloc) {
83 reg := e.regName(a)
84 if at, ok := e.allocTypes[a]; ok && len(at) > 0 && at[0] == '[' {
85 if a.Heap {
86 ipt := e.intptrType()
87 e.nextReg++
88 sz := "%ha" | irItoa(e.nextReg)
89 e.w(" ") ; e.w(sz)
90 e.w(" = ptrtoint ptr getelementptr (") ; e.w(at)
91 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
92 e.w(" ") ; e.w(reg)
93 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
94 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
95 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
96 e.deallocAfterAlloc(a, reg)
97 e.scopeTrackAlloc(reg)
98 } else {
99 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(at) ; e.w("\n")
100 e.emitZeroInit(at, reg)
101 }
102 return
103 }
104 elemType := e.llvmType(a.SSAType())
105 nilElem := false
106 if p, ok := types.SafeUnderlying(a.SSAType()).(*types.Pointer); ok {
107 if p.Elem() != nil {
108 elemType = e.llvmType(p.Elem())
109 } else {
110 nilElem = true
111 }
112 }
113 isDoublePtr := false
114 if p, ok := types.SafeUnderlying(a.SSAType()).(*types.Pointer); ok && p.Elem() != nil {
115 if _, ok2 := types.SafeUnderlying(p.Elem()).(*types.Pointer); ok2 {
116 isDoublePtr = true
117 }
118 }
119 if isDoublePtr && elemType == "ptr" {
120 e.allocTypes[a] = elemType
121 } else if elemType == "void" || (elemType == "ptr" && nilElem) {
122 inferred := e.inferAllocTypeFromStores(a)
123 if inferred != "ptr" || elemType == "void" {
124 elemType = inferred
125 }
126 e.allocTypes[a] = elemType
127 } else {
128 override := e.inferAllocTypeFromStores(a)
129 if override != "ptr" && override != elemType {
130 bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
131 isFloatToInt := (elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == 'i'
132 isScalarToAgg := len(elemType) > 0 && (elemType[0] == 'i' || elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == '{'
133 isAggToScalar := len(elemType) > 0 && elemType[0] == '{' && len(override) > 0 && override[0] == 'i'
134 if !bothScalar && !isFloatToInt && !isScalarToAgg && !isAggToScalar {
135 elemType = override
136 e.allocTypes[a] = elemType
137 }
138 }
139 if elemType == "i32" {
140 ssaIsInt := false
141 if p, ok2 := types.SafeUnderlying(a.SSAType()).(*types.Pointer); ok2 && p.Elem() != nil {
142 if b2, ok3 := types.SafeUnderlying(p.Elem()).(*types.Basic); ok3 && b2.Info()&types.IsInteger != 0 {
143 ssaIsInt = true
144 }
145 }
146 if !ssaIsInt {
147 usage := e.inferAllocTypeFromUsage(a)
148 if usage != "" && usage != "i32" && usage != "void" && usage != "ptr" {
149 elemType = usage
150 e.allocTypes[a] = elemType
151 }
152 }
153 }
154 }
155 if !isDoublePtr {
156 if faType := e.inferAllocTypeFromFieldAddrs(a, elemType); faType != "" {
157 retType := e.inferAllocTypeFromReturn(a)
158 callType := e.inferAllocTypeFromCallArgs(a)
159 appendType := e.inferAllocTypeFromAppendUsage(a)
160 best := faType
161 if retType != "" && len(retType) > len(best) {
162 best = retType
163 }
164 if callType != "" && len(callType) > len(best) {
165 best = callType
166 }
167 if appendType != "" && len(appendType) > len(best) {
168 best = appendType
169 }
170 if elemType != best {
171 elemType = best
172 e.allocTypes[a] = elemType
173 }
174 }
175 }
176 if a.Heap {
177 ipt := e.intptrType()
178 e.nextReg++
179 sz := "%ha" | irItoa(e.nextReg)
180 e.w(" ") ; e.w(sz)
181 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
182 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
183 e.w(" ") ; e.w(reg)
184 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
185 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
186 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
187 e.deallocAfterAlloc(a, reg)
188 e.scopeTrackAlloc(reg)
189 } else {
190 e.w(" ")
191 e.w(reg)
192 e.w(" = alloca ")
193 e.w(elemType)
194 e.w("\n")
195 e.emitZeroInit(elemType, reg)
196 }
197 }
198
199 func (e *irEmitter) inferAllocTypeFromStores(a *ssa.SSAAlloc) string {
200 allocName := a.SSAName()
201 for _, b := range e.curFunc.Blocks {
202 for _, instr := range b.Instrs {
203 if s, ok := instr.(*ssa.SSAStore); ok && s.Addr != nil && s.Addr.SSAName() == allocName {
204 if at, ok2 := e.allocTypes[s.Val]; ok2 && at != "ptr" && at != "void" {
205 return at
206 }
207 vt := e.llvmType(s.Val.SSAType())
208 if vt != "void" && vt != "" {
209 return vt
210 }
211 if call, ok := s.Val.(*ssa.SSACall); ok {
212 if b2, ok2 := call.Call.Value.(*ssa.SSABuiltin); ok2 && b2.SSAName() == "append" {
213 return e.sliceType()
214 }
215 }
216 if _, ok := s.Val.(*ssa.SSASlice); ok {
217 return e.sliceType()
218 }
219 if _, ok := s.Val.(*ssa.SSAMakeSlice); ok {
220 return e.sliceType()
221 }
222 }
223 }
224 }
225 return "ptr"
226 }
227
228 func (e *irEmitter) inferAllocTypeFromReturn(a *ssa.SSAAlloc) string {
229 allocName := a.SSAName()
230 for _, b := range e.curFunc.Blocks {
231 for _, instr := range b.Instrs {
232 ret, ok := instr.(*ssa.SSAReturn)
233 if !ok {
234 continue
235 }
236 for i, rv := range ret.Results {
237 if rv == nil {
238 continue
239 }
240 if uop, ok2 := rv.(*ssa.SSAUnOp); ok2 && uop.Op == ssa.OpMul && uop.X != nil && uop.X.SSAName() == allocName {
241 sig := e.curFunc.Signature
242 if sig != nil && sig.Results() != nil && i < sig.Results().Len() {
243 rt := e.llvmType(sig.Results().At(i).Type())
244 if rt != "void" && rt != "ptr" && rt != "" {
245 return rt
246 }
247 }
248 return ""
249 }
250 }
251 }
252 }
253 return ""
254 }
255
256 func (e *irEmitter) inferAllocTypeFromCallArgs(a *ssa.SSAAlloc) string {
257 allocName := a.SSAName()
258 loadNames := map[string]bool{}
259 for _, b := range e.curFunc.Blocks {
260 for _, instr := range b.Instrs {
261 if uop, ok := instr.(*ssa.SSAUnOp); ok && uop.Op == ssa.OpMul && uop.X != nil && uop.X.SSAName() == allocName {
262 loadNames[uop.SSAName()] = true
263 }
264 }
265 }
266 for _, b := range e.curFunc.Blocks {
267 for _, instr := range b.Instrs {
268 call, ok := instr.(*ssa.SSACall)
269 if !ok { continue }
270 callee := call.Call.Value
271 if callee == nil { continue }
272 var sig *types.Signature
273 if cfn, ok2 := callee.(*ssa.SSAFunction); ok2 && cfn.Signature != nil {
274 sig = cfn.Signature
275 } else {
276 if okv, okok := types.SafeUnderlying(callee.SSAType()).(*types.Signature); okok {
277 sig = okv
278 }
279 }
280 if sig == nil || sig.Params() == nil { continue }
281 recvOff := 0
282 if sig.Recv() != nil { recvOff = 1 }
283 for i, arg := range call.Call.Args {
284 if arg == nil { continue }
285 if !loadNames[arg.SSAName()] { continue }
286 sigIdx := i - recvOff
287 if sigIdx < 0 || sigIdx >= sig.Params().Len() { continue }
288 pt := e.llvmType(sig.Params().At(sigIdx).Type())
289 if pt != "void" && pt != "ptr" && pt != "" && len(pt) > 0 && pt[0] == '{' {
290 return pt
291 }
292 }
293 }
294 }
295 return ""
296 }
297
298 func (e *irEmitter) inferAllocTypeFromAppendUsage(a *ssa.SSAAlloc) string {
299 allocName := a.SSAName()
300 loadNames := map[string]bool{}
301 for _, b := range e.curFunc.Blocks {
302 for _, instr := range b.Instrs {
303 if uop, ok := instr.(*ssa.SSAUnOp); ok && uop.Op == ssa.OpMul && uop.X != nil && uop.X.SSAName() == allocName {
304 loadNames[uop.SSAName()] = true
305 }
306 }
307 }
308 if len(loadNames) == 0 {
309 return ""
310 }
311 for _, b := range e.curFunc.Blocks {
312 for _, instr := range b.Instrs {
313 call, ok := instr.(*ssa.SSACall)
314 if !ok {
315 continue
316 }
317 bi, ok2 := call.Call.Value.(*ssa.SSABuiltin)
318 if !ok2 || bi.SSAName() != "append" {
319 continue
320 }
321 if len(call.Call.Args) < 2 {
322 continue
323 }
324 for j := 1; j < len(call.Call.Args); j++ {
325 arg := call.Call.Args[j]
326 if arg == nil {
327 continue
328 }
329 if !loadNames[arg.SSAName()] {
330 continue
331 }
332 sliceArg := call.Call.Args[0]
333 if sl, ok3 := types.SafeUnderlying(sliceArg.SSAType()).(*types.Slice); ok3 {
334 et := e.llvmType(sl.Elem())
335 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
336 return et
337 }
338 }
339 if sl, ok3 := sliceArg.SSAType().(*types.Slice); ok3 {
340 et := e.llvmType(sl.Elem())
341 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
342 return et
343 }
344 }
345 }
346 }
347 }
348 return ""
349 }
350
351 func (e *irEmitter) inferAllocTypeFromFieldAddrs(a *ssa.SSAAlloc, baseType string) string {
352 allocName := a.SSAName()
353 names := map[string]bool{allocName: true}
354 for _, b := range e.curFunc.Blocks {
355 for _, instr := range b.Instrs {
356 if uop, ok := instr.(*ssa.SSAUnOp); ok && uop.Op == ssa.OpMul && uop.X != nil && uop.X.SSAName() == allocName {
357 names[uop.SSAName()] = true
358 }
359 }
360 }
361 maxField := -1
362 fieldTypes := map[int32]string{}
363 for _, b := range e.curFunc.Blocks {
364 for _, instr := range b.Instrs {
365 fa, ok := instr.(*ssa.SSAFieldAddr)
366 if !ok || fa.X == nil || !names[fa.X.SSAName()] {
367 continue
368 }
369 if fa.Field > maxField {
370 maxField = fa.Field
371 }
372 faName := fa.SSAName()
373 for _, b2 := range e.curFunc.Blocks {
374 for _, i2 := range b2.Instrs {
375 if s, ok2 := i2.(*ssa.SSAStore); ok2 && s.Addr != nil && s.Val != nil && s.Addr.SSAName() == faName {
376 ft := e.llvmType(s.Val.SSAType())
377 if ft != "void" && ft != "" {
378 fieldTypes[fa.Field] = ft
379 }
380 }
381 if ld, ok2 := i2.(*ssa.SSAUnOp); ok2 && ld.Op == ssa.OpMul && ld.X != nil && ld.X.SSAName() == faName {
382 ft := e.llvmType(ld.SSAType())
383 if ft != "void" && ft != "" && ft != "ptr" {
384 if _, exists := fieldTypes[fa.Field]; !exists {
385 fieldTypes[fa.Field] = ft
386 }
387 }
388 }
389 }
390 }
391 }
392 }
393 if maxField < 0 {
394 return ""
395 }
396 baseFields := parseStructFields(baseType)
397 top := maxField
398 if len(baseFields)-1 > top {
399 top = len(baseFields) - 1
400 }
401 s := "{"
402 for i := 0; i <= top; i++ {
403 if i > 0 {
404 s = s | ", "
405 }
406 ft, ok := fieldTypes[i]
407 if !ok {
408 if i < len(baseFields) && baseFields[i] != "" {
409 ft = baseFields[i]
410 } else {
411 ft = "ptr"
412 }
413 } else if i < len(baseFields) && baseFields[i] != "" {
414 bw := irParseIntWidth(baseFields[i])
415 fw := irParseIntWidth(ft)
416 if bw > 0 && fw > 0 && bw > fw {
417 ft = baseFields[i]
418 }
419 }
420 s = s | ft
421 }
422 return s | "}"
423 }
424
425 func parseStructFields(s string) []string {
426 if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' {
427 return nil
428 }
429 inner := s[1 : len(s)-1]
430 var fields []string
431 depth := 0
432 start := int32(0)
433 for i := int32(0); i < int32(len(inner)); i++ {
434 switch inner[i] {
435 case '{':
436 depth++
437 case '}':
438 depth--
439 case ',':
440 if depth == 0 {
441 f := llvmTrimSpace(string(inner[start:i]))
442 fields = append(fields, f)
443 start = i + 1
444 }
445 }
446 }
447 f := llvmTrimSpace(string(inner[start:]))
448 if f != "" {
449 fields = append(fields, f)
450 }
451 return fields
452 }
453
454 func llvmTrimSpace(s string) string {
455 i := int32(0)
456 for i < int32(len(s)) && s[i] == ' ' {
457 i++
458 }
459 j := int32(len(s))
460 for j > i && s[j-1] == ' ' {
461 j--
462 }
463 return string(s[i:j])
464 }
465
466 func (e *irEmitter) inferAllocTypeFromUsage(a *ssa.SSAAlloc) string {
467 allocName := a.SSAName()
468 loadNames := map[string]bool{}
469 for _, b := range e.curFunc.Blocks {
470 for _, instr := range b.Instrs {
471 load, ok := instr.(*ssa.SSAUnOp)
472 if !ok || load.Op != ssa.OpMul {
473 continue
474 }
475 if load.X != nil && load.X.SSAName() == allocName {
476 loadNames[load.SSAName()] = true
477 }
478 }
479 }
480 if len(loadNames) == 0 {
481 return "ptr"
482 }
483 for _, b := range e.curFunc.Blocks {
484 for _, instr := range b.Instrs {
485 switch u := instr.(type) {
486 case *ssa.SSASlice:
487 if u.X != nil && loadNames[u.X.SSAName()] {
488 return e.sliceType()
489 }
490 case *ssa.SSAIndexAddr:
491 if u.X != nil && loadNames[u.X.SSAName()] {
492 return e.sliceType()
493 }
494 case *ssa.SSACall:
495 for _, arg := range u.Call.Args {
496 if arg != nil && loadNames[arg.SSAName()] {
497 if bi, ok2 := u.Call.Value.(*ssa.SSABuiltin); ok2 {
498 nm := bi.SSAName()
499 if nm == "append" || nm == "copy" || nm == "len" || nm == "cap" {
500 return e.sliceType()
501 }
502 }
503 }
504 }
505 }
506 }
507 }
508 return "ptr"
509 }
510
511 func (e *irEmitter) emitStore(s *ssa.SSAStore) {
512 if s.Val == nil || s.Addr == nil {
513 e.w(" ; store with nil val/addr\n")
514 return
515 }
516 valType := e.llvmType(s.Val.SSAType())
517 val := e.operand(s.Val)
518 if load, ok := s.Val.(*ssa.SSAUnOp); ok && load.Op == ssa.OpMul {
519 if g, ok2 := load.X.(*ssa.SSAGlobal); ok2 {
520 valType = e.resolveGlobalDeclType(g)
521 }
522 }
523 if _, isAlloc := s.Val.(*ssa.SSAAlloc); !isAlloc {
524 _, isIndexAddr := s.Val.(*ssa.SSAIndexAddr)
525 _, isExtract := s.Val.(*ssa.SSAExtract)
526 if at, ok := e.allocTypes[s.Val]; ok && at != valType && !isIndexAddr {
527 bothScalar := len(valType) > 0 && valType[0] == 'i' && len(at) > 0 && at[0] == 'i'
528 if !bothScalar || isExtract {
529 valType = at
530 if val == "null" && valType != "ptr" {
531 val = "zeroinitializer"
532 }
533 } else if irParseIntWidth(at) > irParseIntWidth(valType) {
534 valType = at
535 }
536 }
537 }
538 if len(valType) > 0 && (valType[0] == '[' || valType[0] == '{') {
539 if addrAt, ok := e.allocTypes[s.Addr]; ok && addrAt != valType {
540 if len(valType) >= len(addrAt) || (valType[0] == '[' && addrAt[0] == '{') {
541 e.allocTypes[s.Addr] = valType
542 }
543 }
544 }
545 if valType == "void" {
546 if at, ok := e.allocTypes[s.Addr]; ok && at != "ptr" && at != "void" {
547 valType = at
548 if val == "null" && valType != "ptr" {
549 val = "zeroinitializer"
550 }
551 }
552 } else if valType == "ptr" {
553 if uop, ok := s.Val.(*ssa.SSAUnOp); ok && uop.Op == ssa.OpMul {
554 if at, ok2 := e.allocTypes[s.Addr]; ok2 && at != "ptr" && at != "void" {
555 valType = at
556 if val == "null" && valType != "ptr" {
557 val = "zeroinitializer"
558 }
559 }
560 }
561 }
562 if valType == "void" {
563 if _, isFV := s.Addr.(*ssa.SSAFreeVar); isFV {
564 valType = e.llvmType(s.Addr.SSAType())
565 } else if p, ok := types.SafeUnderlying(s.Addr.SSAType()).(*types.Pointer); ok {
566 valType = e.llvmType(p.Elem())
567 }
568 if valType == "void" {
569 valType = "ptr"
570 }
571 if val == "null" && valType != "ptr" {
572 val = "zeroinitializer"
573 }
574 }
575 addr := e.operand(s.Addr)
576 if at, ok := e.allocTypes[s.Addr]; ok && (at == "double" || at == "float") && len(valType) > 0 && valType[0] == 'i' {
577 if isConstOperand(val) {
578 val = ensureTokenFloatLit(val)
579 } else {
580 e.nextReg++
581 conv := "%si2f" | irItoa(e.nextReg)
582 e.w(" ") ; e.w(conv) ; e.w(" = sitofp ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(at) ; e.w("\n")
583 val = conv
584 }
585 valType = at
586 }
587 if at, ok2 := e.allocTypes[s.Addr]; ok2 && len(at) > 0 && at[0] == '{' && len(valType) > 0 && valType[0] == 'i' {
588 if val == "0" || val == "zeroinitializer" {
589 val = "zeroinitializer"
590 valType = at
591 }
592 }
593 if at, ok2 := e.allocTypes[s.Addr]; ok2 && len(at) > 0 && at[0] == 'i' && len(valType) > 0 && valType[0] == '{' {
594 valType = at
595 val = "zeroinitializer"
596 }
597 addrElemT := ""
598 if p, ok := types.SafeUnderlying(s.Addr.SSAType()).(*types.Pointer); ok {
599 addrElemT = e.llvmType(p.Elem())
600 }
601 if addrElemT == "" || addrElemT == "void" {
602 if at, ok2 := e.allocTypes[s.Addr]; ok2 && at != "ptr" && at != "void" {
603 addrElemT = at
604 }
605 }
606 if len(addrElemT) > 1 && addrElemT[0] == 'i' && len(valType) > 1 && valType[0] == 'i' && addrElemT != valType {
607 elemT := addrElemT
608 vw := irParseIntWidth(valType)
609 ew := irParseIntWidth(elemT)
610 if ew > 0 && vw > ew {
611 e.nextReg++
612 trunc := "%tr" | irItoa(e.nextReg)
613 e.w(" ") ; e.w(trunc) ; e.w(" = trunc ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(elemT) ; e.w("\n")
614 val = trunc
615 valType = elemT
616 } else if ew > 0 && vw > 0 && vw < ew {
617 if c, ok2 := s.Val.(*ssa.SSAConst); ok2 {
618 if ci, ok3 := c.Value().(*types.ConstInt); ok3 {
619 val = irItoa64(ci.V)
620 valType = elemT
621 } else {
622 valType = elemT
623 }
624 } else {
625 e.nextReg++
626 ext := "%se" | irItoa(e.nextReg)
627 extOp := "sext"
628 if p2, ok3 := types.SafeUnderlying(s.Addr.SSAType()).(*types.Pointer); ok3 {
629 if b, ok4 := types.SafeUnderlying(p2.Elem()).(*types.Basic); ok4 && b.Info()&types.IsUnsigned != 0 {
630 extOp = "zext"
631 }
632 }
633 e.w(" ") ; e.w(ext) ; e.w(" = ") ; e.w(extOp) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(elemT) ; e.w("\n")
634 val = ext
635 valType = elemT
636 }
637 }
638 }
639 if len(val) > 0 && val[0] == '%' && len(valType) > 1 && valType[0] == 'i' {
640 if rt, ok := e.regTypes[val]; ok && len(rt) > 1 && rt[0] == 'i' && rt != valType {
641 rw := irParseIntWidth(rt)
642 tw := irParseIntWidth(valType)
643 if rw > 0 && tw > 0 && rw > tw {
644 e.nextReg++
645 trunc := "%stf" | irItoa(e.nextReg)
646 e.w(" ") ; e.w(trunc) ; e.w(" = trunc ") ; e.w(rt) ; e.w(" ") ; e.w(val) ; e.w(" to ") ; e.w(valType) ; e.w("\n")
647 val = trunc
648 }
649 }
650 }
651 e.emitScopeRelocateOnStore(s, val, valType)
652 if val == "zeroinitializer" && len(valType) > 0 && valType[0] == '[' && llvmArrayByteSize(valType) >= 1024 {
653 e.emitZeroInit(valType, addr)
654 } else {
655 e.w(" store ")
656 e.w(valType)
657 e.w(" ")
658 e.w(val)
659 e.w(", ptr ")
660 e.w(addr)
661 e.w("\n")
662 }
663 }
664
665 func (e *irEmitter) emitZeroReg(reg string, typ syntax.Type) {
666 rt := e.llvmType(typ)
667 if rt == "void" || rt == "" {
668 rt = "i32"
669 }
670 if rt == "ptr" {
671 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr i64 0 to ptr\n")
672 } else if rt == "i1" {
673 e.w(" ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
674 } else if rt == "float" {
675 e.w(" ") ; e.w(reg) ; e.w(" = fadd float 0.0, 0.0\n")
676 } else if rt == "double" {
677 e.w(" ") ; e.w(reg) ; e.w(" = fadd double 0.0, 0.0\n")
678 } else if e.intBits(rt) > 0 {
679 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
680 } else {
681 e.w(" ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
682 }
683 }
684