ops.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) emitBinOp(b *ssa.SSABinOp) {
11 if b.X == nil || b.X.SSAType() == nil {
12 recov := false
13 if b.X == nil {
14 for _, blk := range e.curFunc.Blocks {
15 for i, inst := range blk.Instrs {
16 if inst == b && i > 0 {
17 if prev, ok := blk.Instrs[i-1].(*ssa.SSAUnOp); ok && prev.Op == ssa.OpMul {
18 b.X = prev
19 recov = true
20 }
21 }
22 }
23 if recov { break }
24 }
25 }
26 if !recov && b.X != nil {
27 rt := e.resolvedType(b.X, "i32")
28 if rt != "i32" && rt != "" {
29 reg := e.regName(b)
30 lv := e.operand(b.X)
31 rv := e.operand(b.Y)
32 isCmp := b.Op == ssa.OpEql || b.Op == ssa.OpNeq || b.Op == ssa.OpLss || b.Op == ssa.OpGtr || b.Op == ssa.OpLeq || b.Op == ssa.OpGeq
33 if isCmp && len(rt) > 0 && rt[0] == '{' && rt != "{ptr, ptr}" && rt != e.sliceType() && rt != e.ifaceType() {
34 e.emitStructCompareByLLVM(reg, b.Op, rt, lv, rv)
35 return
36 }
37 op := e.llvmBinOp(b.Op, nil)
38 if rt == "float" || rt == "double" {
39 op = e.floatBinOp(b.Op)
40 lv = ensureTokenFloatLit(lv)
41 rv = ensureTokenFloatLit(rv)
42 }
43 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(rt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(rv) ; e.w("\n")
44 if !isCmp {
45 e.setRegType(b, reg, rt)
46 }
47 return
48 }
49 }
50 if !recov {
51 e.emitZeroReg(e.regName(b), b.SSAType())
52 return
53 }
54 }
55 reg := e.regName(b)
56 lt := e.llvmType(b.X.SSAType())
57 if lt == "void" && b.Y != nil {
58 lt = e.llvmType(b.Y.SSAType())
59 }
60 if at, ok := e.allocTypes[b.X]; ok && at != "ptr" && at != "void" && at != lt {
61 isScalarToAgg := len(lt) > 0 && (lt[0] == 'i' || lt == "double" || lt == "float") && len(at) > 0 && at[0] == '{'
62 isAggToScalar := len(lt) > 0 && lt[0] == '{' && len(at) > 0 && (at[0] == 'i' || at == "double" || at == "float")
63 if !isScalarToAgg && !isAggToScalar {
64 lt = at
65 }
66 }
67 lv := e.operand(b.X)
68 rv := e.operand(b.Y)
69 if (b.Op == ssa.OpAdd || b.Op == ssa.OpOr) && b.X.SSAType() != nil {
70 if sl, ok := types.SafeUnderlying(b.X.SSAType()).(*types.Slice); ok {
71 e.emitSliceConcat(reg, sl, lv, rv)
72 return
73 }
74 if e.isStringLike(b.X.SSAType()) {
75 e.emitSliceConcat(reg, types.NewSlice(types.Typ[types.Uint8]), lv, rv)
76 return
77 }
78 }
79 if b.X.SSAType() != nil && e.isStringLike(b.X.SSAType()) && (lt == e.sliceType() || lt == "ptr" || lt == "void") {
80 isActuallyIface := false
81 if at, ok := e.allocTypes[b.X]; ok && at == e.ifaceType() {
82 isActuallyIface = true
83 }
84 rvOK := true
85 if b.Y != nil {
86 rvType := e.llvmType(b.Y.SSAType())
87 rvResolved := e.resolvedType(b.Y, rvType)
88 if load, ok := b.Y.(*ssa.SSAUnOp); ok && load.Op == ssa.OpMul {
89 if g, ok2 := load.X.(*ssa.SSAGlobal); ok2 {
90 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
91 rvResolved = gt
92 }
93 }
94 }
95 if e.intBits(rvResolved) > 0 {
96 rvOK = false
97 }
98 }
99 if !isActuallyIface && rvOK {
100 e.emitStringCompare(reg, b.Op, lv, rv)
101 return
102 }
103 }
104 if lt == e.sliceType() {
105 rvOK2 := true
106 if b.Y != nil {
107 rvType2 := e.llvmType(b.Y.SSAType())
108 rvResolved2 := e.resolvedType(b.Y, rvType2)
109 if load, ok := b.Y.(*ssa.SSAUnOp); ok && load.Op == ssa.OpMul {
110 if g, ok2 := load.X.(*ssa.SSAGlobal); ok2 {
111 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
112 rvResolved2 = gt
113 }
114 }
115 }
116 if e.intBits(rvResolved2) > 0 {
117 rvOK2 = false
118 }
119 }
120 if rvOK2 {
121 e.emitStringCompare(reg, b.Op, lv, rv)
122 return
123 }
124 }
125 if (b.Op == ssa.OpEql || b.Op == ssa.OpNeq) && (rv == "null" || rv == "zeroinitializer" || lv == "null" || lv == "zeroinitializer") && b.X.SSAType() != nil {
126 u := types.SafeUnderlying(b.X.SSAType())
127 _, isIface := u.(*types.TCInterface)
128 _, isSlice := u.(*types.Slice)
129 _, isSig := u.(*types.Signature)
130 _, isPtr := u.(*types.Pointer)
131 _, isMap := u.(*types.TCMap)
132 _, isChan := u.(*types.TCChan)
133 if isMap || isChan {
134 isPtr = true
135 }
136 if !isIface && !isSlice && !isSig && !isPtr && u == nil && (lt == "{ptr, ptr}" || lt == "{ptr, i64}") {
137 isIface = true
138 }
139 if isSig {
140 e.nextReg++
141 extReg := "%ne" | irItoa(e.nextReg)
142 aggVal := lv
143 if lv == "null" || lv == "zeroinitializer" {
144 aggVal = rv
145 }
146 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 1\n")
147 cmpOp := "icmp eq"
148 if b.Op == ssa.OpNeq {
149 cmpOp = "icmp ne"
150 }
151 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
152 return
153 }
154 if isIface || isSlice || e.isStringLike(b.X.SSAType()) {
155 e.nextReg++
156 extReg := "%ne" | irItoa(e.nextReg)
157 aggVal := lv
158 if lv == "null" || lv == "zeroinitializer" {
159 aggVal = rv
160 }
161 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 0\n")
162 cmpOp := "icmp eq"
163 if b.Op == ssa.OpNeq {
164 cmpOp = "icmp ne"
165 }
166 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
167 return
168 }
169 if isPtr {
170 cmpOp := "icmp eq"
171 if b.Op == ssa.OpNeq {
172 cmpOp = "icmp ne"
173 }
174 ptrVal := lv
175 if lv == "null" || lv == "zeroinitializer" {
176 ptrVal = rv
177 }
178 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(ptrVal) ; e.w(", null\n")
179 return
180 }
181 }
182 if (b.Op == ssa.OpEql || b.Op == ssa.OpNeq) && len(lt) > 0 && lt[0] == '{' && lt != "{ptr, ptr}" && lt != e.sliceType() && lt != e.ifaceType() {
183 if b.X.SSAType() != nil {
184 if st, ok := types.SafeUnderlying(b.X.SSAType()).(*types.TCStruct); ok {
185 slt := e.llvmStructType(st)
186 e.emitStructCompare(reg, b.Op, st, slt, lv, rv)
187 return
188 }
189 }
190 e.emitStructCompareByLLVM(reg, b.Op, lt, lv, rv)
191 return
192 }
193 if (b.Op == ssa.OpEql || b.Op == ssa.OpNeq) && b.X.SSAType() != nil {
194 if st, okta := types.SafeUnderlying(b.X.SSAType()).(*types.TCStruct); okta && (st != nil && len(lt) > 0 && lt[0] == '{') {
195 slt := e.llvmStructType(st)
196 if slt == lt || (lt != e.ifaceType() && lt != e.sliceType()) {
197 e.emitStructCompare(reg, b.Op, st, slt, lv, rv)
198 return
199 }
200 }
201 if ar, ok := types.SafeUnderlying(b.X.SSAType()).(*types.Array); ok && len(lt) > 0 && lt[0] == '[' {
202 e.emitArrayCompare(reg, b.Op, ar, lt, lv, rv)
203 return
204 }
205 u2 := types.SafeUnderlying(b.X.SSAType())
206 _, isSig2 := u2.(*types.Signature)
207 _, isIfce2 := u2.(*types.TCInterface)
208 if !isSig2 && !isIfce2 && u2 == nil && lt == "{ptr, ptr}" {
209 isIfce2 = true
210 }
211 if isSig2 || isIfce2 {
212 nilField := "0"
213 if isSig2 {
214 nilField = "1"
215 }
216 rt2 := "ptr"
217 if b.Y != nil && b.Y.SSAType() != nil {
218 rt2 = e.llvmType(b.Y.SSAType())
219 }
220 if lt == "{ptr, ptr}" && rt2 == "ptr" {
221 e.nextReg++
222 extReg := "%fc" | irItoa(e.nextReg)
223 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
224 cmpOp := "icmp eq"
225 if b.Op == ssa.OpNeq { cmpOp = "icmp ne" }
226 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
227 return
228 }
229 if lt == "ptr" && rt2 == "{ptr, ptr}" {
230 e.nextReg++
231 extReg := "%fc" | irItoa(e.nextReg)
232 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
233 cmpOp := "icmp eq"
234 if b.Op == ssa.OpNeq { cmpOp = "icmp ne" }
235 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
236 return
237 }
238 if lt == "{ptr, ptr}" && rt2 != "{ptr, ptr}" && rt2 != "ptr" {
239 sty := e.sliceType()
240 e.nextReg++
241 tmp := "%fc" | irItoa(e.nextReg)
242 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(rt2) ; e.w("\n")
243 e.w(" store ") ; e.w(rt2) ; e.w(" ") ; e.w(rv) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
244 e.nextReg++
245 dp := "%fc" | irItoa(e.nextReg)
246 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
247 if rt2 == sty {
248 e.nextReg++
249 ldp := "%fc" | irItoa(e.nextReg)
250 e.w(" ") ; e.w(ldp) ; e.w(" = load ") ; e.w(sty) ; e.w(", ptr ") ; e.w(dp) ; e.w("\n")
251 e.nextReg++
252 lpA := "%fc" | irItoa(e.nextReg)
253 e.w(" ") ; e.w(lpA) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(ldp) ; e.w(", 0\n")
254 e.nextReg++
255 lpB := "%fc" | irItoa(e.nextReg)
256 e.w(" ") ; e.w(lpB) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
257 e.nextReg++
258 llA := "%fc" | irItoa(e.nextReg)
259 e.w(" ") ; e.w(llA) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(ldp) ; e.w(", 1\n")
260 e.nextReg++
261 llB := "%fc" | irItoa(e.nextReg)
262 e.w(" ") ; e.w(llB) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
263 e.nextReg++
264 cA := "%fc" | irItoa(e.nextReg)
265 e.nextReg++
266 cB := "%fc" | irItoa(e.nextReg)
267 cmpOp := "icmp eq"
268 combOp := "and"
269 if b.Op == ssa.OpNeq {
270 cmpOp = "icmp ne"
271 combOp = "or"
272 }
273 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lpA) ; e.w(", ") ; e.w(lpB) ; e.w("\n")
274 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(llA) ; e.w(", ") ; e.w(llB) ; e.w("\n")
275 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
276 return
277 }
278 cmpOp := "icmp eq"
279 if b.Op == ssa.OpNeq { cmpOp = "icmp ne" }
280 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(dp) ; e.w(", ") ; e.w(tmp) ; e.w("\n")
281 return
282 }
283 e.nextReg++
284 pA := "%fc" | irItoa(e.nextReg)
285 e.nextReg++
286 pB := "%fc" | irItoa(e.nextReg)
287 e.nextReg++
288 qA := "%fc" | irItoa(e.nextReg)
289 e.nextReg++
290 qB := "%fc" | irItoa(e.nextReg)
291 e.nextReg++
292 cA := "%fc" | irItoa(e.nextReg)
293 e.nextReg++
294 cB := "%fc" | irItoa(e.nextReg)
295 e.w(" ") ; e.w(pA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 0\n")
296 e.w(" ") ; e.w(pB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 0\n")
297 e.w(" ") ; e.w(qA) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
298 e.w(" ") ; e.w(qB) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 1\n")
299 cmpOp := "icmp eq"
300 combOp := "and"
301 if b.Op == ssa.OpNeq {
302 cmpOp = "icmp ne"
303 combOp = "or"
304 }
305 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(pA) ; e.w(", ") ; e.w(pB) ; e.w("\n")
306 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(qA) ; e.w(", ") ; e.w(qB) ; e.w("\n")
307 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
308 return
309 }
310 }
311 if b.Op == ssa.OpEql || b.Op == ssa.OpNeq {
312 rvt := ""
313 if b.Y != nil && b.Y.SSAType() != nil {
314 rvt = e.llvmType(b.Y.SSAType())
315 }
316 if lt == "ptr" && rvt == "{ptr, ptr}" {
317 e.nextReg++
318 extReg := "%pi" | irItoa(e.nextReg)
319 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(rv) ; e.w(", 1\n")
320 cmpOp := "icmp eq"
321 if b.Op == ssa.OpNeq { cmpOp = "icmp ne" }
322 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
323 return
324 }
325 if lt == "{ptr, ptr}" && rvt == "ptr" {
326 e.nextReg++
327 extReg := "%pi" | irItoa(e.nextReg)
328 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue {ptr, ptr} ") ; e.w(lv) ; e.w(", 1\n")
329 cmpOp := "icmp eq"
330 if b.Op == ssa.OpNeq { cmpOp = "icmp ne" }
331 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
332 return
333 }
334 }
335 if b.Op == ssa.OpAndNot {
336 rt := ""
337 if b.Y != nil && b.Y.SSAType() != nil {
338 rt = e.llvmType(b.Y.SSAType())
339 rt = e.resolvedType(b.Y, rt)
340 }
341 lt = e.resolvedType(b.X, lt)
342 if rt != "" && rt != lt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
343 rv = e.coerceInt(rv, rt, lt)
344 }
345 e.nextReg++
346 notReg := "%an" | irItoa(e.nextReg)
347 allOnes := "-1"
348 e.w(" ") ; e.w(notReg) ; e.w(" = xor ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(allOnes) ; e.w("\n")
349 e.w(" ") ; e.w(reg) ; e.w(" = and ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(notReg) ; e.w("\n")
350 e.setRegType(b, reg, lt)
351 return
352 }
353 if b.Y == nil || b.Y.SSAType() == nil {
354 e.emitZeroReg(e.regName(b), b.SSAType())
355 return
356 }
357 rt := e.llvmType(b.Y.SSAType())
358 atl0 := e.resolvedType(b.X, lt)
359 if atl0 != lt {
360 lt = atl0
361 }
362 atr0 := e.resolvedType(b.Y, rt)
363 if atr0 != rt {
364 rt = atr0
365 }
366 coerced := false
367 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
368 isCmp := b.Op == ssa.OpEql || b.Op == ssa.OpNeq || b.Op == ssa.OpLss || b.Op == ssa.OpGtr || b.Op == ssa.OpLeq || b.Op == ssa.OpGeq
369 resType := e.llvmType(b.SSAType())
370 if !isCmp && e.intBits(resType) > 0 {
371 if lt != resType {
372 lv = e.coerceInt(lv, lt, resType)
373 lt = resType
374 }
375 if rt != resType {
376 rv = e.coerceInt(rv, rt, resType)
377 }
378 } else if e.intBits(lt) > e.intBits(rt) {
379 rv = e.coerceInt(rv, rt, lt)
380 } else {
381 lv = e.coerceInt(lv, lt, rt)
382 lt = rt
383 }
384 coerced = true
385 }
386 if lt == rt && !coerced {
387 atl := e.resolvedType(b.X, lt)
388 if atl != lt {
389 lt = atl
390 }
391 if b.Y != nil {
392 atr := e.resolvedType(b.Y, rt)
393 if atr != rt {
394 rt = atr
395 }
396 }
397 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
398 if e.intBits(lt) > e.intBits(rt) {
399 rv = e.coerceInt(rv, rt, lt)
400 rt = lt
401 } else if e.intBits(rt) > e.intBits(lt) {
402 lv = e.coerceInt(lv, lt, rt)
403 lt = rt
404 }
405 }
406 }
407 resultIsInt := e.intBits(e.llvmType(b.SSAType())) > 0
408 isLF := lt == "double" || lt == "float"
409 isRF := rt == "double" || rt == "float"
410 if !isRF && isConstOperand(rv) && looksLikeFloat(rv) {
411 if resultIsInt {
412 if iv, ok := floatLitToInt(rv); ok {
413 rv = irItoa64(iv)
414 }
415 } else {
416 isRF = true
417 rt = "double"
418 }
419 }
420 if !isLF && isConstOperand(lv) && looksLikeFloat(lv) {
421 if resultIsInt {
422 if iv, ok := floatLitToInt(lv); ok {
423 lv = irItoa64(iv)
424 }
425 } else {
426 isLF = true
427 lt = "double"
428 }
429 }
430 if isLF && isRF {
431 ssaLT := e.llvmType(b.X.SSAType())
432 ssaRT := ""
433 if b.Y != nil && b.Y.SSAType() != nil {
434 ssaRT = e.llvmType(b.Y.SSAType())
435 }
436 if !isConstOperand(lv) && e.intBits(ssaLT) > 0 {
437 _, hasRT := e.regTypes[lv]
438 if !hasRT {
439 lv = e.intToFloat(lv, ssaLT, lt)
440 }
441 }
442 if !isConstOperand(rv) && e.intBits(ssaRT) > 0 {
443 _, hasRT := e.regTypes[rv]
444 if !hasRT {
445 rv = e.intToFloat(rv, ssaRT, rt)
446 }
447 }
448 } else if !isLF && isRF && e.intBits(lt) > 0 {
449 if resultIsInt {
450 demoted := false
451 if yc, ok := b.Y.(*ssa.SSAConst); ok {
452 if cf, ok2 := yc.Value().(*types.ConstFloat); ok2 {
453 lit := cf.Lit
454 if lit == "" {
455 lit = cf.String()
456 }
457 if iv, ok3 := floatLitToInt(lit); ok3 {
458 rv = irItoa64(iv)
459 rt = lt
460 isRF = false
461 demoted = true
462 }
463 }
464 }
465 if !demoted {
466 if isConstOperand(lv) {
467 lv = ensureTokenFloatLit(lv)
468 } else {
469 lv = e.intToFloat(lv, lt, rt)
470 }
471 lt = rt
472 }
473 } else {
474 if isConstOperand(lv) {
475 lv = ensureTokenFloatLit(lv)
476 } else {
477 lv = e.intToFloat(lv, lt, rt)
478 }
479 lt = rt
480 }
481 } else if isLF && !isRF && e.intBits(rt) > 0 {
482 if resultIsInt {
483 if xc, ok := b.X.(*ssa.SSAConst); ok {
484 if cf, ok2 := xc.Value().(*types.ConstFloat); ok2 {
485 lit := cf.Lit
486 if lit == "" {
487 lit = cf.String()
488 }
489 if iv, ok3 := floatLitToInt(lit); ok3 {
490 lv = irItoa64(iv)
491 lt = rt
492 isLF = false
493 }
494 }
495 }
496 if isLF {
497 if isConstOperand(rv) {
498 rv = ensureTokenFloatLit(rv)
499 } else {
500 rv = e.intToFloat(rv, rt, lt)
501 }
502 rt = lt
503 }
504 } else {
505 if isConstOperand(rv) {
506 rv = ensureTokenFloatLit(rv)
507 } else {
508 rv = e.intToFloat(rv, rt, lt)
509 }
510 rt = lt
511 }
512 }
513 if lt == "float" && rt == "double" {
514 e.nextReg++
515 tmp := "%fext" | irItoa(e.nextReg)
516 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(lv) ; e.w(" to double\n")
517 lv = tmp
518 lt = "double"
519 } else if lt == "double" && rt == "float" {
520 e.nextReg++
521 tmp := "%fext" | irItoa(e.nextReg)
522 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(rv) ; e.w(" to double\n")
523 rv = tmp
524 rt = "double"
525 }
526 op := e.llvmBinOp(b.Op, b.X.SSAType())
527 if op == "" {
528 e.w(" ; unsupported binop\n")
529 return
530 }
531 isCmpOp := b.Op == ssa.OpEql || b.Op == ssa.OpNeq || b.Op == ssa.OpLss || b.Op == ssa.OpGtr || b.Op == ssa.OpLeq || b.Op == ssa.OpGeq
532 if lt == "double" || lt == "float" {
533 rv = ensureTokenFloatLit(rv)
534 lv = ensureTokenFloatLit(lv)
535 op = e.floatBinOp(b.Op)
536 if !isCmpOp {
537 e.setRegType(b, reg, lt)
538 }
539 } else if !isCmpOp {
540 ssaLT := e.llvmType(b.X.SSAType())
541 if ssaLT != lt {
542 e.setRegType(b, reg, lt)
543 }
544 }
545 if len(lt) > 0 && lt[0] == '[' && (b.Op == ssa.OpEql || b.Op == ssa.OpNeq) {
546 e.emitArrayCompareByLLVM(reg, b.Op, lt, lv, rv)
547 return
548 }
549 if lt == "ptr" && !isCmpOp {
550 e.nextReg++
551 pi := "%pi" | irItoa(e.nextReg)
552 e.w(" ") ; e.w(pi) ; e.w(" = ptrtoint ptr ") ; e.w(lv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
553 e.nextReg++
554 ri := "%pi" | irItoa(e.nextReg)
555 rvCoerced := rv
556 if rv != "0" && rv != "1" && rv != "-1" {
557 e.w(" ") ; e.w(ri) ; e.w(" = ptrtoint ptr ") ; e.w(rv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
558 rvCoerced = ri
559 }
560 e.nextReg++
561 ai := "%pi" | irItoa(e.nextReg)
562 e.w(" ") ; e.w(ai) ; e.w(" = ") ; e.w(op) ; e.w(" ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(pi) ; e.w(", ") ; e.w(rvCoerced) ; e.w("\n")
563 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(ai) ; e.w(" to ptr\n")
564 return
565 }
566 if isCmpOp && lt == "i32" && b.Y != nil && b.Y.SSAType() != nil {
567 rvt := e.llvmType(b.Y.SSAType())
568 rvr := e.resolvedType(b.Y, rvt)
569 if rvr == e.sliceType() || rvt == e.sliceType() {
570 lt = e.sliceType()
571 }
572 }
573 if isCmpOp && lt == "i32" {
574 lr := e.resolvedType(b.X, lt)
575 if lr == e.sliceType() {
576 lt = e.sliceType()
577 }
578 }
579 if lt == e.sliceType() && isCmpOp {
580 rvIsInt := false
581 if b.Y != nil {
582 rvt3 := e.llvmType(b.Y.SSAType())
583 rvr3 := e.resolvedType(b.Y, rvt3)
584 if e.intBits(rvr3) > 0 {
585 rvIsInt = true
586 }
587 }
588 lvIsInt := false
589 if b.X != nil && b.X.SSAType() != nil {
590 lxt := e.llvmType(b.X.SSAType())
591 if e.intBits(lxt) > 0 {
592 lvIsInt = true
593 }
594 }
595 if !rvIsInt && !lvIsInt {
596 e.emitStringCompare(reg, b.Op, lv, rv)
597 return
598 }
599 }
600 if isCmpOp && len(lt) > 0 && lt[0] == '{' {
601 e.emitStructCompareByLLVM(reg, b.Op, lt, lv, rv)
602 return
603 }
604 e.w(" ")
605 e.w(reg)
606 e.w(" = ")
607 e.w(op)
608 e.w(" ")
609 e.w(lt)
610 e.w(" ")
611 e.w(lv)
612 e.w(", ")
613 e.w(rv)
614 e.w("\n")
615 }
616
617 func looksLikeFloat(s string) bool {
618 if len(s) == 0 {
619 return false
620 }
621 if s[0] != '-' && s[0] != '+' && (s[0] < '0' || s[0] > '9') {
622 return false
623 }
624 for i := 0; i < len(s); i++ {
625 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
626 return true
627 }
628 }
629 return false
630 }
631
632 func floatLitToInt(s string) (int64, bool) {
633 if len(s) == 0 {
634 return 0, false
635 }
636 i := 0
637 neg := false
638 if s[0] == '-' {
639 neg = true
640 i = 1
641 } else if s[0] == '+' {
642 i = 1
643 }
644 var intPart int64
645 for ; i < len(s); i++ {
646 ch := s[i]
647 if ch == '_' {
648 continue
649 }
650 if ch < '0' || ch > '9' {
651 break
652 }
653 intPart = intPart*10 + int64(ch-'0')
654 }
655 var fracDigits int32
656 if i < len(s) && s[i] == '.' {
657 i++
658 for ; i < len(s); i++ {
659 ch := s[i]
660 if ch == '_' {
661 continue
662 }
663 if ch < '0' || ch > '9' {
664 break
665 }
666 if ch != '0' {
667 return 0, false
668 }
669 fracDigits++
670 }
671 }
672 _ = fracDigits
673 exp := 0
674 if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
675 i++
676 expNeg := false
677 if i < len(s) && s[i] == '-' {
678 expNeg = true
679 i++
680 } else if i < len(s) && s[i] == '+' {
681 i++
682 }
683 for ; i < len(s); i++ {
684 ch := s[i]
685 if ch < '0' || ch > '9' {
686 break
687 }
688 exp = exp*10 + int32(ch-'0')
689 }
690 if expNeg {
691 return 0, false
692 }
693 }
694 result := intPart
695 for j := 0; j < exp; j++ {
696 result = result * 10
697 if result < 0 {
698 return 0, false
699 }
700 }
701 if neg {
702 result = -result
703 }
704 if result == 0 {
705 return 0, false
706 }
707 return result, true
708 }
709
710 func isLLVMIntType(s string) bool {
711 if len(s) < 2 || s[0] != 'i' {
712 return false
713 }
714 for j := 1; j < len(s); j++ {
715 if s[j] < '0' || s[j] > '9' {
716 return false
717 }
718 }
719 return true
720 }
721
722 func isConstOperand(s string) bool {
723 if len(s) == 0 {
724 return false
725 }
726 return s[0] != '%' && s[0] != '@'
727 }
728
729 func ensureTokenFloatLit(s string) string {
730 if len(s) == 0 || s[0] == '%' || s[0] == '@' {
731 return s
732 }
733 if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
734 return s
735 }
736 hasDecimal := false
737 for i := 0; i < len(s); i++ {
738 if s[i] == '.' || s[i] == 'e' || s[i] == 'E' {
739 hasDecimal = true
740 break
741 }
742 }
743 if !hasDecimal {
744 return s | ".0"
745 }
746 return s
747 }
748
749 func (e *irEmitter) emitSliceConcat(reg string, sl *types.Slice, lv, rv string) {
750 ipt := e.intptrType()
751 sty := "{ptr, " | ipt | ", " | ipt | "}"
752 if isBareLiteral(lv) { lv = "zeroinitializer" }
753 if isBareLiteral(rv) { rv = "zeroinitializer" }
754 elemType := e.llvmType(sl.Elem())
755 xPtr := e.nextReg2("cc")
756 e.w(" ") ; e.w(xPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
757 xLen := e.nextReg2("cc")
758 e.w(" ") ; e.w(xLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
759 yPtr := e.nextReg2("cc")
760 e.w(" ") ; e.w(yPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
761 yLen := e.nextReg2("cc")
762 e.w(" ") ; e.w(yLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
763 elemSz := e.nextReg2("cc")
764 e.w(" ") ; e.w(elemSz)
765 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
766 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
767 retTy := "{ptr, " | ipt | ", " | ipt | "}"
768 result := e.nextReg2("cc")
769 e.w(" ") ; e.w(result)
770 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
771 e.w(xPtr) ; e.w(", ptr ") ; e.w(yPtr)
772 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
773 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
774 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(yLen)
775 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
776 e.w(")\n")
777 newPtr := e.nextReg2("cc")
778 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
779 e.scopeTrackAlloc(newPtr)
780 newLen := e.nextReg2("cc")
781 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
782 newCap := e.nextReg2("cc")
783 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
784 s1 := e.nextReg2("cc")
785 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
786 s2 := e.nextReg2("cc")
787 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")
788 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(newCap) ; e.w(", 2\n")
789 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
790 }
791
792 func isBareLiteral(s string) bool {
793 if len(s) == 0 { return false }
794 return s[0] >= '0' && s[0] <= '9'
795 }
796
797 func (e *irEmitter) emitStringCompare(reg string, op ssa.SSAOp, lv, rv string) {
798 ipt := e.intptrType()
799 sty := "{ptr, " | ipt | ", " | ipt | "}"
800 if lv == "null" { lv = "zeroinitializer" }
801 if rv == "null" { rv = "zeroinitializer" }
802 if isBareLiteral(lv) { lv = "zeroinitializer" }
803 if isBareLiteral(rv) { rv = "zeroinitializer" }
804 switch op {
805 case ssa.OpEql:
806 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringEqual(")
807 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
808 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
809 case ssa.OpNeq:
810 tmp := e.nextReg2("sc")
811 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringEqual(")
812 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
813 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
814 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
815 case ssa.OpLss:
816 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
817 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
818 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
819 case ssa.OpGtr:
820 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
821 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
822 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
823 case ssa.OpLeq:
824 tmp := e.nextReg2("sc")
825 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
826 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(")\n")
827 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
828 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
829 case ssa.OpGeq:
830 tmp := e.nextReg2("sc")
831 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
832 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(")\n")
833 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
834 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
835 default:
836 e.w(" ; unsupported string binop\n")
837 }
838 }
839
840 func (e *irEmitter) emitStructCompare(reg string, op ssa.SSAOp, st *types.TCStruct, lt, lv, rv string) {
841 if st == nil {
842 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
843 return
844 }
845 n := st.NumFields()
846 if n == 0 {
847 if op == ssa.OpEql {
848 e.valName[nil] = "true"
849 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
850 } else {
851 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
852 }
853 return
854 }
855 var lastCmp string
856 for i := 0; i < n; i++ {
857 ft := e.llvmType(st.Field(i).Type())
858 lf := e.nextReg2("sf")
859 rf := e.nextReg2("sf")
860 e.w(" ") ; e.w(lf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
861 e.w(" ") ; e.w(rf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
862 cmp := e.nextReg2("sf")
863 if e.isStringLike(st.Field(i).Type()) {
864 sty := e.sliceType()
865 e.w(" ") ; e.w(cmp) ; e.w(" = call i1 @runtime.stringEqual(") ; e.w(sty) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rf) ; e.w(")\n")
866 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
867 } else if len(ft) > 0 && ft[0] == '{' {
868 if innerSt, ok2 := types.SafeUnderlying(st.Field(i).Type()).(*types.TCStruct); ok2 {
869 e.emitStructCompare(cmp, ssa.OpEql, innerSt, ft, lf, rf)
870 } else {
871 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq i32 0, 0 ; nested struct fallback\n")
872 }
873 } else {
874 if ft == "void" {
875 ft = "ptr"
876 }
877 cmpOp := "icmp eq"
878 if ft == "float" || ft == "double" {
879 cmpOp = "fcmp oeq"
880 }
881 e.w(" ") ; e.w(cmp) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(ft) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(rf) ; e.w("\n")
882 }
883 if i == 0 {
884 lastCmp = cmp
885 } else {
886 acc := e.nextReg2("sf")
887 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
888 lastCmp = acc
889 }
890 }
891 if op == ssa.OpNeq {
892 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
893 } else if n == 1 {
894 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
895 } else {
896 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
897 }
898 }
899
900 func (e *irEmitter) emitArrayCompare(reg string, op ssa.SSAOp, ar *types.Array, lt, lv, rv string) {
901 n := int32(ar.Len())
902 if n == 0 {
903 if op == ssa.OpEql {
904 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
905 } else {
906 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
907 }
908 return
909 }
910 et := e.llvmType(ar.Elem())
911 isZeroL := lv == "0" || lv == "zeroinitializer"
912 isZeroR := rv == "0" || rv == "zeroinitializer"
913 var lastCmp string
914 for i := 0; i < n; i++ {
915 var lfr, rfr string
916 if isZeroL {
917 lfr = "0"
918 } else {
919 lfr = e.nextReg2("ae")
920 e.w(" ") ; e.w(lfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
921 }
922 if isZeroR {
923 rfr = "0"
924 } else {
925 rfr = e.nextReg2("ae")
926 e.w(" ") ; e.w(rfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
927 }
928 cmp := e.nextReg2("ae")
929 aeCmpOp := "icmp eq"
930 if et == "float" || et == "double" {
931 aeCmpOp = "fcmp oeq"
932 }
933 e.w(" ") ; e.w(cmp) ; e.w(" = ") ; e.w(aeCmpOp) ; e.w(" ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
934 if i == 0 {
935 lastCmp = cmp
936 } else {
937 acc := e.nextReg2("ae")
938 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
939 lastCmp = acc
940 }
941 }
942 if op == ssa.OpNeq {
943 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
944 } else {
945 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
946 }
947 }
948
949 func parseArrayType(lt string) (int32, string) {
950 if len(lt) < 5 || lt[0] != '[' {
951 return 0, ""
952 }
953 i := 1
954 for i < len(lt) && lt[i] >= '0' && lt[i] <= '9' {
955 i++
956 }
957 n := 0
958 for j := 1; j < i; j++ {
959 n = n*10 + int32(lt[j]-'0')
960 }
961 if i+3 >= len(lt) || lt[i] != ' ' || lt[i+1] != 'x' || lt[i+2] != ' ' {
962 return 0, ""
963 }
964 et := lt[i+3 : len(lt)-1]
965 return n, et
966 }
967
968 func (e *irEmitter) emitArrayCompareByLLVM(reg string, op ssa.SSAOp, lt, lv, rv string) {
969 n, et := parseArrayType(lt)
970 if n == 0 {
971 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
972 return
973 }
974 isZeroL := lv == "0" || lv == "zeroinitializer"
975 isZeroR := rv == "0" || rv == "zeroinitializer"
976 var lastCmp string
977 for i := 0; i < n; i++ {
978 var lfr, rfr string
979 if isZeroL {
980 lfr = "0"
981 } else {
982 lfr = e.nextReg2("ae")
983 e.w(" ") ; e.w(lfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
984 }
985 if isZeroR {
986 rfr = "0"
987 } else {
988 rfr = e.nextReg2("ae")
989 e.w(" ") ; e.w(rfr) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
990 }
991 cmp := e.nextReg2("ae")
992 aeCmpOp := "icmp eq"
993 if et == "float" || et == "double" {
994 aeCmpOp = "fcmp oeq"
995 }
996 e.w(" ") ; e.w(cmp) ; e.w(" = ") ; e.w(aeCmpOp) ; e.w(" ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
997 if i == 0 {
998 lastCmp = cmp
999 } else {
1000 acc := e.nextReg2("ae")
1001 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
1002 lastCmp = acc
1003 }
1004 }
1005 if op == ssa.OpNeq {
1006 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
1007 } else {
1008 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1009 }
1010 }
1011
1012 func (e *irEmitter) emitStructCompareByLLVM(reg string, op ssa.SSAOp, lt, lv, rv string) {
1013 fields := parseStructFields(lt)
1014 if len(fields) == 0 {
1015 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
1016 return
1017 }
1018 var lastCmp string
1019 for i, ft := range fields {
1020 lf := e.nextReg2("sf")
1021 rf := e.nextReg2("sf")
1022 e.w(" ") ; e.w(lf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
1023 e.w(" ") ; e.w(rf) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(irItoa(i)) ; e.w("\n")
1024 cmp := e.nextReg2("sf")
1025 if len(ft) > 0 && ft[0] == '{' {
1026 e.emitStructCompareByLLVM(cmp, ssa.OpEql, ft, lf, rf)
1027 } else if len(ft) > 0 && ft[0] == '[' {
1028 e.emitArrayCompareByLLVM(cmp, ssa.OpEql, ft, lf, rf)
1029 } else {
1030 cmpOp := "icmp eq"
1031 if ft == "float" || ft == "double" {
1032 cmpOp = "fcmp oeq"
1033 }
1034 e.w(" ") ; e.w(cmp) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(ft) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(rf) ; e.w("\n")
1035 }
1036 if i == 0 {
1037 lastCmp = cmp
1038 } else {
1039 acc := e.nextReg2("sf")
1040 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
1041 lastCmp = acc
1042 }
1043 }
1044 if op == ssa.OpNeq {
1045 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
1046 } else {
1047 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
1048 }
1049 }
1050
1051 func (e *irEmitter) llvmBinOp(op ssa.SSAOp, typ syntax.Type) string {
1052 isFloat := false
1053 isSigned := true
1054 if typ != nil {
1055 if b, ok := types.SafeUnderlying(typ).(*types.Basic); ok {
1056 if b.Info()&types.IsFloat != 0 {
1057 isFloat = true
1058 }
1059 if b.Info()&types.IsUnsigned != 0 {
1060 isSigned = false
1061 }
1062 }
1063 }
1064 if isFloat {
1065 switch op {
1066 case ssa.OpAdd:
1067 return "fadd"
1068 case ssa.OpSub:
1069 return "fsub"
1070 case ssa.OpMul:
1071 return "fmul"
1072 case ssa.OpQuo:
1073 return "fdiv"
1074 case ssa.OpEql:
1075 return "fcmp oeq"
1076 case ssa.OpNeq:
1077 return "fcmp une"
1078 case ssa.OpLss:
1079 return "fcmp olt"
1080 case ssa.OpLeq:
1081 return "fcmp ole"
1082 case ssa.OpGtr:
1083 return "fcmp ogt"
1084 case ssa.OpGeq:
1085 return "fcmp oge"
1086 }
1087 return ""
1088 }
1089 switch op {
1090 case ssa.OpAdd:
1091 return "add"
1092 case ssa.OpSub:
1093 return "sub"
1094 case ssa.OpMul:
1095 return "mul"
1096 case ssa.OpQuo:
1097 if isSigned {
1098 return "sdiv"
1099 }
1100 return "udiv"
1101 case ssa.OpRem:
1102 if isSigned {
1103 return "srem"
1104 }
1105 return "urem"
1106 case ssa.OpAnd, ssa.OpLand:
1107 return "and"
1108 case ssa.OpOr, ssa.OpLor:
1109 return "or"
1110 case ssa.OpXor:
1111 return "xor"
1112 case ssa.OpShl:
1113 return "shl"
1114 case ssa.OpShr:
1115 if isSigned {
1116 return "ashr"
1117 }
1118 return "lshr"
1119 case ssa.OpAndNot:
1120 return ""
1121 case ssa.OpEql:
1122 return "icmp eq"
1123 case ssa.OpNeq:
1124 return "icmp ne"
1125 case ssa.OpLss:
1126 if isSigned {
1127 return "icmp slt"
1128 }
1129 return "icmp ult"
1130 case ssa.OpLeq:
1131 if isSigned {
1132 return "icmp sle"
1133 }
1134 return "icmp ule"
1135 case ssa.OpGtr:
1136 if isSigned {
1137 return "icmp sgt"
1138 }
1139 return "icmp ugt"
1140 case ssa.OpGeq:
1141 if isSigned {
1142 return "icmp sge"
1143 }
1144 return "icmp uge"
1145 }
1146 return ""
1147 }
1148
1149 func (e *irEmitter) instrRefsValue(instr ssa.SSAInstruction, v ssa.SSAValue) bool {
1150 switch i := instr.(type) {
1151 case *ssa.SSASlice:
1152 return i.X == v || i.Low == v || i.High == v || i.Max == v
1153 case *ssa.SSAStore:
1154 return i.Val == v || i.Addr == v
1155 case *ssa.SSACall:
1156 if i.Call.Value == v {
1157 return true
1158 }
1159 for _, arg := range i.Call.Args {
1160 if arg == v {
1161 return true
1162 }
1163 }
1164 case *ssa.SSAReturn:
1165 for _, res := range i.Results {
1166 if res == v {
1167 return true
1168 }
1169 }
1170 case *ssa.SSAPhi:
1171 for _, ed := range i.Edges {
1172 if ed == v {
1173 return true
1174 }
1175 }
1176 case *ssa.SSABinOp:
1177 return i.X == v || i.Y == v
1178 case *ssa.SSAUnOp:
1179 return i.X == v
1180 case *ssa.SSAFieldAddr:
1181 return i.X == v
1182 case *ssa.SSAIndexAddr:
1183 return i.X == v || i.Index == v
1184 case *ssa.SSAConvert:
1185 return i.X == v
1186 case *ssa.SSAChangeType:
1187 return i.X == v
1188 case *ssa.SSAMakeInterface:
1189 return i.X == v
1190 case *ssa.SSATypeAssert:
1191 return i.X == v
1192 case *ssa.SSAIf:
1193 return i.Cond == v
1194 case *ssa.SSALookup:
1195 return i.X == v || i.Index == v
1196 }
1197 return false
1198 }
1199
1200 func (e *irEmitter) arrayDerefOnlyUsedBySlice(u *ssa.SSAUnOp) bool {
1201 fn := u.InstrParent()
1202 if fn == nil {
1203 return false
1204 }
1205 hasSliceUse := false
1206 for _, b := range fn.Blocks {
1207 for _, instr := range b.Instrs {
1208 if instr == u {
1209 continue
1210 }
1211 if sl, ok := instr.(*ssa.SSASlice); ok && sl.X == u {
1212 hasSliceUse = true
1213 continue
1214 }
1215 if e.instrRefsValue(instr, u) {
1216 return false
1217 }
1218 }
1219 }
1220 return hasSliceUse
1221 }
1222
1223 func (e *irEmitter) emitUnOp(u *ssa.SSAUnOp) {
1224 reg := e.regName(u)
1225 if u.Op == ssa.OpMul {
1226 loadType := e.llvmType(u.SSAType())
1227 if loadType == "void" {
1228 if at, ok := e.allocTypes[u.X]; ok {
1229 loadType = at
1230 } else if a, ok := u.X.(*ssa.SSAAlloc); ok {
1231 loadType = e.inferAllocTypeFromStores(a)
1232 } else if ia, ok := u.X.(*ssa.SSAIndexAddr); ok {
1233 et := e.llvmType(ia.SSAType())
1234 if p2, ok2 := types.SafeUnderlying(ia.SSAType()).(*types.Pointer); ok2 && p2.Elem() != nil {
1235 et = e.llvmType(p2.Elem())
1236 }
1237 if et == "void" {
1238 et = "i8"
1239 }
1240 loadType = et
1241 } else {
1242 loadType = "ptr"
1243 }
1244 e.allocTypes[u] = loadType
1245 }
1246 if g, ok := u.X.(*ssa.SSAGlobal); ok {
1247 loadType = e.resolveGlobalDeclType(g)
1248 }
1249 if at, ok := e.allocTypes[u.X]; ok && at != "ptr" && at != "void" && at != loadType {
1250 bothScalar := len(loadType) > 0 && loadType[0] == 'i' && len(at) > 0 && at[0] == 'i'
1251 isArrayElem := len(at) > 0 && at[0] == '[' && len(loadType) > 0 && loadType[0] != '{' && loadType != at
1252 bothAgg := len(loadType) > 0 && loadType[0] == '{' && len(at) > 0 && at[0] == '{'
1253 ssaIsScalar := len(loadType) > 0 && (loadType[0] == 'i' || loadType == "float" || loadType == "double") && loadType != "void"
1254 allocIsAgg := len(at) > 0 && at[0] == '{'
1255 ssaIsAgg := len(loadType) > 0 && loadType[0] == '{'
1256 allocIsScalar := len(at) > 0 && (at[0] == 'i' || at == "double" || at == "float")
1257 if !bothScalar && !isArrayElem && !bothAgg && !(ssaIsScalar && allocIsAgg) && !(ssaIsAgg && allocIsScalar) {
1258 loadType = at
1259 e.allocTypes[u] = loadType
1260 }
1261 }
1262 if _, isIA := u.X.(*ssa.SSAIndexAddr); isIA && len(loadType) > 0 && loadType[0] == '[' {
1263 if at, ok2 := e.allocTypes[u.X]; ok2 && at != loadType {
1264 loadType = at
1265 e.allocTypes[u] = loadType
1266 }
1267 }
1268 if len(loadType) > 0 && loadType[0] == '[' && e.arrayDerefOnlyUsedBySlice(u) {
1269 addr := e.operand(u.X)
1270 e.valName[u] = addr
1271 e.allocTypes[u] = loadType
1272 return
1273 }
1274 addr := e.operand(u.X)
1275 e.w(" ")
1276 e.w(reg)
1277 e.w(" = load ")
1278 e.w(loadType)
1279 e.w(", ptr ")
1280 e.w(addr)
1281 e.w("\n")
1282 if loadType == "double" || loadType == "float" {
1283 e.setRegType(u, reg, loadType)
1284 }
1285 return
1286 }
1287 valType := e.llvmType(u.X.SSAType())
1288 resolved := e.resolvedType(u.X, valType)
1289 if resolved != valType {
1290 valType = resolved
1291 }
1292 val := e.operand(u.X)
1293 if u.Op == ssa.OpSub {
1294 isFloat := false
1295 if b, ok := types.SafeUnderlying(u.X.SSAType()).(*types.Basic); ok {
1296 isFloat = b.Info()&types.IsFloat != 0
1297 }
1298 if !isFloat && (valType == "double" || valType == "float") {
1299 isFloat = true
1300 }
1301 if !isFloat && isConstOperand(val) && looksLikeFloat(val) {
1302 isFloat = true
1303 if valType != "float" && valType != "double" {
1304 valType = "double"
1305 }
1306 }
1307 e.w(" ")
1308 e.w(reg)
1309 if isFloat {
1310 e.w(" = fneg ")
1311 e.w(valType)
1312 e.w(" ")
1313 e.w(val)
1314 e.w("\n")
1315 e.setRegType(u, reg, valType)
1316 } else {
1317 e.w(" = sub ")
1318 e.w(valType)
1319 e.w(" 0, ")
1320 e.w(val)
1321 e.w("\n")
1322 }
1323 return
1324 }
1325 if u.Op == ssa.OpNot {
1326 e.w(" ")
1327 e.w(reg)
1328 e.w(" = xor i1 ")
1329 e.w(val)
1330 e.w(", true\n")
1331 e.setRegType(u, reg, "i1")
1332 return
1333 }
1334 if u.Op == ssa.OpXor {
1335 e.w(" ")
1336 e.w(reg)
1337 e.w(" = xor ")
1338 e.w(valType)
1339 e.w(" ")
1340 e.w(val)
1341 e.w(", -1\n")
1342 return
1343 }
1344 if u.Op == ssa.OpArrow {
1345 e.emitChanRecv(u)
1346 return
1347 }
1348 e.w(" ; unsupported unop op=")
1349 e.w(u.Op.String())
1350 e.w("\n")
1351 }
1352