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