types.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 llvmArrayByteSize(t string) int64 {
10 if len(t) == 0 || t[0] != '[' {
11 return 0
12 }
13 i := 1
14 for i < len(t) && t[i] >= '0' && t[i] <= '9' {
15 i++
16 }
17 if i <= 1 {
18 return 0
19 }
20 n := int64(0)
21 for j := 1; j < i; j++ {
22 n = n*10 + int64(t[j]-'0')
23 }
24 xpos := -1
25 for k := i; k < len(t)-1; k++ {
26 if t[k] == 'x' && t[k-1] == ' ' && k+2 < len(t) && t[k+1] == ' ' {
27 xpos = k + 2
28 break
29 }
30 }
31 if xpos < 0 {
32 return 0
33 }
34 elemT := t[xpos:]
35 if len(elemT) > 0 && elemT[len(elemT)-1] == ']' {
36 elemT = elemT[:len(elemT)-1]
37 }
38 var elemSize int64
39 switch elemT {
40 case "i8":
41 elemSize = 1
42 case "i16":
43 elemSize = 2
44 case "i32", "float":
45 elemSize = 4
46 case "i64", "double", "ptr":
47 elemSize = 8
48 default:
49 inner := llvmArrayByteSize(elemT)
50 if inner > 0 {
51 elemSize = inner
52 } else {
53 elemSize = 8
54 }
55 }
56 return n * elemSize
57 }
58
59 func (e *irEmitter) emitZeroInit(typ, reg string) {
60 sz := llvmArrayByteSize(typ)
61 if sz >= 1024 {
62 e.w(" call void @llvm.memset.p0.i64(ptr ") ; e.w(reg) ; e.w(", i8 0, i64 ") ; e.w(irItoa64(sz)) ; e.w(", i1 false)\n")
63 e.declareRuntime("llvm.memset.p0.i64", "void", "ptr, i8, i64, i1")
64 } else {
65 e.w(" store ") ; e.w(typ) ; e.w(" zeroinitializer, ptr ") ; e.w(reg) ; e.w("\n")
66 }
67 }
68
69 func (e *irEmitter) regName(v ssa.SSAValue) string {
70 if v == nil {
71 e.nextReg++
72 return "%r" | irItoa(e.nextReg)
73 }
74 if n, ok := e.valName[v]; ok {
75 return n
76 }
77 name := v.SSAName()
78 if name == "" {
79 e.nextReg++
80 name = "r" | irItoa(e.nextReg)
81 }
82 n := "%" | name
83 for e.nameUsed[n] {
84 e.nextReg++
85 n = "%r" | irItoa(e.nextReg)
86 }
87 e.valName[v] = n
88 e.nameUsed[n] = true
89 return n
90 }
91
92 func (e *irEmitter) setRegType(v ssa.SSAValue, reg string, typ string) {
93 e.allocTypes[v] = typ
94 if len(reg) > 0 && reg[0] == '%' {
95 e.regTypes[reg] = typ
96 }
97 }
98
99 func (e *irEmitter) resolvedType(v ssa.SSAValue, fallback string) string {
100 if _, isIdx := v.(*ssa.SSAIndexAddr); isIdx {
101 return "ptr"
102 }
103 if at, ok := e.allocTypes[v]; ok {
104 return at
105 }
106 if n, ok := e.valName[v]; ok {
107 if rt, ok2 := e.regTypes[n]; ok2 {
108 return rt
109 }
110 }
111 op := e.operandNoSideEffect(v)
112 if len(op) > 0 && op[0] == '%' {
113 if rt, ok := e.regTypes[op]; ok {
114 return rt
115 }
116 }
117 return fallback
118 }
119
120 func (e *irEmitter) llvmType(t syntax.Type) string {
121 if t == nil {
122 return "void"
123 }
124 u := types.SafeUnderlying(t)
125 if u == nil {
126 if _, ok := t.(*types.Slice); ok {
127 return e.sliceType()
128 }
129 if n, ok := t.(*types.Named); ok {
130 _ = n
131 return "ptr"
132 }
133 return "ptr"
134 }
135 t = u
136 switch t := t.(type) {
137 case *types.Basic:
138 return e.llvmBasicType(t)
139 case *types.Pointer:
140 return "ptr"
141 case *types.Slice:
142 return e.sliceType()
143 case *types.Array:
144 n := t.Len()
145 if n < 0 {
146 return e.sliceType()
147 }
148 elem := e.llvmType(t.Elem())
149 return "[" | irItoa(int32(n)) | " x " | elem | "]"
150 case *types.TCStruct:
151 return e.llvmStructType(t)
152 case *types.Signature:
153 return "{ptr, ptr}"
154 case *types.TCMap:
155 return "ptr"
156 case *types.TCChan:
157 return "ptr"
158 case *types.TCInterface:
159 return e.ifaceType()
160 case *types.Named:
161 if t.Obj() != nil && t.Obj().Name() == "error" {
162 return e.ifaceType()
163 }
164 if t.NumMethods() > 0 && len(t.TypeArgs()) == 0 {
165 return e.ifaceType()
166 }
167 return "ptr"
168 case *types.Tuple:
169 if t == nil || t.Len() == 0 {
170 return "void"
171 }
172 if t.Len() == 1 {
173 return e.llvmType(t.At(0).Type())
174 }
175 s := "{"
176 for i := 0; i < t.Len(); i++ {
177 if i > 0 {
178 s = s | ", "
179 }
180 ft := e.llvmType(t.At(i).Type())
181 if ft == "void" {
182 ft = "ptr"
183 }
184 s = s | ft
185 }
186 return s | "}"
187 }
188 return "i8"
189 }
190
191 func (e *irEmitter) llvmBasicType(t *types.Basic) string {
192 switch t.Kind() {
193 case types.Bool:
194 return "i1"
195 case types.Int8, types.Uint8:
196 return "i8"
197 case types.Int16, types.Uint16:
198 return "i16"
199 case types.Int32, types.Uint32:
200 return "i32"
201 case types.Int64, types.Uint64:
202 return "i64"
203 case types.Float32:
204 return "float"
205 case types.Float64:
206 return "double"
207 case types.TCString:
208 return e.sliceType()
209 case types.UnsafePointer:
210 return "ptr"
211 case types.UntypedBool:
212 return "i1"
213 case types.UntypedInt, types.UntypedRune:
214 return "i32"
215 case types.UntypedFloat:
216 return "double"
217 case types.UntypedString:
218 return e.sliceType()
219 }
220 return "i32"
221 }
222
223 func (e *irEmitter) ptrType() string {
224 return "ptr"
225 }
226
227 func (e *irEmitter) intptrType() string {
228 if e.ptrBits == 32 {
229 return "i32"
230 }
231 return "i64"
232 }
233
234 func (e *irEmitter) sliceType() string {
235 ipt := e.intptrType()
236 return "{ptr, " | ipt | ", " | ipt | "}"
237 }
238
239 func (e *irEmitter) ifaceType() string {
240 return "{ptr, ptr}"
241 }
242
243 func (e *irEmitter) emitIntCast(dst, srcType, src, dstType string) string {
244 if srcType == dstType {
245 return src
246 }
247 srcBits := llvmTypeBits(srcType)
248 dstBits := llvmTypeBits(dstType)
249 if srcBits > dstBits {
250 e.w(" ") ; e.w(dst) ; e.w(" = trunc ") ; e.w(srcType) ; e.w(" ") ; e.w(src) ; e.w(" to ") ; e.w(dstType) ; e.w("\n")
251 } else {
252 e.w(" ") ; e.w(dst) ; e.w(" = sext ") ; e.w(srcType) ; e.w(" ") ; e.w(src) ; e.w(" to ") ; e.w(dstType) ; e.w("\n")
253 }
254 return dst
255 }
256
257 func llvmTypeBits(t string) int32 {
258 if t == "i1" { return 1 }
259 if t == "i8" { return 8 }
260 if t == "i16" { return 16 }
261 if t == "i32" { return 32 }
262 if t == "i64" { return 64 }
263 return 0
264 }
265
266 func (e *irEmitter) nextReg2(prefix string) string {
267 e.nextReg++
268 return "%" | prefix | irItoa(e.nextReg)
269 }
270
271 func (e *irEmitter) llvmStructType(t *types.TCStruct) string {
272 if t == nil {
273 return "{}"
274 }
275 s := "{"
276 for i := 0; i < t.NumFields(); i++ {
277 if i > 0 {
278 s = s | ", "
279 }
280 ft := e.llvmType(t.Field(i).Type())
281 if ft == "void" {
282 ft = "ptr"
283 }
284 s = s | ft
285 }
286 return s | "}"
287 }
288