collections.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/types"
   7  )
   8  
   9  func (e *irEmitter) emitFieldAddr(f *ssa.SSAFieldAddr) {
  10  	reg := e.regName(f)
  11  	baseType := e.llvmType(f.X.SSAType())
  12  	if p, ok := types.SafeUnderlying(f.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil {
  13  		elem := p.Elem()
  14  		if p2, ok2 := types.SafeUnderlying(elem).(*types.Pointer); ok2 && p2.Elem() != nil {
  15  			baseType = e.llvmType(p2.Elem())
  16  		} else {
  17  			baseType = e.llvmType(elem)
  18  		}
  19  	}
  20  	if at, ok := e.allocTypes[f.X]; ok && at != "ptr" && at != "void" {
  21  		baseType = at
  22  	}
  23  	base := e.operand(f.X)
  24  	if uop, ok := f.X.(*ssa.SSAUnOp); ok {
  25  		_, isFreeVar := uop.X.(*ssa.SSAFreeVar)
  26  		addrType := e.llvmType(uop.X.SSAType())
  27  		useSource := false
  28  		if p, ok2 := types.SafeUnderlying(uop.X.SSAType()).(*types.Pointer); ok2 && p.Elem() != nil {
  29  			elem := p.Elem()
  30  			if _, ok3 := types.SafeUnderlying(elem).(*types.Pointer); ok3 {
  31  				// double-pointer: alloca holds **T, keep the loaded *T as base
  32  			} else {
  33  				baseType = e.llvmType(elem)
  34  				useSource = true
  35  			}
  36  		}
  37  		if useSource && !isFreeVar && addrType == "ptr" && baseType != "ptr" && baseType != "void" {
  38  			base = e.operand(uop.X)
  39  		}
  40  	}
  41  	if baseType == "ptr" || baseType == "void" {
  42  		e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(base)
  43  		e.w(", i32 0\n")
  44  		return
  45  	}
  46  	_, isCall := f.X.(*ssa.SSACall)
  47  	_, isPhi := f.X.(*ssa.SSAPhi)
  48  	isExtract := false
  49  	if _, ok := f.X.(*ssa.SSAExtract); ok {
  50  		isExtract = true
  51  	}
  52  	needsAlloca := (isCall || isPhi || isExtract) && len(baseType) > 0 && baseType[0] == '{'
  53  	if !needsAlloca {
  54  		if _, isAlloc := f.X.(*ssa.SSAAlloc); !isAlloc {
  55  			if _, isGlobal := f.X.(*ssa.SSAGlobal); !isGlobal {
  56  				if _, isUop := f.X.(*ssa.SSAUnOp); !isUop {
  57  					if _, isIdxAddr := f.X.(*ssa.SSAIndexAddr); !isIdxAddr {
  58  						if _, isFA := f.X.(*ssa.SSAFieldAddr); !isFA {
  59  							if _, isFV := f.X.(*ssa.SSAFreeVar); !isFV {
  60  								if len(baseType) > 0 && (baseType[0] == '{' || baseType[0] == '[') {
  61  									needsAlloca = true
  62  								}
  63  							}
  64  						}
  65  					}
  66  				}
  67  			}
  68  		}
  69  	}
  70  	if needsAlloca {
  71  		actualType := e.resolvedType(f.X, e.llvmType(f.X.SSAType()))
  72  		if actualType == "ptr" {
  73  			needsAlloca = false
  74  		} else {
  75  			e.nextReg++
  76  			tmp := "%fa" | irItoa(e.nextReg)
  77  			e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(baseType) ; e.w("\n")
  78  			e.w("  store ") ; e.w(baseType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
  79  			base = tmp
  80  		}
  81  	}
  82  	e.w("  ")
  83  	e.w(reg)
  84  	e.w(" = getelementptr inbounds ")
  85  	e.w(baseType)
  86  	e.w(", ptr ")
  87  	e.w(base)
  88  	e.w(", i32 0, i32 ")
  89  	e.w(irItoa(f.Field))
  90  	e.w("\n")
  91  }
  92  
  93  func (e *irEmitter) emitIndexAddr(idx *ssa.SSAIndexAddr) {
  94  	reg := e.regName(idx)
  95  	elemType := e.llvmType(idx.SSAType())
  96  	if p, ok := types.SafeUnderlying(idx.SSAType()).(*types.Pointer); ok {
  97  		elemType = e.llvmType(p.Elem())
  98  	}
  99  	base := e.operand(idx.X)
 100  	index := e.operand(idx.Index)
 101  	baseType := e.llvmType(idx.X.SSAType())
 102  	resolvedBase := e.resolvedType(idx.X, baseType)
 103  	_, isSlice := types.SafeUnderlying(idx.X.SSAType()).(*types.Slice)
 104  	if !isSlice {
 105  		if b, ok := types.SafeUnderlying(idx.X.SSAType()).(*types.Basic); ok && b.Info()&types.IsString != 0 {
 106  			isSlice = true
 107  		}
 108  	}
 109  	if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
 110  		isSlice = false
 111  	} else if !isSlice && (baseType == e.sliceType() || resolvedBase == e.sliceType()) {
 112  		isSlice = true
 113  	}
 114  	if isSlice && elemType == "void" {
 115  		elemType = "i8"
 116  	}
 117  	idxType := e.resolvedType(idx.Index, e.llvmType(idx.Index.SSAType()))
 118  	if e.intBits(idxType) == 0 && idxType != "ptr" {
 119  		if idxType == e.ifaceType() || (len(idxType) > 0 && idxType[0] == '{') {
 120  			fieldType := extractTupleField(idxType, 1)
 121  			if fieldType == "" {
 122  				fieldType = "i64"
 123  			}
 124  			e.nextReg++
 125  			valPtr := "%idxv" | irItoa(e.nextReg)
 126  			e.w("  ") ; e.w(valPtr) ; e.w(" = extractvalue ") ; e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w(", 1\n")
 127  			e.nextReg++
 128  			intVal := "%idxi" | irItoa(e.nextReg)
 129  			if fieldType == "ptr" {
 130  				e.w("  ") ; e.w(intVal) ; e.w(" = ptrtoint ptr ") ; e.w(valPtr) ; e.w(" to i32\n")
 131  			} else if fieldType == "i32" {
 132  				intVal = valPtr
 133  			} else {
 134  				e.w("  ") ; e.w(intVal) ; e.w(" = trunc ") ; e.w(fieldType) ; e.w(" ") ; e.w(valPtr) ; e.w(" to i32\n")
 135  			}
 136  			index = intVal
 137  			idxType = "i32"
 138  		}
 139  	}
 140  	if isSlice {
 141  		e.nextReg++
 142  		dataPtr := "%sp" | irItoa(e.nextReg)
 143  		e.w("  ")
 144  		e.w(dataPtr)
 145  		e.w(" = extractvalue ")
 146  		e.w(e.sliceType())
 147  		e.w(" ")
 148  		e.w(base)
 149  		e.w(", 0\n")
 150  		e.w("  ")
 151  		e.w(reg)
 152  		e.w(" = getelementptr inbounds ")
 153  		e.w(elemType)
 154  		e.w(", ptr ")
 155  		e.w(dataPtr)
 156  		e.w(", ")
 157  		e.w(idxType)
 158  		e.w(" ")
 159  		e.w(index)
 160  		e.w("\n")
 161  		e.setRegType(idx, reg, elemType)
 162  		return
 163  	}
 164  	arr, isArray := types.SafeUnderlying(idx.X.SSAType()).(*types.Array)
 165  	if !isArray {
 166  		if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
 167  			isArray = true
 168  		}
 169  	}
 170  	if !isArray {
 171  		if alloc, ok4 := idx.X.(*ssa.SSAAlloc); ok4 {
 172  			if p, ok5 := types.SafeUnderlying(alloc.SSAType()).(*types.Pointer); ok5 && p.Elem() != nil {
 173  				if ar, ok6 := types.SafeUnderlying(p.Elem()).(*types.Array); ok6 && ar.Len() > 0 {
 174  					isArray = true
 175  					arrT := e.llvmType(p.Elem())
 176  					if len(arrT) > 0 && arrT[0] == '[' {
 177  						e.allocTypes[alloc] = arrT
 178  					}
 179  				}
 180  			}
 181  		}
 182  	}
 183  	if !isArray {
 184  		if load, ok4 := idx.X.(*ssa.SSAUnOp); ok4 && load.Op == ssa.OpMul {
 185  			if at, ok5 := e.allocTypes[load.X]; ok5 && len(at) > 0 && at[0] == '[' {
 186  				isArray = true
 187  				e.allocTypes[idx.X] = at
 188  				allocBase := e.operand(load.X)
 189  				e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
 190  				e.w(at) ; e.w(", ptr ") ; e.w(allocBase) ; e.w(", i32 0, ")
 191  				e.w(e.llvmType(idx.Index.SSAType())) ; e.w(" ") ; e.w(index) ; e.w("\n")
 192  				aet := e.arrayElemType(at)
 193  				if aet != "" { e.setRegType(idx, reg, aet) }
 194  				return
 195  			}
 196  		}
 197  	}
 198  	if isArray {
 199  		arrType := e.llvmType(idx.X.SSAType())
 200  		if at, ok4 := e.allocTypes[idx.X]; ok4 && len(at) > 0 && at[0] == '[' {
 201  			arrType = at
 202  		}
 203  		if arrType == "ptr" || arrType == "void" {
 204  			if p, ok4 := types.SafeUnderlying(idx.X.SSAType()).(*types.Pointer); ok4 && p.Elem() != nil {
 205  				arrType = e.llvmType(p.Elem())
 206  			}
 207  		}
 208  		_, isGlobal := idx.X.(*ssa.SSAGlobal)
 209  		_, isAlloc := idx.X.(*ssa.SSAAlloc)
 210  		if isGlobal || isAlloc {
 211  			_ = arr
 212  			e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
 213  			e.w(arrType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ")
 214  			e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n")
 215  			return
 216  		}
 217  		e.nextReg++
 218  		arrPtr := "%ai" | irItoa(e.nextReg)
 219  		e.w("  ") ; e.w(arrPtr) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
 220  		e.w("  store ") ; e.w(arrType) ; e.w(" ") ; e.w(base) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w("\n")
 221  		e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
 222  		e.w(arrType) ; e.w(", ptr ") ; e.w(arrPtr) ; e.w(", i32 0, ")
 223  		e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n")
 224  		aet := e.arrayElemType(arrType)
 225  		if aet != "" {
 226  			e.setRegType(idx, reg, aet)
 227  		}
 228  		return
 229  	}
 230  	if p, ok := types.SafeUnderlying(idx.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil {
 231  		if _, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
 232  			arrType := e.llvmType(p.Elem())
 233  			if len(arrType) > 0 && arrType[0] == '[' {
 234  				e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
 235  				e.w(arrType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ")
 236  				e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n")
 237  				return
 238  			}
 239  		}
 240  	}
 241  	if len(elemType) > 0 && elemType[0] == '[' {
 242  		aet := e.arrayElemType(elemType)
 243  		e.w("  ") ; e.w(reg) ; e.w(" = getelementptr inbounds ")
 244  		e.w(elemType) ; e.w(", ptr ") ; e.w(base) ; e.w(", i32 0, ")
 245  		e.w(idxType) ; e.w(" ") ; e.w(index) ; e.w("\n")
 246  		e.setRegType(idx, reg, aet)
 247  		return
 248  	}
 249  	e.w("  ")
 250  	e.w(reg)
 251  	e.w(" = getelementptr inbounds ")
 252  	e.w(elemType)
 253  	e.w(", ptr ")
 254  	e.w(base)
 255  	e.w(", ")
 256  	e.w(idxType)
 257  	e.w(" ")
 258  	e.w(index)
 259  	e.w("\n")
 260  }
 261  
 262  func (e *irEmitter) emitExtract(ex *ssa.SSAExtract) {
 263  	reg := e.regName(ex)
 264  	tupType := e.llvmType(ex.Tuple.SSAType())
 265  	allocFound := false
 266  	if at, ok := e.allocTypes[ex.Tuple]; ok {
 267  		tupType = at
 268  		allocFound = true
 269  	}
 270  	if n, ok := ex.Tuple.(*ssa.SSANext); ok && !allocFound {
 271  		rangeInstr := n.Iter.(*ssa.SSARange)
 272  		if mt, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.TCMap); ok2 {
 273  			tupType = "{i1, " | e.llvmType(mt.Key()) | ", " | e.llvmType(mt.Elem()) | "}"
 274  		} else if arr, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Array); ok2 {
 275  			tupType = "{i1, i32, " | e.llvmType(arr.Elem()) | "}"
 276  		} else if p, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Pointer); ok2 && p.Elem() != nil {
 277  			if arr2, ok3 := types.SafeUnderlying(p.Elem()).(*types.Array); ok3 {
 278  				tupType = "{i1, i32, " | e.llvmType(arr2.Elem()) | "}"
 279  			}
 280  		} else if n.IsString {
 281  			tupType = "{i1, i32, i8}"
 282  		} else {
 283  			et := "i8"
 284  			if sl, ok2 := types.SafeUnderlying(rangeInstr.X.SSAType()).(*types.Slice); ok2 {
 285  				et = e.llvmType(sl.Elem())
 286  			} else if tup, ok2 := n.SSAType().(*types.Tuple); ok2 && tup.Len() >= 3 {
 287  				vt := tup.At(2).Type()
 288  				if vt != nil {
 289  					vlt := e.llvmType(vt)
 290  					if vlt != "void" {
 291  						et = vlt
 292  					}
 293  				}
 294  			}
 295  			tupType = "{i1, i32, " | et | "}"
 296  		}
 297  	}
 298  	val := e.operand(ex.Tuple)
 299  	// Track extracted element type for downstream alloc/store consistency
 300  	extractedType := extractTupleField(tupType, ex.Index)
 301  	if extractedType != "" {
 302  		ssaType := e.llvmType(ex.SSAType())
 303  		if extractedType != ssaType {
 304  			e.allocTypes[ex] = extractedType
 305  		}
 306  	}
 307  	if tupType == "ptr" || tupType == "void" {
 308  		elemType := e.llvmType(ex.SSAType())
 309  		if elemType == "void" { elemType = "ptr" }
 310  		e.nextReg++
 311  		castReg := "%ev" | irItoa(e.nextReg)
 312  		e.w("  ") ; e.w(castReg) ; e.w(" = getelementptr inbounds i8, ptr ") ; e.w(val) ; e.w(", i32 0\n")
 313  		e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(castReg) ; e.w("\n")
 314  		e.allocTypes[ex] = elemType
 315  		return
 316  	}
 317  	e.w("  ")
 318  	e.w(reg)
 319  	e.w(" = extractvalue ")
 320  	e.w(tupType)
 321  	e.w(" ")
 322  	e.w(val)
 323  	e.w(", ")
 324  	e.w(irItoa(ex.Index))
 325  	e.w("\n")
 326  }
 327  
 328  func extractTupleField(tupType string, index int32) string {
 329  	if len(tupType) < 3 || tupType[0] != '{' {
 330  		return ""
 331  	}
 332  	inner := tupType[1 : len(tupType)-1]
 333  	depth := 0
 334  	field := 0
 335  	start := 0
 336  	for i := 0; i < len(inner); i++ {
 337  		c := inner[i]
 338  		if c == '{' {
 339  			depth++
 340  		} else if c == '}' {
 341  			depth--
 342  		} else if c == ',' && depth == 0 {
 343  			if field == index {
 344  				s := inner[start:i]
 345  				for len(s) > 0 && s[0] == ' ' { s = s[1:] }
 346  				for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
 347  				return s
 348  			}
 349  			field++
 350  			start = i + 1
 351  		}
 352  	}
 353  	if field == index {
 354  		s := inner[start:]
 355  		for len(s) > 0 && s[0] == ' ' { s = s[1:] }
 356  		for len(s) > 0 && s[len(s)-1] == ' ' { s = s[:len(s)-1] }
 357  		return s
 358  	}
 359  	return ""
 360  }
 361  
 362  func (e *irEmitter) sextToIpt(val ssa.SSAValue, op string) string {
 363  	ipt := e.intptrType()
 364  	if val == nil {
 365  		return op
 366  	}
 367  	valType := e.llvmType(val.SSAType())
 368  	if valType == ipt {
 369  		return op
 370  	}
 371  	e.nextReg++
 372  	ext := "%sx" | irItoa(e.nextReg)
 373  	srcBits := llvmTypeBits(valType)
 374  	dstBits := llvmTypeBits(ipt)
 375  	if srcBits > dstBits {
 376  		e.w("  ") ; e.w(ext) ; e.w(" = trunc ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 377  	} else {
 378  		extOp := "sext"
 379  		if b, ok := types.SafeUnderlying(val.SSAType()).(*types.Basic); ok && b.Info()&types.IsUnsigned != 0 {
 380  			extOp = "zext"
 381  		}
 382  		e.w("  ") ; e.w(ext) ; e.w(" = ") ; e.w(extOp) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(op) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 383  	}
 384  	return ext
 385  }
 386  
 387  func (e *irEmitter) emitMakeChan(m *ssa.SSAMakeChan) {
 388  	reg := e.regName(m)
 389  	ipt := e.intptrType()
 390  	elemType := "i8"
 391  	if ch, ok := types.SafeUnderlying(m.SSAType()).(*types.TCChan); ok && ch.Elem() != nil {
 392  		et := e.llvmType(ch.Elem())
 393  		if et != "void" && et != "" {
 394  			elemType = et
 395  		}
 396  	}
 397  	e.nextReg++
 398  	elemSz := "%mc" | irItoa(e.nextReg)
 399  	e.w("  ") ; e.w(elemSz) ; e.w(" = ptrtoint ptr getelementptr (")
 400  	e.w(elemType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 401  	bufSz := "0"
 402  	if m.Size != nil {
 403  		bufSz = e.sextToIpt(m.Size, e.operand(m.Size))
 404  	}
 405  	e.w("  ") ; e.w(reg) ; e.w(" = call ptr @runtime.chanMake(")
 406  	e.w(ipt) ; e.w(" ") ; e.w(elemSz) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(bufSz) ; e.w(")\n")
 407  	e.declareRuntime("runtime.chanMake", "ptr", ipt | ", " | ipt)
 408  	e.scopeTrackAlloc(reg)
 409  }
 410  
 411  func (e *irEmitter) chanElemType(chanType syntax.Type) string {
 412  	if ch, ok := types.SafeUnderlying(chanType).(*types.TCChan); ok && ch.Elem() != nil {
 413  		et := e.llvmType(ch.Elem())
 414  		if et != "void" && et != "" {
 415  			return et
 416  		}
 417  	}
 418  	return "i8"
 419  }
 420  
 421  func (e *irEmitter) emitChanRecv(u *ssa.SSAUnOp) {
 422  	reg := e.regName(u)
 423  	elemType := e.chanElemType(u.X.SSAType())
 424  	ch := e.operand(u.X)
 425  	opType := "{ptr, ptr, i32, ptr}"
 426  
 427  	e.nextReg++
 428  	valAlloca := "%chanrv" | irItoa(e.nextReg)
 429  	e.w("  ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
 430  	e.w("  store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(valAlloca) ; e.w("\n")
 431  
 432  	e.nextReg++
 433  	opAlloca := "%chanrop" | irItoa(e.nextReg)
 434  	e.w("  ") ; e.w(opAlloca) ; e.w(" = alloca ") ; e.w(opType) ; e.w("\n")
 435  	e.w("  store ") ; e.w(opType) ; e.w(" zeroinitializer, ptr ") ; e.w(opAlloca) ; e.w("\n")
 436  
 437  	e.nextReg++
 438  	okReg := "%chanrok" | irItoa(e.nextReg)
 439  	e.w("  ") ; e.w(okReg) ; e.w(" = call i1 @runtime.chanRecv(ptr ") ; e.w(ch) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w(", ptr ") ; e.w(opAlloca) ; e.w(")\n")
 440  	e.declareRuntime("runtime.chanRecv", "i1", "ptr, ptr, ptr")
 441  
 442  	if u.CommaOk {
 443  		e.nextReg++
 444  		loadedVal := "%chanrlv" | irItoa(e.nextReg)
 445  		e.w("  ") ; e.w(loadedVal) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
 446  
 447  		tupleType := "{" | elemType | ", i1}"
 448  		e.nextReg++
 449  		t1 := "%chanrt1_" | irItoa(e.nextReg)
 450  		e.w("  ") ; e.w(t1) ; e.w(" = insertvalue ") ; e.w(tupleType) ; e.w(" zeroinitializer, ") ; e.w(elemType) ; e.w(" ") ; e.w(loadedVal) ; e.w(", 0\n")
 451  		e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(tupleType) ; e.w(" ") ; e.w(t1) ; e.w(", i1 ") ; e.w(okReg) ; e.w(", 1\n")
 452  	} else {
 453  		e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(elemType) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
 454  	}
 455  }
 456  
 457  func (e *irEmitter) emitChanSend(s *ssa.SSASend) {
 458  	elemType := e.chanElemType(s.Chan.SSAType())
 459  	ch := e.operand(s.Chan)
 460  	val := e.operand(s.X)
 461  	opType := "{ptr, ptr, i32, ptr}"
 462  
 463  	e.nextReg++
 464  	valAlloca := "%chansv" | irItoa(e.nextReg)
 465  	e.w("  ") ; e.w(valAlloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
 466  
 467  	valSrcType := e.llvmType(s.X.SSAType())
 468  	resolved := e.resolvedType(s.X, valSrcType)
 469  	if resolved != valSrcType {
 470  		valSrcType = resolved
 471  	}
 472  	if valSrcType == elemType {
 473  		e.w("  store ") ; e.w(elemType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
 474  	} else {
 475  		e.w("  store ") ; e.w(valSrcType) ; e.w(" ") ; e.w(val) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w("\n")
 476  	}
 477  
 478  	e.nextReg++
 479  	opAlloca := "%chansop" | irItoa(e.nextReg)
 480  	e.w("  ") ; e.w(opAlloca) ; e.w(" = alloca ") ; e.w(opType) ; e.w("\n")
 481  	e.w("  store ") ; e.w(opType) ; e.w(" zeroinitializer, ptr ") ; e.w(opAlloca) ; e.w("\n")
 482  
 483  	e.w("  call void @runtime.chanSend(ptr ") ; e.w(ch) ; e.w(", ptr ") ; e.w(valAlloca) ; e.w(", ptr ") ; e.w(opAlloca) ; e.w(")\n")
 484  	e.declareRuntime("runtime.chanSend", "void", "ptr, ptr, ptr")
 485  }
 486  
 487  func (e *irEmitter) emitMakeSlice(m *ssa.SSAMakeSlice) {
 488  	reg := e.regName(m)
 489  	ipt := e.intptrType()
 490  	sty := e.sliceType()
 491  	lenOp := e.sextToIpt(m.Len, e.operand(m.Len))
 492  	capOp := lenOp
 493  	if m.Cap != nil {
 494  		capOp = e.sextToIpt(m.Cap, e.operand(m.Cap))
 495  	}
 496  	var dataPtr string
 497  	if m.Data != nil {
 498  		dataPtr = e.operand(m.Data)
 499  	} else {
 500  		elemType := "i8"
 501  		if sl, ok := types.SafeUnderlying(m.SSAType()).(*types.Slice); ok {
 502  			elemType = e.llvmType(sl.Elem())
 503  		}
 504  		e.nextReg++
 505  		elemSz := "%ms" | irItoa(e.nextReg)
 506  		e.w("  ")
 507  		e.w(elemSz)
 508  		e.w(" = ptrtoint ptr getelementptr (")
 509  		e.w(elemType)
 510  		e.w(", ptr null, i32 1) to ")
 511  		e.w(ipt)
 512  		e.w("\n")
 513  		e.nextReg++
 514  		allocSz := "%ms" | irItoa(e.nextReg)
 515  		e.w("  ")
 516  		e.w(allocSz)
 517  		e.w(" = mul ")
 518  		e.w(ipt)
 519  		e.w(" ")
 520  		e.w(elemSz)
 521  		e.w(", ")
 522  		e.w(capOp)
 523  		e.w("\n")
 524  		e.nextReg++
 525  		dataPtr = "%ms" | irItoa(e.nextReg)
 526  		e.w("  ")
 527  		e.w(dataPtr)
 528  		e.w(" = call ptr @runtime.alloc(")
 529  		e.w(ipt)
 530  		e.w(" ")
 531  		e.w(allocSz)
 532  		e.w(", ptr null, ptr undef)\n")
 533  		e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
 534  		e.scopeTrackAlloc(dataPtr)
 535  	}
 536  	e.nextReg++
 537  	s1 := "%ms" | irItoa(e.nextReg)
 538  	e.w("  ")
 539  	e.w(s1)
 540  	e.w(" = insertvalue ")
 541  	e.w(sty)
 542  	e.w(" undef, ptr ")
 543  	e.w(dataPtr)
 544  	e.w(", 0\n")
 545  	e.nextReg++
 546  	s2 := "%ms" | irItoa(e.nextReg)
 547  	e.w("  ")
 548  	e.w(s2)
 549  	e.w(" = insertvalue ")
 550  	e.w(sty)
 551  	e.w(" ")
 552  	e.w(s1)
 553  	e.w(", ")
 554  	e.w(ipt)
 555  	e.w(" ")
 556  	e.w(lenOp)
 557  	e.w(", 1\n")
 558  	e.w("  ")
 559  	e.w(reg)
 560  	e.w(" = insertvalue ")
 561  	e.w(sty)
 562  	e.w(" ")
 563  	e.w(s2)
 564  	e.w(", ")
 565  	e.w(ipt)
 566  	e.w(" ")
 567  	e.w(capOp)
 568  	e.w(", 2\n")
 569  }
 570  
 571  func (e *irEmitter) emitSliceOp(s *ssa.SSASlice) {
 572  	reg := e.regName(s)
 573  	ipt := e.intptrType()
 574  	sty := e.sliceType()
 575  	src := e.operand(s.X)
 576  	var oldPtr, oldLen, oldCap string
 577  	srcType := types.SafeUnderlying(s.X.SSAType())
 578  	if p, ok := srcType.(*types.Pointer); ok && p.Elem() != nil {
 579  		if arr, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
 580  			oldPtr = src
 581  			oldLen = irItoa64(arr.Len())
 582  			oldCap = oldLen
 583  			srcType = nil
 584  		}
 585  	}
 586  	if arr, ok := srcType.(*types.Array); ok {
 587  		if uop, ok2 := s.X.(*ssa.SSAUnOp); ok2 && uop.Op == ssa.OpMul {
 588  			oldPtr = e.operand(uop.X)
 589  		} else {
 590  			arrType := e.llvmType(s.X.SSAType())
 591  			e.nextReg++
 592  			tmp := "%sl" | irItoa(e.nextReg)
 593  			e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(arrType) ; e.w("\n")
 594  			e.w("  store ") ; e.w(arrType) ; e.w(" ") ; e.w(src) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
 595  			oldPtr = tmp
 596  		}
 597  		oldLen = irItoa64(arr.Len())
 598  		oldCap = oldLen
 599  	} else if oldPtr == "" {
 600  		e.nextReg++
 601  		oldPtr = "%sl" | irItoa(e.nextReg)
 602  		e.w("  ")
 603  		e.w(oldPtr)
 604  		e.w(" = extractvalue ")
 605  		e.w(sty)
 606  		e.w(" ")
 607  		e.w(src)
 608  		e.w(", 0\n")
 609  		e.nextReg++
 610  		oldLen = "%sl" | irItoa(e.nextReg)
 611  		e.w("  ")
 612  		e.w(oldLen)
 613  		e.w(" = extractvalue ")
 614  		e.w(sty)
 615  		e.w(" ")
 616  		e.w(src)
 617  		e.w(", 1\n")
 618  		e.nextReg++
 619  		oldCap = "%sl" | irItoa(e.nextReg)
 620  		e.w("  ")
 621  		e.w(oldCap)
 622  		e.w(" = extractvalue ")
 623  		e.w(sty)
 624  		e.w(" ")
 625  		e.w(src)
 626  		e.w(", 2\n")
 627  	}
 628  	low := "0"
 629  	if s.Low != nil {
 630  		low = e.sliceIdxToIpt(s.Low, ipt)
 631  	}
 632  	high := oldLen
 633  	if s.High != nil {
 634  		high = e.sliceIdxToIpt(s.High, ipt)
 635  	}
 636  	maxCap := oldCap
 637  	if s.Max != nil {
 638  		maxCap = e.sliceIdxToIpt(s.Max, ipt)
 639  	}
 640  	elemType := "i8"
 641  	if sl, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Slice); ok {
 642  		elemType = e.llvmType(sl.Elem())
 643  	} else if ar, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Array); ok {
 644  		elemType = e.llvmType(ar.Elem())
 645  	} else if p, ok := types.SafeUnderlying(s.X.SSAType()).(*types.Pointer); ok && p.Elem() != nil {
 646  		if ar, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
 647  			elemType = e.llvmType(ar.Elem())
 648  		}
 649  	}
 650  	srcOff := e.nextReg2("sl")
 651  	e.w("  ") ; e.w(srcOff) ; e.w(" = getelementptr inbounds ") ; e.w(elemType)
 652  	e.w(", ptr ") ; e.w(oldPtr) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(low) ; e.w("\n")
 653  	newLen := e.nextReg2("sl")
 654  	e.w("  ") ; e.w(newLen) ; e.w(" = sub ") ; e.w(ipt) ; e.w(" ") ; e.w(high) ; e.w(", ") ; e.w(low) ; e.w("\n")
 655  	elemSz := e.nextReg2("sl")
 656  	e.w("  ") ; e.w(elemSz) ; e.w(" = ptrtoint ptr getelementptr (")
 657  	e.w(elemType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 658  	totalBytes := e.nextReg2("sl")
 659  	e.w("  ") ; e.w(totalBytes) ; e.w(" = mul ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", ") ; e.w(elemSz) ; e.w("\n")
 660  	freshPtr := e.nextReg2("sl")
 661  	e.w("  ") ; e.w(freshPtr) ; e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
 662  	e.w(" ") ; e.w(totalBytes) ; e.w(", ptr null, ptr null)\n")
 663  	e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr, ptr")
 664  	cpReg := e.nextReg2("sl")
 665  	e.w("  ") ; e.w(cpReg) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.sliceCopy(ptr ") ; e.w(freshPtr)
 666  	e.w(", ptr ") ; e.w(srcOff) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen)
 667  	e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz) ; e.w(")\n")
 668  	e.declareRuntime("runtime.sliceCopy", ipt, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt)
 669  	s1 := e.nextReg2("sl")
 670  	e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(freshPtr) ; e.w(", 0\n")
 671  	s2 := e.nextReg2("sl")
 672  	e.w("  ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
 673  	e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(newLen) ; e.w(", 2\n")
 674  }
 675  
 676  func (e *irEmitter) sliceIdxToIpt(val ssa.SSAValue, ipt string) string {
 677  	operandStr := e.operand(val)
 678  	valType := e.llvmType(val.SSAType())
 679  	if valType == "void" || valType == "ptr" {
 680  		if at, ok := e.allocTypes[val]; ok && at != "ptr" && at != "void" {
 681  			valType = at
 682  		} else {
 683  			valType = "i32"
 684  		}
 685  	}
 686  	if valType == ipt {
 687  		return operandStr
 688  	}
 689  	e.nextReg++
 690  	ext := "%sl" | irItoa(e.nextReg)
 691  	srcBits := llvmTypeBits(valType)
 692  	dstBits := llvmTypeBits(ipt)
 693  	if srcBits > dstBits {
 694  		e.w("  ") ; e.w(ext) ; e.w(" = trunc ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 695  	} else {
 696  		op := "sext"
 697  		if b, ok2 := types.SafeUnderlying(val.SSAType()).(*types.Basic); ok2 && b.Info()&types.IsUnsigned != 0 {
 698  			op = "zext"
 699  		}
 700  		e.w("  ") ; e.w(ext) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(valType) ; e.w(" ") ; e.w(operandStr) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 701  	}
 702  	return ext
 703  }
 704