calls.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) callArgType(arg ssa.SSAValue, sig *types.Signature, i int32) string {
  11  	if _, isFreeVar := arg.(*ssa.SSAFreeVar); isFreeVar {
  12  		return "ptr"
  13  	}
  14  	t := e.llvmType(arg.SSAType())
  15  	_, isIdxAddr := arg.(*ssa.SSAIndexAddr)
  16  	if _, isAlloc := arg.(*ssa.SSAAlloc); !isAlloc && !isIdxAddr {
  17  		resolved := e.resolvedType(arg, t)
  18  		if resolved != t {
  19  			t = resolved
  20  		}
  21  	}
  22  	if _, isConst := arg.(*ssa.SSAConst); isConst && sig != nil && sig.Params() != nil && isLLVMIntType(t) {
  23  		sigIdx := i
  24  		if sig.Recv() != nil {
  25  			sigIdx = i - 1
  26  		}
  27  		if sigIdx >= 0 && sigIdx < sig.Params().Len() {
  28  			sigT := e.llvmType(sig.Params().At(sigIdx).Type())
  29  			if isLLVMIntType(sigT) && sigT != t {
  30  				return sigT
  31  			}
  32  		}
  33  	}
  34  	if (t == "ptr" || t == "i1") && sig != nil && sig.Params() != nil {
  35  		_, isCall := arg.(*ssa.SSACall)
  36  		_, isAlloc := arg.(*ssa.SSAAlloc)
  37  		if !isCall && !isAlloc {
  38  			sigIdx := i
  39  			if sig.Recv() != nil {
  40  				sigIdx = i - 1
  41  			}
  42  			if sigIdx >= 0 && sigIdx < sig.Params().Len() {
  43  				sigT := e.llvmType(sig.Params().At(sigIdx).Type())
  44  				if sigT != "ptr" && sigT != "void" && sigT != "i1" && sigT != "" {
  45  					return sigT
  46  				}
  47  			}
  48  		}
  49  	}
  50  	if t == "ptr" || t == "i1" {
  51  		if load, ok := arg.(*ssa.SSAUnOp); ok && load.Op == ssa.OpMul {
  52  			if g, ok2 := load.X.(*ssa.SSAGlobal); ok2 {
  53  				if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
  54  					return gt
  55  				}
  56  			}
  57  		}
  58  	}
  59  	if t != "void" {
  60  		return t
  61  	}
  62  	if sig != nil && sig.Params() != nil {
  63  		sigIdx := i
  64  		if sig.Recv() != nil {
  65  			sigIdx = i - 1
  66  		}
  67  		if sigIdx >= 0 && sigIdx < sig.Params().Len() {
  68  			return e.llvmType(sig.Params().At(sigIdx).Type())
  69  		}
  70  	}
  71  	return "ptr"
  72  }
  73  
  74  func (e *irEmitter) funcCallRetType(c *ssa.SSACall) string {
  75  	sig := e.callSig(c)
  76  	if sig == nil || sig.Results() == nil || sig.Results().Len() == 0 {
  77  		return "void"
  78  	}
  79  	if sig.Results().Len() == 1 {
  80  		return e.resolveResultType(sig.Results().At(0).Type())
  81  	}
  82  	s := "{"
  83  	for i := 0; i < sig.Results().Len(); i++ {
  84  		if i > 0 { s = s | ", " }
  85  		s = s | e.resolveResultType(sig.Results().At(i).Type())
  86  	}
  87  	return s | "}"
  88  }
  89  
  90  func (e *irEmitter) callSig(c *ssa.SSACall) *types.Signature {
  91  	if fn, ok := c.Call.Value.(*ssa.SSAFunction); ok && fn.Signature != nil {
  92  		return fn.Signature
  93  	}
  94  	if sig, ok := types.SafeUnderlying(c.Call.Value.SSAType()).(*types.Signature); ok {
  95  		return sig
  96  	}
  97  	return nil
  98  }
  99  
 100  func (e *irEmitter) emitCall(c *ssa.SSACall) {
 101  	if b, ok := c.Call.Value.(*ssa.SSABuiltin); ok {
 102  		e.emitBuiltinCall(c, b)
 103  		return
 104  	}
 105  	reg := e.regName(c)
 106  	retType := e.llvmType(c.SSAType())
 107  	isVoid := retType == "void"
 108  	sig := e.callSig(c)
 109  
 110  	if fn, ok := c.Call.Value.(*ssa.SSAFunction); ok {
 111  		if fn.Pkg != nil && fn.Pkg.Pkg.Path() == "unsafe" {
 112  			ipt := e.intptrType()
 113  			switch fn.SSAName() {
 114  			case "Sizeof":
 115  				argType := "i8"
 116  				if len(c.Call.Args) > 0 {
 117  					at := e.llvmType(c.Call.Args[0].SSAType())
 118  					if at != "void" && at != "" {
 119  						argType = at
 120  					}
 121  				}
 122  				e.nextReg++
 123  				szr := "%sz" | irItoa(e.nextReg)
 124  				e.w("  ") ; e.w(szr) ; e.w(" = ptrtoint ptr getelementptr (")
 125  				e.w(argType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 126  				if ipt != "i32" {
 127  					e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(szr) ; e.w(" to i32\n")
 128  				} else {
 129  					e.w("  ") ; e.w(reg) ; e.w(" = add i32 ") ; e.w(szr) ; e.w(", 0\n")
 130  				}
 131  				return
 132  			case "Alignof":
 133  				argType := "i8"
 134  				if len(c.Call.Args) > 0 {
 135  					at := e.llvmType(c.Call.Args[0].SSAType())
 136  					if at != "void" && at != "" {
 137  						argType = at
 138  					}
 139  				}
 140  				al := e.nextReg2("align")
 141  				e.w("  ") ; e.w(al) ; e.w(" = ptrtoint ptr getelementptr (")
 142  				e.w(argType) ; e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
 143  				nal := e.nextReg2("nalgn")
 144  				e.w("  ") ; e.w(nal) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @llvm.cttz.")
 145  				e.w(ipt) ; e.w("(") ; e.w(ipt) ; e.w(" ") ; e.w(al) ; e.w(", i1 true)\n")
 146  				alw := e.nextReg2("alw")
 147  				e.w("  ") ; e.w(alw) ; e.w(" = shl ") ; e.w(ipt) ; e.w(" 1, ") ; e.w(nal) ; e.w("\n")
 148  				if ipt != "i32" {
 149  					e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(alw) ; e.w(" to i32\n")
 150  				} else {
 151  					e.w("  ") ; e.w(reg) ; e.w(" = add i32 ") ; e.w(alw) ; e.w(", 0\n")
 152  				}
 153  				return
 154  			case "Offsetof":
 155  				e.w("  ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
 156  				return
 157  			}
 158  		}
 159  		if !e.isPkgFunc(fn) {
 160  			e.declareExternalFunc(fn)
 161  		}
 162  		recvPromoReg := ""
 163  		if sig != nil && sig.Recv() != nil && len(c.Call.Args) > 0 && c.Call.Args[0] != nil {
 164  			at := e.callArgType(c.Call.Args[0], sig, 0)
 165  			if at != "ptr" && len(at) > 0 && (at[0] == '{' || at[0] == '[') {
 166  				av := e.operand(c.Call.Args[0])
 167  				recvPromoReg = e.nextReg2("rcv")
 168  				e.w("  ") ; e.w(recvPromoReg) ; e.w(" = alloca ") ; e.w(at) ; e.w("\n")
 169  				e.w("  store ") ; e.w(at) ; e.w(" ") ; e.w(av) ; e.w(", ptr ") ; e.w(recvPromoReg) ; e.w("\n")
 170  			}
 171  		}
 172  		e.w("  ")
 173  		if !isVoid {
 174  			e.w(reg) ; e.w(" = ")
 175  		}
 176  		e.w("call ") ; e.w(retType) ; e.w(" ")
 177  		e.w(e.funcSymbol(fn))
 178  		e.w("(")
 179  		for i, arg := range c.Call.Args {
 180  			if i > 0 { e.w(", ") }
 181  			if arg == nil {
 182  				e.w("ptr null")
 183  				continue
 184  			}
 185  			if i == 0 && recvPromoReg != "" {
 186  				e.w("ptr ") ; e.w(recvPromoReg)
 187  				continue
 188  			}
 189  			at := e.callArgType(arg, sig, i)
 190  			av := e.operand(arg)
 191  			if av == "null" && at != "ptr" {
 192  				if at == "void" {
 193  					at = "ptr"
 194  				} else {
 195  					av = "zeroinitializer"
 196  				}
 197  			}
 198  			if (at == "float" || at == "double") && isConstOperand(av) {
 199  				av = ensureTokenFloatLit(av)
 200  			}
 201  			e.w(at) ; e.w(" ") ; e.w(av)
 202  		}
 203  		if !fn.IsExternC() {
 204  			if len(c.Call.Args) > 0 { e.w(", ") }
 205  			e.w("ptr null")
 206  		}
 207  		e.w(")\n")
 208  		return
 209  	}
 210  
 211  	funcVal := e.operand(c.Call.Value)
 212  	funcPtr := e.nextReg2("fp")
 213  	ctx := e.nextReg2("ctx")
 214  	e.w("  ") ; e.w(funcPtr) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 1\n")
 215  	e.w("  ") ; e.w(ctx) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(funcVal) ; e.w(", 0\n")
 216  	e.w("  ")
 217  	if !isVoid {
 218  		e.w(reg) ; e.w(" = ")
 219  	}
 220  	e.w("call ") ; e.w(retType) ; e.w(" ") ; e.w(funcPtr) ; e.w("(")
 221  	for i, arg := range c.Call.Args {
 222  		if i > 0 { e.w(", ") }
 223  		at := e.callArgType(arg, sig, i)
 224  		av := e.operand(arg)
 225  		if av == "null" && at != "ptr" {
 226  			if at == "void" {
 227  				at = "ptr"
 228  			} else {
 229  				av = "zeroinitializer"
 230  			}
 231  		}
 232  		if (at == "float" || at == "double") && isConstOperand(av) {
 233  			av = ensureTokenFloatLit(av)
 234  		}
 235  		e.w(at) ; e.w(" ") ; e.w(av)
 236  	}
 237  	if len(c.Call.Args) > 0 { e.w(", ") }
 238  	e.w("ptr ") ; e.w(ctx)
 239  	e.w(")\n")
 240  }
 241  
 242  func (e *irEmitter) emitBuiltinCall(c *ssa.SSACall, b *ssa.SSABuiltin) {
 243  	reg := e.regName(c)
 244  	name := b.SSAName()
 245  	if name == "recover" {
 246  		retType := e.ifaceType()
 247  		e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(retType) ; e.w(" zeroinitializer, ptr null, 0\n")
 248  		e.allocTypes[c] = retType
 249  		return
 250  	}
 251  	ipt := e.intptrType()
 252  	sty := e.sliceType()
 253  	if name == "len" {
 254  		if len(c.Call.Args) == 1 {
 255  			arg := e.operand(c.Call.Args[0])
 256  			u := types.SafeUnderlying(c.Call.Args[0].SSAType())
 257  			if u == nil { u = c.Call.Args[0].SSAType() }
 258  			if arr, ok := u.(*types.Array); ok {
 259  				retType := e.llvmType(c.SSAType())
 260  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
 261  				_ = arg
 262  				return
 263  			}
 264  			if p, ok := u.(*types.Pointer); ok && p.Elem() != nil {
 265  				if arr, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
 266  					retType := e.llvmType(c.SSAType())
 267  					e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
 268  					_ = arg
 269  					return
 270  				}
 271  			}
 272  			_, isSlice := u.(*types.Slice)
 273  			_, isMap := u.(*types.TCMap)
 274  			isStr := e.isStringLike(c.Call.Args[0].SSAType())
 275  			if !isSlice && !isMap && !isStr {
 276  				isSlice = true
 277  			}
 278  			if isMap {
 279  				retType := e.llvmType(c.SSAType())
 280  				e.nextReg++
 281  				tmp := "%bl" | irItoa(e.nextReg)
 282  				e.w("  ") ; e.w(tmp) ; e.w(" = call ") ; e.w(ipt) ; e.w(" @runtime.hashmapLen(ptr ") ; e.w(arg) ; e.w(")\n")
 283  				if retType != ipt {
 284  					e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
 285  				} else {
 286  					e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(", 0\n")
 287  				}
 288  				e.declareRuntime("runtime.hashmapLen", ipt, "ptr")
 289  				return
 290  			}
 291  			if isSlice || isStr {
 292  				retType := e.llvmType(c.SSAType())
 293  				if retType != ipt {
 294  					e.nextReg++
 295  					tmp := "%bl" | irItoa(e.nextReg)
 296  					e.w("  ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
 297  					e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
 298  				} else {
 299  					e.w("  ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 1\n")
 300  				}
 301  				return
 302  			}
 303  		}
 304  	} else if name == "cap" {
 305  		if len(c.Call.Args) == 1 {
 306  			arg := e.operand(c.Call.Args[0])
 307  			uc := types.SafeUnderlying(c.Call.Args[0].SSAType())
 308  			if uc == nil { uc = c.Call.Args[0].SSAType() }
 309  			if arr, ok := uc.(*types.Array); ok {
 310  				retType := e.llvmType(c.SSAType())
 311  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
 312  				_ = arg
 313  				return
 314  			}
 315  			if p, ok := uc.(*types.Pointer); ok && p.Elem() != nil {
 316  				if arr, ok2 := types.SafeUnderlying(p.Elem()).(*types.Array); ok2 {
 317  					retType := e.llvmType(c.SSAType())
 318  					e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(retType) ; e.w(" ") ; e.w(irItoa(int32(arr.Len()))) ; e.w(", 0\n")
 319  					_ = arg
 320  					return
 321  				}
 322  			}
 323  			_, isSlice := uc.(*types.Slice)
 324  			isStr := e.isStringLike(c.Call.Args[0].SSAType())
 325  			if isSlice || isStr {
 326  				retType := e.llvmType(c.SSAType())
 327  				if retType != ipt {
 328  					e.nextReg++
 329  					tmp := "%bl" | irItoa(e.nextReg)
 330  					e.w("  ") ; e.w(tmp) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
 331  					e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
 332  				} else {
 333  					e.w("  ") ; e.w(reg) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(arg) ; e.w(", 2\n")
 334  				}
 335  				return
 336  			}
 337  		}
 338  	} else if name == "append" {
 339  		if len(c.Call.Args) > 2 {
 340  			src := e.operand(c.Call.Args[0])
 341  			elemType := ""
 342  			if sl, ok := types.SafeUnderlying(c.Call.Args[0].SSAType()).(*types.Slice); ok {
 343  				elemType = e.llvmType(sl.Elem())
 344  			}
 345  			if sl, ok := c.Call.Args[0].SSAType().(*types.Slice); ok && (elemType == "" || elemType == "void") {
 346  				elemType = e.llvmType(sl.Elem())
 347  			}
 348  			if elemType == "" || elemType == "void" {
 349  				et := e.llvmType(c.Call.Args[1].SSAType())
 350  				if et != "" && et != "void" {
 351  					elemType = et
 352  				} else {
 353  					elemType = "i8"
 354  				}
 355  			}
 356  			nElems := len(c.Call.Args) - 1
 357  			arrAlloca := e.nextReg2("ap")
 358  			arrTy := "[" | irItoa(nElems) | " x " | elemType | "]"
 359  			e.w("  ") ; e.w(arrAlloca) ; e.w(" = alloca ") ; e.w(arrTy) ; e.w("\n")
 360  			for j := 1; j < len(c.Call.Args); j++ {
 361  				elemVal := e.operand(c.Call.Args[j])
 362  				argLLT := e.llvmType(c.Call.Args[j].SSAType())
 363  				if len(argLLT) > 1 && argLLT[0] == 'i' && len(elemType) > 1 && elemType[0] == 'i' && argLLT != elemType {
 364  					aw := irParseIntWidth(argLLT)
 365  					ew := irParseIntWidth(elemType)
 366  					if ew > 0 && aw > ew {
 367  						tr := e.nextReg2("ap")
 368  						e.w("  ") ; e.w(tr) ; e.w(" = trunc ") ; e.w(argLLT) ; e.w(" ") ; e.w(elemVal) ; e.w(" to ") ; e.w(elemType) ; e.w("\n")
 369  						elemVal = tr
 370  					}
 371  				}
 372  				gep := e.nextReg2("ap")
 373  				e.w("  ") ; e.w(gep) ; e.w(" = getelementptr inbounds ") ; e.w(arrTy)
 374  				e.w(", ptr ") ; e.w(arrAlloca) ; e.w(", i32 0, i32 ") ; e.w(irItoa(j-1)) ; e.w("\n")
 375  				e.w("  store ") ; e.w(elemType) ; e.w(" ") ; e.w(elemVal) ; e.w(", ptr ") ; e.w(gep) ; e.w("\n")
 376  			}
 377  			srcBuf := e.nextReg2("ap")
 378  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
 379  			srcLen := e.nextReg2("ap")
 380  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
 381  			srcCap := e.nextReg2("ap")
 382  			e.w("  ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
 383  			elemSz := e.nextReg2("ap")
 384  			e.w("  ") ; e.w(elemSz)
 385  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
 386  			e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
 387  			retTy := e.sliceType()
 388  			result := e.nextReg2("ap")
 389  			e.w("  ") ; e.w(result)
 390  			e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
 391  			e.w(srcBuf) ; e.w(", ptr ") ; e.w(arrAlloca)
 392  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
 393  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcCap)
 394  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(irItoa(nElems))
 395  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
 396  			e.w(")\n")
 397  			newPtr := e.nextReg2("ap")
 398  			e.w("  ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
 399  			e.scopeTrackAlloc(newPtr)
 400  			newLen := e.nextReg2("ap")
 401  			e.w("  ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
 402  			newCap := e.nextReg2("ap")
 403  			e.w("  ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
 404  			s1 := e.nextReg2("ap")
 405  			e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
 406  			s2 := e.nextReg2("ap")
 407  			e.w("  ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
 408  			e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
 409  			e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
 410  			return
 411  		}
 412  		if len(c.Call.Args) == 2 {
 413  			src := e.operand(c.Call.Args[0])
 414  			elems := e.operand(c.Call.Args[1])
 415  			elemType := ""
 416  			arg0t := c.Call.Args[0].SSAType()
 417  			if sl, ok := types.SafeUnderlying(arg0t).(*types.Slice); ok {
 418  				elemType = e.llvmType(sl.Elem())
 419  			}
 420  			if sl, ok := arg0t.(*types.Slice); ok && (elemType == "" || elemType == "void") {
 421  				elemType = e.llvmType(sl.Elem())
 422  			}
 423  			if elemType == "" || elemType == "void" {
 424  				et := e.llvmType(c.Call.Args[1].SSAType())
 425  				if et != "" && et != "void" {
 426  					elemType = et
 427  				} else {
 428  					elemType = "i8"
 429  				}
 430  			}
 431  			srcBuf := e.nextReg2("ap")
 432  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
 433  			srcLen := e.nextReg2("ap")
 434  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
 435  			srcCap := e.nextReg2("ap")
 436  			e.w("  ") ; e.w(srcCap) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 2\n")
 437  			var elemsBuf, elemsLen string
 438  			arg1IsSlice := c.Call.HasDots
 439  			if !arg1IsSlice && c.Call.Args[1] != nil {
 440  				arg1t := c.Call.Args[1].SSAType()
 441  				if arg1t != nil {
 442  					arg1LT := e.llvmType(arg1t)
 443  					if arg1LT == e.sliceType() && elemType != e.sliceType() {
 444  						arg1IsSlice = true
 445  					}
 446  				}
 447  				if !arg1IsSlice {
 448  					arg0t := c.Call.Args[0].SSAType()
 449  					if arg0t != nil && arg1t != nil {
 450  						if Identical(arg0t, arg1t) {
 451  							if _, ok := types.SafeUnderlying(arg0t).(*types.Slice); ok {
 452  								arg1IsSlice = true
 453  							}
 454  						}
 455  					}
 456  				}
 457  			}
 458  			if arg1IsSlice {
 459  				elemsBuf = e.nextReg2("ap")
 460  				e.w("  ") ; e.w(elemsBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 0\n")
 461  				elemsLen = e.nextReg2("ap")
 462  				e.w("  ") ; e.w(elemsLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(elems) ; e.w(", 1\n")
 463  			} else {
 464  				argLLT := ""
 465  				if c.Call.Args[1] != nil && c.Call.Args[1].SSAType() != nil {
 466  					argLLT = e.llvmType(c.Call.Args[1].SSAType())
 467  				}
 468  				if argLLT == "" {
 469  					argLLT = e.resolvedType(c.Call.Args[1], elemType)
 470  				}
 471  				if len(argLLT) > 1 && argLLT[0] == 'i' && len(elemType) > 1 && elemType[0] == 'i' && argLLT != elemType {
 472  					aw := irParseIntWidth(argLLT)
 473  					ew := irParseIntWidth(elemType)
 474  					if ew > 0 && aw > ew {
 475  						tr := e.nextReg2("ap")
 476  						e.w("  ") ; e.w(tr) ; e.w(" = trunc ") ; e.w(argLLT) ; e.w(" ") ; e.w(elems) ; e.w(" to ") ; e.w(elemType) ; e.w("\n")
 477  						elems = tr
 478  					} else if aw > 0 && ew > aw {
 479  						tr := e.nextReg2("ap")
 480  						e.w("  ") ; e.w(tr) ; e.w(" = sext ") ; e.w(argLLT) ; e.w(" ") ; e.w(elems) ; e.w(" to ") ; e.w(elemType) ; e.w("\n")
 481  						elems = tr
 482  					}
 483  				}
 484  				alloca := e.nextReg2("ap")
 485  				e.w("  ") ; e.w(alloca) ; e.w(" = alloca ") ; e.w(elemType) ; e.w("\n")
 486  				storeVal := elems
 487  				if storeVal == "null" && elemType != "ptr" {
 488  					storeVal = "zeroinitializer"
 489  				}
 490  				e.w("  store ") ; e.w(elemType) ; e.w(" ") ; e.w(storeVal) ; e.w(", ptr ") ; e.w(alloca) ; e.w("\n")
 491  				elemsBuf = alloca
 492  				elemsLen = "1"
 493  			}
 494  			elemSz := e.nextReg2("ap")
 495  			e.w("  ") ; e.w(elemSz)
 496  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
 497  			e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
 498  			retTy := e.sliceType()
 499  			result := e.nextReg2("ap")
 500  			e.w("  ") ; e.w(result)
 501  			e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
 502  			e.w(srcBuf) ; e.w(", ptr ") ; e.w(elemsBuf)
 503  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
 504  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcCap)
 505  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemsLen)
 506  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
 507  			e.w(")\n")
 508  			newPtr := e.nextReg2("ap")
 509  			e.w("  ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
 510  			e.scopeTrackAlloc(newPtr)
 511  			newLen := e.nextReg2("ap")
 512  			e.w("  ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
 513  			newCap := e.nextReg2("ap")
 514  			e.w("  ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
 515  			s1 := e.nextReg2("ap")
 516  			e.w("  ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
 517  			s2 := e.nextReg2("ap")
 518  			e.w("  ") ; e.w(s2) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s1) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newLen) ; e.w(", 1\n")
 519  			e.w("  ") ; e.w(reg) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" ") ; e.w(s2) ; e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(newCap) ; e.w(", 2\n")
 520  			e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
 521  			return
 522  		}
 523  	} else if name == "copy" {
 524  		if len(c.Call.Args) == 2 {
 525  			dst := e.operand(c.Call.Args[0])
 526  			src := e.operand(c.Call.Args[1])
 527  			elemType := "i8"
 528  			if sl, ok := types.SafeUnderlying(c.Call.Args[0].SSAType()).(*types.Slice); ok {
 529  				elemType = e.llvmType(sl.Elem())
 530  			}
 531  			dstBuf := e.nextReg2("cp")
 532  			e.w("  ") ; e.w(dstBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 0\n")
 533  			dstLen := e.nextReg2("cp")
 534  			e.w("  ") ; e.w(dstLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(dst) ; e.w(", 1\n")
 535  			srcBuf := e.nextReg2("cp")
 536  			e.w("  ") ; e.w(srcBuf) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 0\n")
 537  			srcLen := e.nextReg2("cp")
 538  			e.w("  ") ; e.w(srcLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(src) ; e.w(", 1\n")
 539  			elemSz := e.nextReg2("cp")
 540  			e.w("  ") ; e.w(elemSz)
 541  			e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
 542  			e.w(", ptr null, i32 1) to ") ; e.w(e.intptrType()) ; e.w("\n")
 543  			callReg := e.nextReg2("cp")
 544  			e.w("  ") ; e.w(callReg)
 545  			e.w(" = call ") ; e.w(e.intptrType()) ; e.w(" @runtime.sliceCopy(ptr ")
 546  			e.w(dstBuf) ; e.w(", ptr ") ; e.w(srcBuf)
 547  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(dstLen)
 548  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(srcLen)
 549  			e.w(", ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(elemSz)
 550  			e.w(")\n")
 551  			retType := e.llvmType(c.SSAType())
 552  			if retType != e.intptrType() {
 553  				e.w("  ") ; e.w(reg) ; e.w(" = trunc ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(callReg) ; e.w(" to ") ; e.w(retType) ; e.w("\n")
 554  			} else {
 555  				e.w("  ") ; e.w(reg) ; e.w(" = add ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(callReg) ; e.w(", 0\n")
 556  			}
 557  			e.declareRuntime("runtime.sliceCopy", e.intptrType(), "ptr, ptr, " | e.intptrType() | ", " | e.intptrType() | ", " | e.intptrType())
 558  			return
 559  		}
 560  	} else if name == "print" || name == "println" {
 561  		e.w("  call void @runtime.printlock()\n")
 562  		for i, arg := range c.Call.Args {
 563  			if i > 0 && b.id == BuiltinPrintln {
 564  				e.w("  call void @runtime.printspace()\n")
 565  			}
 566  			av := e.operand(arg)
 567  			at := arg.SSAType()
 568  			e.emitPrintArg(av, at)
 569  		}
 570  		if b.id == BuiltinPrintln {
 571  			e.w("  call void @runtime.printnl()\n")
 572  			e.declareRuntime("runtime.printnl", "void", "")
 573  		}
 574  		e.w("  call void @runtime.printunlock()\n")
 575  		e.declareRuntime("runtime.printlock", "void", "")
 576  		e.declareRuntime("runtime.printunlock", "void", "")
 577  		if b.id == BuiltinPrintln && len(c.Call.Args) > 1 {
 578  			e.declareRuntime("runtime.printspace", "void", "")
 579  		}
 580  		return
 581  	} else if name == "delete" {
 582  		if len(c.Call.Args) == 2 {
 583  			mapVal := e.operand(c.Call.Args[0])
 584  			keyVal := e.operand(c.Call.Args[1])
 585  			var mt *types.TCMap
 586  			if okv, okok := types.SafeUnderlying(c.Call.Args[0].SSAType()).(*types.TCMap); okok {
 587  				mt = okv
 588  			}
 589  			keyType := "i32"
 590  			if mt != nil {
 591  				keyType = e.llvmType(mt.Key())
 592  			}
 593  			keyAlloca := e.nextReg2("dl")
 594  			e.w("  ") ; e.w(keyAlloca) ; e.w(" = alloca ") ; e.w(keyType) ; e.w("\n")
 595  			e.w("  store ") ; e.w(keyType) ; e.w(" ") ; e.w(keyVal) ; e.w(", ptr ") ; e.w(keyAlloca) ; e.w("\n")
 596  			e.w("  call void @runtime.hashmapBinaryDelete(ptr ") ; e.w(mapVal)
 597  			e.w(", ptr ") ; e.w(keyAlloca) ; e.w(")\n")
 598  			e.declareRuntime("runtime.hashmapBinaryDelete", "void", "ptr, ptr")
 599  			return
 600  		}
 601  	} else if name == "close" {
 602  		if len(c.Call.Args) == 1 {
 603  			e.w("  call void @runtime.chanClose(ptr ")
 604  			e.w(e.operand(c.Call.Args[0]))
 605  			e.w(")\n")
 606  			e.declareRuntime("runtime.chanClose", "void", "ptr")
 607  			return
 608  		}
 609  	} else if name == "min" || name == "max" {
 610  		if len(c.Call.Args) >= 2 {
 611  			retType := e.llvmType(c.SSAType())
 612  			if retType == "" || retType == "void" {
 613  				retType = "i32"
 614  			}
 615  			a := e.operand(c.Call.Args[0])
 616  			b2 := e.operand(c.Call.Args[1])
 617  			cmpOp := "slt"
 618  			if b.id == BuiltinMax {
 619  				cmpOp = "sgt"
 620  			}
 621  			u := types.SafeUnderlying(c.SSAType())
 622  			if bb, ok := u.(*types.Basic); ok && bb.Info()&types.IsUnsigned != 0 {
 623  				cmpOp = "ult"
 624  				if b.id == BuiltinMax {
 625  					cmpOp = "ugt"
 626  				}
 627  			}
 628  			e.nextReg++
 629  			cmpReg := "%mm" | irItoa(e.nextReg)
 630  			e.w("  ") ; e.w(cmpReg) ; e.w(" = icmp ") ; e.w(cmpOp) ; e.w(" ") ; e.w(retType) ; e.w(" ") ; e.w(a) ; e.w(", ") ; e.w(b2) ; e.w("\n")
 631  			e.w("  ") ; e.w(reg) ; e.w(" = select i1 ") ; e.w(cmpReg) ; e.w(", ") ; e.w(retType) ; e.w(" ") ; e.w(a) ; e.w(", ") ; e.w(retType) ; e.w(" ") ; e.w(b2) ; e.w("\n")
 632  			return
 633  		}
 634  	}
 635  	e.w("  ; unhandled builtin: ")
 636  	e.w(name)
 637  	e.w("\n")
 638  	retType := e.llvmType(c.SSAType())
 639  	if retType != "void" && retType != "" {
 640  		if retType == "ptr" || e.intBits(retType) > 0 || retType == "i1" {
 641  			e.emitZeroReg(reg, c.SSAType())
 642  		} else {
 643  			e.nextReg++
 644  			tmp := "%ub" | irItoa(e.nextReg)
 645  			e.w("  ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(retType) ; e.w("\n")
 646  			e.w("  ") ; e.w(reg) ; e.w(" = load ") ; e.w(retType) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
 647  			e.allocTypes[c] = retType
 648  		}
 649  	}
 650  }
 651  
 652  func (e *irEmitter) emitPrintArg(val string, t syntax.Type) {
 653  	if t == nil {
 654  		return
 655  	}
 656  	sty := e.sliceType()
 657  	switch u := types.SafeUnderlying(t).(type) {
 658  	case *types.Basic:
 659  		switch {
 660  		case u.Info()&types.IsString != 0:
 661  			e.w("  call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
 662  			e.declareRuntime("runtime.printstring", "void", sty)
 663  		case u.Kind() == types.Bool || u.Kind() == types.UntypedBool:
 664  			e.w("  call void @runtime.printbool(i1 ") ; e.w(val) ; e.w(")\n")
 665  			e.declareRuntime("runtime.printbool", "void", "i1")
 666  		case u.Kind() == types.Float32:
 667  			e.w("  call void @runtime.printfloat32(float ") ; e.w(val) ; e.w(")\n")
 668  			e.declareRuntime("runtime.printfloat32", "void", "float")
 669  		case u.Kind() == types.Float64 || u.Kind() == types.UntypedFloat:
 670  			e.w("  call void @runtime.printfloat64(double ") ; e.w(val) ; e.w(")\n")
 671  			e.declareRuntime("runtime.printfloat64", "void", "double")
 672  		case u.Info()&types.IsUnsigned != 0:
 673  			lt := e.llvmType(t)
 674  			fname := "runtime.printuint" | lt[1:]
 675  			e.w("  call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
 676  			e.declareRuntime(fname, "void", lt)
 677  		case u.Info()&types.IsInteger != 0:
 678  			lt := e.llvmType(t)
 679  			fname := "runtime.printint" | lt[1:]
 680  			e.w("  call void @") ; e.w(fname) ; e.w("(") ; e.w(lt) ; e.w(" ") ; e.w(val) ; e.w(")\n")
 681  			e.declareRuntime(fname, "void", lt)
 682  		}
 683  	case *types.Pointer:
 684  		ipt := e.intptrType()
 685  		e.nextReg++
 686  		tmp := "%pr" | irItoa(e.nextReg)
 687  		e.w("  ") ; e.w(tmp) ; e.w(" = ptrtoint ptr ") ; e.w(val) ; e.w(" to ") ; e.w(ipt) ; e.w("\n")
 688  		e.w("  call void @runtime.printptr(") ; e.w(ipt) ; e.w(" ") ; e.w(tmp) ; e.w(")\n")
 689  		e.declareRuntime("runtime.printptr", "void", ipt)
 690  	case *types.Slice:
 691  		if b, ok := u.Elem().(*types.Basic); ok && (b.Kind() == Uint8 || b.Kind() == Int8) {
 692  			e.w("  call void @runtime.printbytes(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
 693  			e.declareRuntime("runtime.printbytes", "void", sty)
 694  		} else {
 695  			e.w("  call void @runtime.printstring(") ; e.w(sty) ; e.w(" ") ; e.w(val) ; e.w(")\n")
 696  			e.declareRuntime("runtime.printstring", "void", sty)
 697  		}
 698  	case *types.TCMap:
 699  		e.w("  call void @runtime.printmap(ptr ") ; e.w(val) ; e.w(")\n")
 700  		e.declareRuntime("runtime.printmap", "void", "ptr")
 701  	}
 702  }
 703