ir_alloc.mx raw
1 package main
2
3 import (
4 . "git.smesh.lol/moxie/pkg/types"
5 )
6
7 func (e *irEmitter) emitAlloc(a *SSAAlloc) {
8 reg := e.regName(a)
9 if at, ok := e.allocTypes[a]; ok && len(at) > 0 && at[0] == '[' {
10 if a.Heap {
11 ipt := e.intptrType()
12 e.nextReg++
13 sz := "%ha" | irItoa(e.nextReg)
14 e.w(" ") ; e.w(sz)
15 e.w(" = ptrtoint ptr getelementptr (") ; e.w(at)
16 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
17 e.w(" ") ; e.w(reg)
18 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
19 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
20 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr")
21 e.scopeTrackAlloc(reg)
22 } else {
23 e.w(" ") ; e.w(reg) ; e.w(" = alloca ") ; e.w(at) ; e.w("\n")
24 e.w(" store ") ; e.w(at) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
25 }
26 return
27 }
28 elemType := e.llvmType(a.SSAType())
29 nilElem := false
30 if p, ok := SafeUnderlying(a.SSAType()).(*Pointer); ok {
31 if p.Base != nil {
32 elemType = e.llvmType(p.Base)
33 } else {
34 nilElem = true
35 }
36 }
37 isDoublePtr := false
38 if p, ok := SafeUnderlying(a.SSAType()).(*Pointer); ok && p.Base != nil {
39 if _, ok2 := SafeUnderlying(p.Base).(*Pointer); ok2 {
40 isDoublePtr = true
41 }
42 }
43 if isDoublePtr && elemType == "ptr" {
44 e.allocTypes[a] = elemType
45 } else if elemType == "void" {
46 inferred := e.inferAllocTypeFromStores(a)
47 elemType = inferred
48 e.allocTypes[a] = elemType
49 } else if elemType == "ptr" && nilElem {
50 inferred := e.inferAllocTypeFromStores(a)
51 if inferred != "ptr" && (len(inferred) == 0 || inferred[0] != '{') {
52 elemType = inferred
53 }
54 e.allocTypes[a] = elemType
55 } else {
56 isSimple := elemType == "i1" || elemType == "i8" || elemType == "i16" || elemType == "i32" || elemType == "i64" || elemType == "float" || elemType == "double" || elemType == "ptr"
57 if !isSimple {
58 override := e.inferAllocTypeFromStores(a)
59 if override != "ptr" && override != elemType {
60 bothScalar := len(elemType) > 0 && elemType[0] == 'i' && len(override) > 0 && override[0] == 'i'
61 isFloatToInt := (elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == 'i'
62 isScalarToAgg := len(elemType) > 0 && (elemType[0] == 'i' || elemType == "double" || elemType == "float") && len(override) > 0 && override[0] == '{'
63 isAggToScalar := len(elemType) > 0 && elemType[0] == '{' && len(override) > 0 && (override[0] == 'i' || override == "double" || override == "float")
64 if !bothScalar && !isFloatToInt && !isScalarToAgg && !isAggToScalar {
65 elemType = override
66 e.allocTypes[a] = elemType
67 }
68 }
69 }
70 }
71 isSimple2 := elemType == "i1" || elemType == "i8" || elemType == "i16" || elemType == "i32" || elemType == "i64" || elemType == "float" || elemType == "double" || elemType == "ptr"
72 if !isDoublePtr && !isSimple2 {
73 if faType := e.inferAllocTypeFromFieldAddrs(a, elemType); faType != "" {
74 retType := e.inferAllocTypeFromReturn(a)
75 callType := e.inferAllocTypeFromCallArgs(a)
76 appendType := e.inferAllocTypeFromAppendUsage(a)
77 best := faType
78 if retType != "" && len(retType) > len(best) {
79 best = retType
80 }
81 if callType != "" && len(callType) > len(best) {
82 best = callType
83 }
84 if appendType != "" && len(appendType) > len(best) {
85 best = appendType
86 }
87 if elemType != best {
88 elemType = best
89 e.allocTypes[a] = elemType
90 }
91 }
92 }
93 if a.Heap {
94 ipt := e.intptrType()
95 e.nextReg++
96 sz := "%ha" | irItoa(e.nextReg)
97 e.w(" ") ; e.w(sz)
98 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
99 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
100 e.w(" ") ; e.w(reg)
101 e.w(" = call ptr @runtime.alloc(") ; e.w(ipt)
102 e.w(" ") ; e.w(sz) ; e.w(", ptr null, ptr null)\n")
103 e.declareRuntime("runtime.alloc", "ptr", ipt | ", ptr")
104 e.scopeTrackAlloc(reg)
105 } else {
106 e.w(" ")
107 e.w(reg)
108 e.w(" = alloca ")
109 e.w(elemType)
110 e.w("\n")
111 e.w(" store ") ; e.w(elemType) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
112 }
113 }
114
115 func (e *irEmitter) inferAllocTypeFromStores(a *SSAAlloc) (s string) {
116 allocName := a.SSAName()
117 for _, b := range e.curFunc.Blocks {
118 for _, instr := range b.Instrs {
119 if sv, okSv := instr.(*SSAStore); okSv && sv.Addr != nil && sv.Addr.SSAName() == allocName {
120 if at, ok2 := e.allocTypes[sv.Val]; ok2 && at != "ptr" && at != "void" {
121 return at
122 }
123 vt := e.llvmType(sv.Val.SSAType())
124 if vt != "void" && vt != "" {
125 return vt
126 }
127 if call, ok3 := sv.Val.(*SSACall); ok3 {
128 if b2, ok4 := call.Call.Value.(*SSABuiltin); ok4 && b2.SSAName() == "append" {
129 return e.sliceType()
130 }
131 }
132 if _, ok4 := sv.Val.(*SSASlice); ok4 {
133 return e.sliceType()
134 }
135 if _, ok5 := sv.Val.(*SSAMakeSlice); ok5 {
136 return e.sliceType()
137 }
138 }
139 }
140 }
141 return "ptr"
142 }
143
144 func (e *irEmitter) inferAllocTypeFromReturn(a *SSAAlloc) (s string) {
145 allocName := a.SSAName()
146 for _, b := range e.curFunc.Blocks {
147 for _, instr := range b.Instrs {
148 ret, ok := instr.(*SSAReturn)
149 if !ok {
150 continue
151 }
152 for i, rv := range ret.Results {
153 if rv == nil {
154 continue
155 }
156 if uop, ok2 := rv.(*SSAUnOp); ok2 && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
157 sig := e.curFunc.Signature
158 if sig != nil && sig.Results != nil && i < sig.Results.Len() {
159 rt := e.llvmType(sig.Results.At(i).Typ)
160 if rt != "void" && rt != "ptr" && rt != "" {
161 return rt
162 }
163 }
164 return ""
165 }
166 }
167 }
168 }
169 return ""
170 }
171
172 func (e *irEmitter) inferAllocTypeFromCallArgs(a *SSAAlloc) (s string) {
173 allocName := a.SSAName()
174 loadNames := map[string]bool{}
175 for _, b := range e.curFunc.Blocks {
176 for _, instr := range b.Instrs {
177 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
178 loadNames[uop.SSAName()] = true
179 }
180 }
181 }
182 for _, b := range e.curFunc.Blocks {
183 for _, instr := range b.Instrs {
184 call, ok := instr.(*SSACall)
185 if !ok { continue }
186 callee := call.Call.Value
187 if callee == nil { continue }
188 var sig *Signature
189 if cfn, ok2 := callee.(*SSAFunction); ok2 && cfn.Signature != nil {
190 sig = cfn.Signature
191 } else {
192 sig, _ = SafeUnderlying(callee.SSAType()).(*Signature)
193 }
194 if sig == nil || sig.Params == nil { continue }
195 recvOff := 0
196 if sig.Recv != nil { recvOff = 1 }
197 for i, arg := range call.Call.Args {
198 if arg == nil { continue }
199 if !loadNames[arg.SSAName()] { continue }
200 sigIdx := i - recvOff
201 if sigIdx < 0 || sigIdx >= sig.Params.Len() { continue }
202 pt := e.llvmType(sig.Params.At(sigIdx).Typ)
203 if pt != "void" && pt != "ptr" && pt != "" && len(pt) > 0 && pt[0] == '{' {
204 return pt
205 }
206 }
207 }
208 }
209 return ""
210 }
211
212 func (e *irEmitter) inferAllocTypeFromAppendUsage(a *SSAAlloc) (s string) {
213 allocName := a.SSAName()
214 loadNames := map[string]bool{}
215 for _, b := range e.curFunc.Blocks {
216 for _, instr := range b.Instrs {
217 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
218 loadNames[uop.SSAName()] = true
219 }
220 }
221 }
222 if len(loadNames) == 0 {
223 return ""
224 }
225 for _, b := range e.curFunc.Blocks {
226 for _, instr := range b.Instrs {
227 call, ok := instr.(*SSACall)
228 if !ok {
229 continue
230 }
231 bi, ok2 := call.Call.Value.(*SSABuiltin)
232 if !ok2 || bi.SSAName() != "append" {
233 continue
234 }
235 if len(call.Call.Args) < 2 {
236 continue
237 }
238 for j := 1; j < len(call.Call.Args); j++ {
239 arg := call.Call.Args[j]
240 if arg == nil {
241 continue
242 }
243 if !loadNames[arg.SSAName()] {
244 continue
245 }
246 sliceArg := call.Call.Args[0]
247 if sl, ok3 := SafeUnderlying(sliceArg.SSAType()).(*Slice); ok3 {
248 et := e.llvmType(sl.Elem)
249 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
250 return et
251 }
252 }
253 if sl, ok3 := sliceArg.SSAType().(*Slice); ok3 {
254 et := e.llvmType(sl.Elem)
255 if et != "" && et != "void" && et != "ptr" && len(et) > 0 && et[0] == '{' {
256 return et
257 }
258 }
259 }
260 }
261 }
262 return ""
263 }
264
265 func (e *irEmitter) inferAllocTypeFromFieldAddrs(a *SSAAlloc, baseType string) (s string) {
266 allocName := a.SSAName()
267 names := map[string]bool{allocName: true}
268 for _, b := range e.curFunc.Blocks {
269 for _, instr := range b.Instrs {
270 if uop, ok := instr.(*SSAUnOp); ok && uop.Op == OpMul && uop.X != nil && uop.X.SSAName() == allocName {
271 names[uop.SSAName()] = true
272 }
273 }
274 }
275 maxField := -1
276 fieldTypes := map[int32]string{}
277 for _, b := range e.curFunc.Blocks {
278 for _, instr := range b.Instrs {
279 fa, ok := instr.(*SSAFieldAddr)
280 if !ok || fa.X == nil || !names[fa.X.SSAName()] {
281 continue
282 }
283 if fa.Field > maxField {
284 maxField = fa.Field
285 }
286 faName := fa.SSAName()
287 for _, b2 := range e.curFunc.Blocks {
288 for _, i2 := range b2.Instrs {
289 if sv, ok2 := i2.(*SSAStore); ok2 && sv.Addr != nil && sv.Addr.SSAName() == faName {
290 ft := e.llvmType(sv.Val.SSAType())
291 if ft != "void" && ft != "" {
292 fieldTypes[fa.Field] = ft
293 }
294 }
295 if ld, ok2 := i2.(*SSAUnOp); ok2 && ld.Op == OpMul && ld.X != nil && ld.X.SSAName() == faName {
296 ft := e.llvmType(ld.SSAType())
297 if ft != "void" && ft != "" && ft != "ptr" {
298 if _, exists := fieldTypes[fa.Field]; !exists {
299 fieldTypes[fa.Field] = ft
300 }
301 }
302 }
303 }
304 }
305 }
306 }
307 if maxField < 0 {
308 return ""
309 }
310 baseFields := parseStructFields(baseType)
311 top := maxField
312 if len(baseFields)-1 > top {
313 top = len(baseFields) - 1
314 }
315 s := "{"
316 for i := 0; i <= top; i++ {
317 if i > 0 {
318 s = s | ", "
319 }
320 ft, ok := fieldTypes[i]
321 if !ok {
322 if i < len(baseFields) && baseFields[i] != "" {
323 ft = baseFields[i]
324 } else {
325 ft = "ptr"
326 }
327 } else if i < len(baseFields) && baseFields[i] != "" {
328 bw := irParseIntWidth(baseFields[i])
329 fw := irParseIntWidth(ft)
330 if bw > 0 && fw > 0 && bw > fw {
331 ft = baseFields[i]
332 }
333 }
334 s = s | ft
335 }
336 return s | "}"
337 }
338
339 func (e *irEmitter) inferAllocTypeFromUsage(a *SSAAlloc) (s string) {
340 allocName := a.SSAName()
341 loadNames := map[string]bool{}
342 for _, b := range e.curFunc.Blocks {
343 for _, instr := range b.Instrs {
344 load, ok := instr.(*SSAUnOp)
345 if !ok || load.Op != OpMul {
346 continue
347 }
348 if load.X != nil && load.X.SSAName() == allocName {
349 loadNames[load.SSAName()] = true
350 }
351 }
352 }
353 if len(loadNames) == 0 {
354 return "ptr"
355 }
356 for _, b := range e.curFunc.Blocks {
357 for _, instr := range b.Instrs {
358 switch u := instr.(type) {
359 case *SSASlice:
360 if u.X != nil && loadNames[u.X.SSAName()] {
361 return e.sliceType()
362 }
363 case *SSAIndexAddr:
364 if u.X != nil && loadNames[u.X.SSAName()] {
365 return e.sliceType()
366 }
367 case *SSACall:
368 for _, arg := range u.Call.Args {
369 if arg != nil && loadNames[arg.SSAName()] {
370 if bi, ok2 := u.Call.Value.(*SSABuiltin); ok2 {
371 nm := bi.SSAName()
372 if nm == "append" || nm == "copy" || nm == "len" || nm == "cap" {
373 return e.sliceType()
374 }
375 }
376 }
377 }
378 }
379 }
380 }
381 return "ptr"
382 }
383
384 func (e *irEmitter) emitZeroReg(reg string, typ Type) {
385 rt := e.llvmType(typ)
386 if rt == "void" || rt == "" {
387 rt = "i32"
388 }
389 if rt == "ptr" {
390 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr " | e.intptrType() | " 0 to ptr\n")
391 } else if rt == "i1" {
392 e.w(" ") ; e.w(reg) ; e.w(" = add i1 false, false\n")
393 } else if e.intBits(rt) > 0 {
394 e.w(" ") ; e.w(reg) ; e.w(" = add ") ; e.w(rt) ; e.w(" 0, 0\n")
395 } else {
396 e.w(" ") ; e.w(reg) ; e.w(" = add i32 0, 0\n")
397 }
398 }
399