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