ir_binop.mx raw
1 package main
2
3 import (
4 "git.smesh.lol/moxie/pkg/mxutil"
5 . "git.smesh.lol/moxie/pkg/types"
6 )
7
8 func (e *irEmitter) emitBinOp(b *SSABinOp) {
9 if b.X == nil || b.X.SSAType() == nil {
10 recov := false
11 if b.X == nil {
12 for _, blk := range e.curFunc.Blocks {
13 for i, inst := range blk.Instrs {
14 if inst == b && i > 0 {
15 if prev, ok := blk.Instrs[i-1].(*SSAUnOp); ok && prev.Op == OpMul {
16 b.X = prev
17 recov = true
18 }
19 }
20 }
21 if recov { break }
22 }
23 }
24 if !recov && b.X != nil {
25 rt2 := e.resolvedType(b.X, "i32")
26 if rt2 != "i32" && rt2 != "" {
27 reg2 := e.regName(b)
28 lv2 := e.operand(b.X)
29 rv2 := e.operand(b.Y)
30 isNullRecov := (b.Op == OpEql || b.Op == OpNeq) && (rv2 == "null" || rv2 == "zeroinitializer" || lv2 == "null" || lv2 == "zeroinitializer")
31 if isNullRecov && len(rt2) > 0 && rt2[0] == '{' {
32 aggVal := lv2
33 if lv2 == "null" || lv2 == "zeroinitializer" { aggVal = rv2 }
34 curType := rt2
35 curVal := aggVal
36 for len(curType) > 0 && curType[0] == '{' {
37 e.nextReg++
38 extReg := "%ne" | irItoa(e.nextReg)
39 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(curType) ; e.w(" ") ; e.w(curVal) ; e.w(", 0\n")
40 curVal = extReg
41 curType = e.structField0Type(curType)
42 }
43 if curType != "ptr" { curType = "ptr" }
44 cmpOp2 := "icmp eq"
45 if b.Op == OpNeq { cmpOp2 = "icmp ne" }
46 e.w(" ") ; e.w(reg2) ; e.w(" = ") ; e.w(cmpOp2) ; e.w(" ") ; e.w(curType) ; e.w(" ") ; e.w(curVal) ; e.w(", null\n")
47 e.setRegType(b, reg2, "i1")
48 return
49 }
50 op2 := e.llvmBinOp(b.Op, nil)
51 e.w(" ") ; e.w(reg2) ; e.w(" = ") ; e.w(op2) ; e.w(" ") ; e.w(rt2) ; e.w(" ") ; e.w(lv2) ; e.w(", ") ; e.w(rv2) ; e.w("\n")
52 e.setRegType(b, reg2, rt2)
53 return
54 }
55 }
56 if !recov {
57 e.emitZeroReg(e.regName(b), b.SSAType())
58 return
59 }
60 }
61 reg := e.regName(b)
62 lt := e.llvmType(b.X.SSAType())
63 if lt == "void" && b.Y != nil {
64 lt = e.llvmType(b.Y.SSAType())
65 }
66 if _, xIsIA := b.X.(*SSAIndexAddr); !xIsIA {
67 if at, ok := e.allocTypes[b.X]; ok && at != "ptr" && at != "void" && at != lt {
68 isScalarToAgg := len(lt) > 0 && (lt[0] == 'i' || lt == "double" || lt == "float") && len(at) > 0 && at[0] == '{'
69 isAggToScalar := len(lt) > 0 && lt[0] == '{' && len(at) > 0 && (at[0] == 'i' || at == "double" || at == "float")
70 if !isScalarToAgg && !isAggToScalar {
71 lt = at
72 }
73 }
74 }
75 lv := e.operand(b.X)
76 rv := e.operand(b.Y)
77 if (b.Op == OpAdd || b.Op == OpOr) && b.X.SSAType() != nil {
78 if sl, ok := SafeUnderlying(b.X.SSAType()).(*Slice); ok {
79 e.emitSliceConcat(reg, sl, lv, rv)
80 return
81 }
82 if e.isStringLike(b.X.SSAType()) {
83 e.emitSliceConcat(reg, NewSlice(Typ[Uint8]), lv, rv)
84 return
85 }
86 }
87 if b.X.SSAType() != nil && e.isStringLike(b.X.SSAType()) && (lt == e.sliceType() || lt == "ptr" || lt == "void") {
88 isActuallyIface := false
89 if at, ok := e.allocTypes[b.X]; ok && at == e.ifaceType() {
90 isActuallyIface = true
91 }
92 rvOK := true
93 if b.Y != nil {
94 rvType := e.llvmType(b.Y.SSAType())
95 rvResolved := e.resolvedType(b.Y, rvType)
96 if load, ok := b.Y.(*SSAUnOp); ok && load.Op == OpMul {
97 if g, ok2 := load.X.(*SSAGlobal); ok2 {
98 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 {
99 rvResolved = gt
100 }
101 }
102 }
103 if e.intBits(rvResolved) > 0 {
104 rvOK = false
105 }
106 }
107 if !isActuallyIface && rvOK {
108 e.emitStringCompare(reg, b.Op, lv, rv)
109 return
110 }
111 }
112 isStringOp := lt == e.sliceType()
113 // Fallback: if RV looks like a string aggregate but LV has a
114 // mismatched type (interface, void), bitcast LV to string type.
115 if !isStringOp && (b.Op == OpEql || b.Op == OpNeq) {
116 rvIsStr := len(rv) > 6 && rv[0] == '{' && rv[2] == 'p' && rv[3] == 't' && rv[4] == 'r'
117 if rvIsStr {
118 sty := e.sliceType()
119 if lt != sty && lt != "void" && len(lt) > 0 && lt[0] == '{' {
120 e.nextReg++
121 cast := "%sbc" | irItoa(e.nextReg)
122 e.w(" ") ; e.w(cast) ; e.w(" = alloca ") ; e.w(sty) ; e.w("\n")
123 e.nextReg++
124 tmp := "%sbc" | irItoa(e.nextReg)
125 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(lt) ; e.w("\n")
126 e.w(" store ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
127 e.nextReg++
128 reloaded := "%sbc" | irItoa(e.nextReg)
129 e.w(" ") ; e.w(reloaded) ; e.w(" = load ") ; e.w(sty) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
130 lv = reloaded
131 }
132 lt = sty
133 isStringOp = true
134 }
135 }
136 if isStringOp {
137 rvOK2 := true
138 if b.Y != nil {
139 if load, ok := b.Y.(*SSAUnOp); ok && load.Op == OpMul {
140 if g, ok2 := load.X.(*SSAGlobal); ok2 {
141 if gt, ok3 := e.globalTypes[e.globalName(g)]; ok3 && e.intBits(gt) > 0 {
142 rvOK2 = false
143 }
144 }
145 }
146 }
147 if rvOK2 {
148 e.emitStringCompare(reg, b.Op, lv, rv)
149 return
150 }
151 }
152 isNullCmp := (b.Op == OpEql || b.Op == OpNeq) && (rv == "null" || rv == "zeroinitializer" || lv == "null" || lv == "zeroinitializer")
153 if isNullCmp && len(lt) > 0 && lt[0] == '{' && lt != "{ptr, ptr}" && lt != e.sliceType() && lt != e.ifaceType() {
154 aggVal := lv
155 if lv == "null" || lv == "zeroinitializer" {
156 aggVal = rv
157 }
158 curType := lt
159 curVal := aggVal
160 for len(curType) > 0 && curType[0] == '{' {
161 e.nextReg++
162 extReg := "%ne" | irItoa(e.nextReg)
163 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(curType) ; e.w(" ") ; e.w(curVal) ; e.w(", 0\n")
164 curVal = extReg
165 curType = e.structField0Type(curType)
166 }
167 if curType != "ptr" {
168 curType = "ptr"
169 }
170 cmpOp := "icmp eq"
171 if b.Op == OpNeq {
172 cmpOp = "icmp ne"
173 }
174 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(curType) ; e.w(" ") ; e.w(curVal) ; e.w(", null\n")
175 return
176 }
177 if isNullCmp && b.X.SSAType() != nil {
178 u := SafeUnderlying(b.X.SSAType())
179 _, isIface := u.(*TCInterface)
180 _, isSlice := u.(*Slice)
181 _, isSig := u.(*Signature)
182 _, isPtr := u.(*Pointer)
183 if !isPtr {
184 if b2, ok2 := u.(*Basic); ok2 && b2.Kind == UnsafePointer {
185 isPtr = true
186 }
187 }
188 _, isMap := u.(*TCMap)
189 _, isChan := u.(*TCChan)
190 if !isIface && !isSlice && !isSig && !isPtr && u == nil && (lt == "{ptr, ptr}" || lt == e.ifaceType() || lt == "{ptr, " | e.intptrType() | "}") {
191 isIface = true
192 }
193 if isSig {
194 e.nextReg++
195 extReg := "%ne" | irItoa(e.nextReg)
196 aggVal := lv
197 if lv == "null" || lv == "zeroinitializer" {
198 aggVal = rv
199 }
200 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 1\n")
201 cmpOp := "icmp eq"
202 if b.Op == OpNeq {
203 cmpOp = "icmp ne"
204 }
205 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
206 return
207 }
208 if (isMap || isChan) && lt == "ptr" {
209 isPtr = true
210 }
211 if isIface || isSlice || ((isMap || isChan) && lt != "ptr") || e.isStringLike(b.X.SSAType()) {
212 e.nextReg++
213 extReg := "%ne" | irItoa(e.nextReg)
214 aggVal := lv
215 if lv == "null" || lv == "zeroinitializer" {
216 aggVal = rv
217 }
218 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(aggVal) ; e.w(", 0\n")
219 cmpOp := "icmp eq"
220 if b.Op == OpNeq {
221 cmpOp = "icmp ne"
222 }
223 if lt == e.ifaceType() {
224 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" " | e.intptrType() | " ") ; e.w(extReg) ; e.w(", 0\n")
225 } else {
226 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", null\n")
227 }
228 return
229 }
230 if isPtr {
231 cmpOp := "icmp eq"
232 if b.Op == OpNeq {
233 cmpOp = "icmp ne"
234 }
235 ptrVal := lv
236 if lv == "null" || lv == "zeroinitializer" {
237 ptrVal = rv
238 }
239 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(ptrVal) ; e.w(", null\n")
240 return
241 }
242 }
243 if (b.Op == OpEql || b.Op == OpNeq) && b.X.SSAType() != nil {
244 if st, ok := SafeUnderlying(b.X.SSAType()).(*TCStruct); ok && len(lt) > 0 && lt[0] == '{' {
245 slt := e.llvmStructType(st)
246 e.emitStructCompare(reg, b.Op, st, slt, lv, rv)
247 return
248 }
249 if ar, ok := SafeUnderlying(b.X.SSAType()).(*Array); ok && len(lt) > 0 && lt[0] == '[' {
250 e.emitArrayCompare(reg, b.Op, ar, lt, lv, rv)
251 return
252 }
253 u2 := SafeUnderlying(b.X.SSAType())
254 _, isSig2 := u2.(*Signature)
255 _, isIfce2 := u2.(*TCInterface)
256 if !isSig2 && !isIfce2 && u2 == nil && (lt == "{ptr, ptr}" || lt == e.ifaceType()) {
257 isIfce2 = true
258 }
259 if !isSig2 && !isIfce2 && b.Y != nil && b.Y.SSAType() != nil {
260 u2y := SafeUnderlying(b.Y.SSAType())
261 _, isIfce2y := u2y.(*TCInterface)
262 if isIfce2y {
263 isIfce2 = true
264 }
265 }
266 if !isSig2 && !isIfce2 && lt == "ptr" && b.Y != nil && b.Y.SSAType() != nil {
267 rt2c := e.llvmType(b.Y.SSAType())
268 if rt2c == "{ptr, ptr}" || rt2c == e.ifaceType() {
269 isIfce2 = true
270 }
271 }
272 if isSig2 || isIfce2 {
273 nilField := "0"
274 if isSig2 {
275 nilField = "1"
276 }
277 rt2 := "ptr"
278 if b.Y != nil && b.Y.SSAType() != nil {
279 rt2 = e.llvmType(b.Y.SSAType())
280 }
281 if at, ok := e.allocTypes[b.Y]; ok && at != "" {
282 rt2 = at
283 }
284 if (lt == "{ptr, ptr}" || lt == e.ifaceType()) && rt2 == "ptr" {
285 e.nextReg++
286 extReg := "%fc" | irItoa(e.nextReg)
287 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
288 cmpOp3 := "icmp eq"
289 if b.Op == OpNeq { cmpOp3 = "icmp ne" }
290 ipt := e.intptrType()
291 if lt == e.ifaceType() && nilField == "0" {
292 e.nextReg++
293 p2i := "%fc" | irItoa(e.nextReg)
294 e.w(" ") ; e.w(p2i) ; e.w(" = ptrtoint ptr ") ; e.w(rv) ; e.w(" to " | ipt | "\n")
295 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp3) ; e.w(" " | ipt | " ") ; e.w(extReg) ; e.w(", ") ; e.w(p2i) ; e.w("\n")
296 } else {
297 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp3) ; e.w(" ptr ") ; e.w(extReg) ; e.w(", ") ; e.w(rv) ; e.w("\n")
298 }
299 return
300 }
301 if lt == "ptr" && (rt2 == "{ptr, ptr}" || rt2 == e.ifaceType()) {
302 e.nextReg++
303 extReg := "%fc" | irItoa(e.nextReg)
304 e.w(" ") ; e.w(extReg) ; e.w(" = extractvalue ") ; e.w(rt2) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(nilField) ; e.w("\n")
305 cmpOp4 := "icmp eq"
306 if b.Op == OpNeq { cmpOp4 = "icmp ne" }
307 if rt2 == e.ifaceType() && nilField == "0" {
308 ipt2 := e.intptrType()
309 e.nextReg++
310 p2i := "%fc" | irItoa(e.nextReg)
311 e.w(" ") ; e.w(p2i) ; e.w(" = ptrtoint ptr ") ; e.w(lv) ; e.w(" to " | ipt2 | "\n")
312 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp4) ; e.w(" " | ipt2 | " ") ; e.w(p2i) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
313 } else {
314 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp4) ; e.w(" ptr ") ; e.w(lv) ; e.w(", ") ; e.w(extReg) ; e.w("\n")
315 }
316 return
317 }
318 if (lt == "{ptr, ptr}" || lt == e.ifaceType()) && rt2 != "{ptr, ptr}" && rt2 != e.ifaceType() && rt2 != "ptr" {
319 sty := e.sliceType()
320 e.nextReg++
321 dp := "%fc" | irItoa(e.nextReg)
322 e.w(" ") ; e.w(dp) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
323 if rt2 == sty {
324 baseID := e.nextReg
325 nullLbl := "fc.null" | irItoa(baseID)
326 cmpLbl := "fc.cmp" | irItoa(baseID)
327 mergeLbl := "fc.merge" | irItoa(baseID)
328 e.nextReg++
329 nullChk := "%fc" | irItoa(e.nextReg)
330 e.w(" ") ; e.w(nullChk) ; e.w(" = icmp eq ptr ") ; e.w(dp) ; e.w(", null\n")
331 e.w(" br i1 ") ; e.w(nullChk) ; e.w(", label %") ; e.w(nullLbl) ; e.w(", label %") ; e.w(cmpLbl) ; e.w("\n")
332 e.w(nullLbl) ; e.w(":\n")
333 e.w(" br label %") ; e.w(mergeLbl) ; e.w("\n")
334 e.w(cmpLbl) ; e.w(":\n")
335 e.nextReg++
336 ldp := "%fc" | irItoa(e.nextReg)
337 e.w(" ") ; e.w(ldp) ; e.w(" = load ") ; e.w(sty) ; e.w(", ptr ") ; e.w(dp) ; e.w("\n")
338 e.nextReg++
339 eqR := "%fc" | irItoa(e.nextReg)
340 e.w(" ") ; e.w(eqR) ; e.w(" = call i1 @runtime.stringEqual(") ; e.w(sty) ; e.w(" ") ; e.w(ldp) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ptr null)\n")
341 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
342 cmpResult := eqR
343 if b.Op == OpNeq {
344 e.nextReg++
345 cmpResult = "%fc" | irItoa(e.nextReg)
346 e.w(" ") ; e.w(cmpResult) ; e.w(" = xor i1 ") ; e.w(eqR) ; e.w(", true\n")
347 }
348 e.w(" br label %") ; e.w(mergeLbl) ; e.w("\n")
349 e.w(mergeLbl) ; e.w(":\n")
350 nullVal := "false"
351 if b.Op == OpNeq {
352 nullVal = "true"
353 }
354 e.w(" ") ; e.w(reg) ; e.w(" = phi i1 [") ; e.w(nullVal) ; e.w(", %") ; e.w(nullLbl) ; e.w("], [") ; e.w(cmpResult) ; e.w(", %") ; e.w(cmpLbl) ; e.w("]\n")
355 if blk := b.InstrBlock(); blk != nil {
356 e.blockExitLabel[blk.Index] = "%" | mergeLbl
357 }
358 return
359 }
360 e.nextReg++
361 tmp := "%fc" | irItoa(e.nextReg)
362 e.w(" ") ; e.w(tmp) ; e.w(" = alloca ") ; e.w(rt2) ; e.w("\n")
363 e.w(" store ") ; e.w(rt2) ; e.w(" ") ; e.w(rv) ; e.w(", ptr ") ; e.w(tmp) ; e.w("\n")
364 cmpOp5 := "icmp eq"
365 if b.Op == OpNeq { cmpOp5 = "icmp ne" }
366 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(cmpOp5) ; e.w(" ptr ") ; e.w(dp) ; e.w(", ") ; e.w(tmp) ; e.w("\n")
367 return
368 }
369 e.nextReg++
370 pA := "%fc" | irItoa(e.nextReg)
371 e.nextReg++
372 pB := "%fc" | irItoa(e.nextReg)
373 e.nextReg++
374 qA := "%fc" | irItoa(e.nextReg)
375 e.nextReg++
376 qB := "%fc" | irItoa(e.nextReg)
377 e.nextReg++
378 cA := "%fc" | irItoa(e.nextReg)
379 e.nextReg++
380 cB := "%fc" | irItoa(e.nextReg)
381 e.w(" ") ; e.w(pA) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
382 e.w(" ") ; e.w(pB) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
383 e.w(" ") ; e.w(qA) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
384 e.w(" ") ; e.w(qB) ; e.w(" = extractvalue ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
385 cmpOp := "icmp eq"
386 combOp := "and"
387 if b.Op == OpNeq {
388 cmpOp = "icmp ne"
389 combOp = "or"
390 }
391 f0type := "ptr"
392 if lt == e.ifaceType() {
393 f0type = e.intptrType()
394 }
395 e.w(" ") ; e.w(cA) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ") ; e.w(f0type) ; e.w(" ") ; e.w(pA) ; e.w(", ") ; e.w(pB) ; e.w("\n")
396 e.w(" ") ; e.w(cB) ; e.w(" = ") ; e.w(cmpOp) ; e.w(" ptr ") ; e.w(qA) ; e.w(", ") ; e.w(qB) ; e.w("\n")
397 e.w(" ") ; e.w(reg) ; e.w(" = ") ; e.w(combOp) ; e.w(" i1 ") ; e.w(cA) ; e.w(", ") ; e.w(cB) ; e.w("\n")
398 return
399 }
400 }
401 if b.Op == OpAndNot {
402 rt3 := ""
403 if b.Y != nil && b.Y.SSAType() != nil {
404 rt3 = e.llvmType(b.Y.SSAType())
405 rt3 = e.resolvedType(b.Y, rt3)
406 }
407 lt = e.resolvedType(b.X, lt)
408 if rt3 != "" && rt3 != lt && e.intBits(lt) > 0 && e.intBits(rt3) > 0 {
409 rv = e.coerceInt(rv, rt3, lt)
410 }
411 e.nextReg++
412 notReg := "%an" | irItoa(e.nextReg)
413 allOnes := "-1"
414 e.w(" ") ; e.w(notReg) ; e.w(" = xor ") ; e.w(lt) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(allOnes) ; e.w("\n")
415 e.w(" ") ; e.w(reg) ; e.w(" = and ") ; e.w(lt) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(notReg) ; e.w("\n")
416 e.setRegType(b, reg, lt)
417 return
418 }
419 if b.Y == nil || b.Y.SSAType() == nil {
420 e.emitZeroReg(e.regName(b), b.SSAType())
421 return
422 }
423 rt := e.llvmType(b.Y.SSAType())
424 atl0 := e.resolvedType(b.X, lt)
425 if atl0 != lt {
426 lt = atl0
427 }
428 atr0 := e.resolvedType(b.Y, rt)
429 if atr0 != rt {
430 rt = atr0
431 }
432 coerced := false
433 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
434 isCmp := b.Op == OpEql || b.Op == OpNeq || b.Op == OpLss || b.Op == OpGtr || b.Op == OpLeq || b.Op == OpGeq
435 resType := e.llvmType(b.SSAType())
436 if !isCmp && e.intBits(resType) > 0 {
437 if lt != resType {
438 lv = e.coerceInt(lv, lt, resType)
439 lt = resType
440 }
441 if rt != resType {
442 rv = e.coerceInt(rv, rt, resType)
443 }
444 } else if e.intBits(lt) > e.intBits(rt) {
445 rv = e.coerceInt(rv, rt, lt)
446 } else {
447 lv = e.coerceInt(lv, lt, rt)
448 lt = rt
449 }
450 coerced = true
451 }
452 if !coerced && lt == rt {
453 atl := e.resolvedType(b.X, lt)
454 if atl != lt {
455 lt = atl
456 }
457 if b.Y != nil {
458 atr := e.resolvedType(b.Y, rt)
459 if atr != rt {
460 rt = atr
461 }
462 }
463 if lt != rt && e.intBits(lt) > 0 && e.intBits(rt) > 0 {
464 if e.intBits(lt) > e.intBits(rt) {
465 rv = e.coerceInt(rv, rt, lt)
466 rt = lt
467 } else if e.intBits(rt) > e.intBits(lt) {
468 lv = e.coerceInt(lv, lt, rt)
469 lt = rt
470 }
471 }
472 }
473 resultIsInt := e.intBits(e.llvmType(b.SSAType())) > 0
474 isLF := lt == "double" || lt == "float"
475 isRF := rt == "double" || rt == "float"
476 if !isRF && isConstOperand(rv) && looksLikeFloat(rv) {
477 if resultIsInt {
478 if iv, ok := floatLitToInt(rv); ok {
479 rv = irItoa64(iv)
480 }
481 } else {
482 isRF = true
483 rt = "double"
484 }
485 }
486 if !isLF && isConstOperand(lv) && looksLikeFloat(lv) {
487 if resultIsInt {
488 if iv, ok := floatLitToInt(lv); ok {
489 lv = irItoa64(iv)
490 }
491 } else {
492 isLF = true
493 lt = "double"
494 }
495 }
496 if isLF && isRF {
497 ssaLT := e.llvmType(b.X.SSAType())
498 ssaRT := ""
499 if b.Y != nil && b.Y.SSAType() != nil {
500 ssaRT = e.llvmType(b.Y.SSAType())
501 }
502 if !isConstOperand(lv) && e.intBits(ssaLT) > 0 {
503 _, hasRT := e.regTypes[lv]
504 if !hasRT {
505 lv = e.intToFloat(lv, ssaLT, lt)
506 }
507 }
508 if !isConstOperand(rv) && e.intBits(ssaRT) > 0 {
509 _, hasRT := e.regTypes[rv]
510 if !hasRT {
511 rv = e.intToFloat(rv, ssaRT, rt)
512 }
513 }
514 } else if !isLF && isRF && e.intBits(lt) > 0 {
515 if resultIsInt {
516 demoted := false
517 if yc, ok := b.Y.(*SSAConst); ok {
518 if cf, ok2 := yc.val.(*ConstFloat); ok2 {
519 lit := cf.Lit
520 if lit == "" {
521 lit = cf.String()
522 }
523 if iv, ok3 := floatLitToInt(lit); ok3 {
524 rv = irItoa64(iv)
525 rt = lt
526 isRF = false
527 demoted = true
528 }
529 }
530 }
531 if !demoted {
532 if isConstOperand(lv) {
533 lv = ensureFloatLit(lv)
534 } else {
535 lv = e.intToFloat(lv, lt, rt)
536 }
537 lt = rt
538 }
539 } else {
540 if isConstOperand(lv) {
541 lv = ensureFloatLit(lv)
542 } else {
543 lv = e.intToFloat(lv, lt, rt)
544 }
545 lt = rt
546 }
547 } else if isLF && !isRF && e.intBits(rt) > 0 {
548 if resultIsInt {
549 if xc, ok := b.X.(*SSAConst); ok {
550 if cf, ok2 := xc.val.(*ConstFloat); ok2 {
551 lit := cf.Lit
552 if lit == "" {
553 lit = cf.String()
554 }
555 if iv, ok3 := floatLitToInt(lit); ok3 {
556 lv = irItoa64(iv)
557 lt = rt
558 isLF = false
559 }
560 }
561 }
562 if isLF {
563 if isConstOperand(rv) {
564 rv = ensureFloatLit(rv)
565 } else {
566 rv = e.intToFloat(rv, rt, lt)
567 }
568 rt = lt
569 }
570 } else {
571 if isConstOperand(rv) {
572 rv = ensureFloatLit(rv)
573 } else {
574 rv = e.intToFloat(rv, rt, lt)
575 }
576 rt = lt
577 }
578 }
579 if lt == "float" && rt == "double" {
580 e.nextReg++
581 tmp := "%fext" | irItoa(e.nextReg)
582 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(lv) ; e.w(" to double\n")
583 lv = tmp
584 lt = "double"
585 } else if lt == "double" && rt == "float" {
586 e.nextReg++
587 tmp := "%fext" | irItoa(e.nextReg)
588 e.w(" ") ; e.w(tmp) ; e.w(" = fpext float ") ; e.w(rv) ; e.w(" to double\n")
589 rv = tmp
590 rt = "double"
591 }
592 op := e.llvmBinOp(b.Op, b.X.SSAType())
593 if op == "" {
594 e.w(" ; unsupported binop\n")
595 return
596 }
597 isCmpOp := b.Op == OpEql || b.Op == OpNeq || b.Op == OpLss || b.Op == OpGtr || b.Op == OpLeq || b.Op == OpGeq
598 if lt == "double" || lt == "float" {
599 rv = ensureFloatLit(rv)
600 lv = ensureFloatLit(lv)
601 op = e.floatBinOp(b.Op)
602 if !isCmpOp {
603 e.setRegType(b, reg, lt)
604 }
605 } else if !isCmpOp {
606 ssaLT := e.llvmType(b.X.SSAType())
607 if ssaLT != lt {
608 e.setRegType(b, reg, lt)
609 }
610 }
611 if len(lt) > 0 && lt[0] == '[' && (b.Op == OpEql || b.Op == OpNeq) {
612 e.emitArrayCompareByLLVM(reg, b.Op, lt, lv, rv)
613 return
614 }
615 if lt == "ptr" && !isCmpOp {
616 e.nextReg++
617 pi := "%pi" | irItoa(e.nextReg)
618 e.w(" ") ; e.w(pi) ; e.w(" = ptrtoint ptr ") ; e.w(lv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
619 e.nextReg++
620 ri := "%pi" | irItoa(e.nextReg)
621 rvCoerced := rv
622 if rv != "0" && rv != "1" && rv != "-1" {
623 e.w(" ") ; e.w(ri) ; e.w(" = ptrtoint ptr ") ; e.w(rv) ; e.w(" to ") ; e.w(e.intptrType()) ; e.w("\n")
624 rvCoerced = ri
625 }
626 e.nextReg++
627 ai := "%pi" | irItoa(e.nextReg)
628 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")
629 e.w(" ") ; e.w(reg) ; e.w(" = inttoptr ") ; e.w(e.intptrType()) ; e.w(" ") ; e.w(ai) ; e.w(" to ptr\n")
630 return
631 }
632 e.w(" ")
633 e.w(reg)
634 e.w(" = ")
635 e.w(op)
636 e.w(" ")
637 e.w(lt)
638 e.w(" ")
639 e.w(lv)
640 e.w(", ")
641 e.w(rv)
642 e.w("\n")
643 }
644
645 func (e *irEmitter) emitSliceConcat(reg string, sl *Slice, lv, rv string) {
646 ipt := e.intptrType()
647 sty := "{ptr, " | ipt | ", " | ipt | "}"
648 if isBareLiteral(lv) { lv = "zeroinitializer" }
649 if isBareLiteral(rv) { rv = "zeroinitializer" }
650 elemType := e.llvmType(sl.Elem)
651 xPtr := e.nextReg2("cc")
652 e.w(" ") ; e.w(xPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 0\n")
653 xLen := e.nextReg2("cc")
654 e.w(" ") ; e.w(xLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", 1\n")
655 yPtr := e.nextReg2("cc")
656 e.w(" ") ; e.w(yPtr) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 0\n")
657 yLen := e.nextReg2("cc")
658 e.w(" ") ; e.w(yLen) ; e.w(" = extractvalue ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", 1\n")
659 elemSz := e.nextReg2("cc")
660 e.w(" ") ; e.w(elemSz)
661 e.w(" = ptrtoint ptr getelementptr (") ; e.w(elemType)
662 e.w(", ptr null, i32 1) to ") ; e.w(ipt) ; e.w("\n")
663 retTy := "{ptr, " | ipt | ", " | ipt | "}"
664 result := e.nextReg2("cc")
665 e.w(" ") ; e.w(result)
666 e.w(" = call ") ; e.w(retTy) ; e.w(" @runtime.sliceAppend(ptr ")
667 e.w(xPtr) ; e.w(", ptr ") ; e.w(yPtr)
668 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
669 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(xLen)
670 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(yLen)
671 e.w(", ") ; e.w(ipt) ; e.w(" ") ; e.w(elemSz)
672 e.w(", ptr null)\n")
673 newPtr := e.nextReg2("cc")
674 e.w(" ") ; e.w(newPtr) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 0\n")
675 e.scopeTrackAlloc(newPtr)
676 newLen := e.nextReg2("cc")
677 e.w(" ") ; e.w(newLen) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 1\n")
678 newCap := e.nextReg2("cc")
679 e.w(" ") ; e.w(newCap) ; e.w(" = extractvalue ") ; e.w(retTy) ; e.w(" ") ; e.w(result) ; e.w(", 2\n")
680 s1 := e.nextReg2("cc")
681 e.w(" ") ; e.w(s1) ; e.w(" = insertvalue ") ; e.w(sty) ; e.w(" undef, ptr ") ; e.w(newPtr) ; e.w(", 0\n")
682 s2 := e.nextReg2("cc")
683 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")
684 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")
685 e.declareRuntime("runtime.sliceAppend", retTy, "ptr, ptr, " | ipt | ", " | ipt | ", " | ipt | ", " | ipt)
686 }
687
688 func (e *irEmitter) emitStringCompare(reg string, op SSAOp, lv, rv string) {
689 ipt := e.intptrType()
690 sty := "{ptr, " | ipt | ", " | ipt | "}"
691 if lv == "null" { lv = "zeroinitializer" }
692 if rv == "null" { rv = "zeroinitializer" }
693 if isBareLiteral(lv) { lv = "zeroinitializer" }
694 if isBareLiteral(rv) { rv = "zeroinitializer" }
695 switch op {
696 case OpEql:
697 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringEqual(")
698 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ptr null)\n")
699 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
700 case OpNeq:
701 tmp := e.nextReg2("sc")
702 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringEqual(")
703 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ptr null)\n")
704 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
705 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
706 case OpLss:
707 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
708 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ptr null)\n")
709 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
710 case OpGtr:
711 e.w(" ") ; e.w(reg) ; e.w(" = call i1 @runtime.stringLess(")
712 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ptr null)\n")
713 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
714 case OpLeq:
715 tmp := e.nextReg2("sc")
716 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
717 e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ptr null)\n")
718 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
719 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
720 case OpGeq:
721 tmp := e.nextReg2("sc")
722 e.w(" ") ; e.w(tmp) ; e.w(" = call i1 @runtime.stringLess(")
723 e.w(sty) ; e.w(" ") ; e.w(lv) ; e.w(", ") ; e.w(sty) ; e.w(" ") ; e.w(rv) ; e.w(", ptr null)\n")
724 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(tmp) ; e.w(", -1\n")
725 e.declareRuntime("runtime.stringLess", "i1", sty | ", " | sty)
726 case OpLor:
727 e.w(" ") ; e.w(reg) ; e.w(" = or i1 ") ; e.w(lv) ; e.w(", ") ; e.w(rv) ; e.w("\n")
728 case OpLand:
729 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lv) ; e.w(", ") ; e.w(rv) ; e.w("\n")
730 default:
731 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i1 ") ; e.w(lv) ; e.w(", ") ; e.w(rv) ; e.w("\n")
732 }
733 }
734
735 func (e *irEmitter) emitStructCompare(reg string, op SSAOp, st *TCStruct, lt, lv, rv string) {
736 if st == nil {
737 mxutil.WriteStr(2, "BUG: emitStructCompare called with nil TCStruct\n")
738 if op == OpEql {
739 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
740 } else {
741 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
742 }
743 return
744 }
745 n := st.NumFields()
746 if n == 0 {
747 if op == OpEql {
748 e.valName[nil] = "true"
749 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
750 } else {
751 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
752 }
753 return
754 }
755 var lastCmp string
756 for i := 0; i < n; i++ {
757 ft := e.llvmType(st.Field(i).Typ)
758 lf := e.nextReg2("sf")
759 rf := e.nextReg2("sf")
760 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")
761 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")
762 cmp := e.nextReg2("sf")
763 if e.isStringLike(st.Field(i).Typ) {
764 sty := e.sliceType()
765 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(", ptr null)\n")
766 e.declareRuntime("runtime.stringEqual", "i1", sty | ", " | sty)
767 } else if subst, ok := SafeUnderlying(st.Field(i).Typ).(*TCStruct); ok && len(ft) > 0 && ft[0] == '{' {
768 e.emitStructCompare(cmp, OpEql, subst, ft, lf, rf)
769 } else if subarr, ok2 := SafeUnderlying(st.Field(i).Typ).(*Array); ok2 && len(ft) > 0 && ft[0] == '[' {
770 e.emitArrayCompare(cmp, OpEql, subarr, ft, lf, rf)
771 } else {
772 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(ft) ; e.w(" ") ; e.w(lf) ; e.w(", ") ; e.w(rf) ; e.w("\n")
773 }
774 if i == 0 {
775 lastCmp = cmp
776 } else {
777 acc := e.nextReg2("sf")
778 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
779 lastCmp = acc
780 }
781 }
782 if op == OpNeq {
783 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
784 } else if n == 1 {
785 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
786 } else {
787 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
788 }
789 }
790
791 func (e *irEmitter) emitArrayCompare(reg string, op SSAOp, ar *Array, lt, lv, rv string) {
792 n := int32(ar.Len)
793 if n == 0 {
794 if op == OpEql {
795 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
796 } else {
797 e.w(" ") ; e.w(reg) ; e.w(" = icmp ne i32 0, 0\n")
798 }
799 return
800 }
801 et := e.llvmType(ar.Elem)
802 isZeroL := lv == "0" || lv == "zeroinitializer"
803 isZeroR := rv == "0" || rv == "zeroinitializer"
804 var lastCmp string
805 for i := 0; i < n; i++ {
806 var lfr, rfr string
807 if isZeroL {
808 lfr = "0"
809 } else {
810 lfr = e.nextReg2("ae")
811 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")
812 }
813 if isZeroR {
814 rfr = "0"
815 } else {
816 rfr = e.nextReg2("ae")
817 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")
818 }
819 cmp := e.nextReg2("ae")
820 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
821 if i == 0 {
822 lastCmp = cmp
823 } else {
824 acc := e.nextReg2("ae")
825 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
826 lastCmp = acc
827 }
828 }
829 if op == OpNeq {
830 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
831 } else {
832 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
833 }
834 }
835
836 func (e *irEmitter) emitArrayCompareByLLVM(reg string, op SSAOp, lt, lv, rv string) {
837 n, et := parseArrayType(lt)
838 if n == 0 {
839 e.w(" ") ; e.w(reg) ; e.w(" = icmp eq i32 0, 0\n")
840 return
841 }
842 isZeroL := lv == "0" || lv == "zeroinitializer"
843 isZeroR := rv == "0" || rv == "zeroinitializer"
844 var lastCmp string
845 for i := 0; i < n; i++ {
846 var lfr, rfr string
847 if isZeroL {
848 lfr = "0"
849 } else {
850 lfr = e.nextReg2("ae")
851 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")
852 }
853 if isZeroR {
854 rfr = "0"
855 } else {
856 rfr = e.nextReg2("ae")
857 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")
858 }
859 cmp := e.nextReg2("ae")
860 e.w(" ") ; e.w(cmp) ; e.w(" = icmp eq ") ; e.w(et) ; e.w(" ") ; e.w(lfr) ; e.w(", ") ; e.w(rfr) ; e.w("\n")
861 if i == 0 {
862 lastCmp = cmp
863 } else {
864 acc := e.nextReg2("ae")
865 e.w(" ") ; e.w(acc) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", ") ; e.w(cmp) ; e.w("\n")
866 lastCmp = acc
867 }
868 }
869 if op == OpNeq {
870 e.w(" ") ; e.w(reg) ; e.w(" = xor i1 ") ; e.w(lastCmp) ; e.w(", -1\n")
871 } else {
872 e.w(" ") ; e.w(reg) ; e.w(" = and i1 ") ; e.w(lastCmp) ; e.w(", true\n")
873 }
874 }
875
876 func (e *irEmitter) llvmBinOp(op SSAOp, typ Type) (s string) {
877 isFloat := false
878 isSigned := true
879 if typ != nil {
880 if b, ok := SafeUnderlying(typ).(*Basic); ok {
881 if b.Info&IsFloat != 0 {
882 isFloat = true
883 }
884 if b.Info&IsUnsigned != 0 {
885 isSigned = false
886 }
887 }
888 }
889 if isFloat {
890 switch op {
891 case OpAdd:
892 return "fadd"
893 case OpSub:
894 return "fsub"
895 case OpMul:
896 return "fmul"
897 case OpQuo:
898 return "fdiv"
899 case OpEql:
900 return "fcmp oeq"
901 case OpNeq:
902 return "fcmp une"
903 case OpLss:
904 return "fcmp olt"
905 case OpLeq:
906 return "fcmp ole"
907 case OpGtr:
908 return "fcmp ogt"
909 case OpGeq:
910 return "fcmp oge"
911 }
912 return ""
913 }
914 switch op {
915 case OpAdd:
916 return "add"
917 case OpSub:
918 return "sub"
919 case OpMul:
920 return "mul"
921 case OpQuo:
922 if isSigned {
923 return "sdiv"
924 }
925 return "udiv"
926 case OpRem:
927 if isSigned {
928 return "srem"
929 }
930 return "urem"
931 case OpAnd, OpLand:
932 return "and"
933 case OpOr, OpLor:
934 return "or"
935 case OpXor:
936 return "xor"
937 case OpShl:
938 return "shl"
939 case OpShr:
940 if isSigned {
941 return "ashr"
942 }
943 return "lshr"
944 case OpAndNot:
945 return ""
946 case OpEql:
947 return "icmp eq"
948 case OpNeq:
949 return "icmp ne"
950 case OpLss:
951 if isSigned {
952 return "icmp slt"
953 }
954 return "icmp ult"
955 case OpLeq:
956 if isSigned {
957 return "icmp sle"
958 }
959 return "icmp ule"
960 case OpGtr:
961 if isSigned {
962 return "icmp sgt"
963 }
964 return "icmp ugt"
965 case OpGeq:
966 if isSigned {
967 return "icmp sge"
968 }
969 return "icmp uge"
970 }
971 return ""
972 }
973