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