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