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