Example #1
0
func (mach X86) binaryIntCompareOp(code gen.RegCoder, cond uint8, a, b values.Operand) (result values.Operand) {
	result = values.ConditionFlagsOperand(values.Condition(cond))

	targetReg, _, own := mach.opBorrowMaybeResultReg(code, a, false)
	if own {
		defer code.FreeReg(a.Type, targetReg)
	}

	if b.Storage == values.VarMem {
		Cmp.opFromStack(code, a.Type, targetReg, b.VarMemOffset())
		return
	}

	var sourceReg regs.R

	if b.Storage.IsReg() {
		sourceReg = b.Reg()
	} else {
		if b.Storage == values.Imm {
			if value := b.ImmValue(); value >= -0x80000000 && value < 0x80000000 {
				Cmp.opImm(code, a.Type, targetReg, int32(value))
				return
			}
		}
		sourceReg = regScratch
		mach.OpMove(code, sourceReg, b, false)
	}

	Cmp.opFromReg(code, a.Type, targetReg, sourceReg)
	code.Consumed(b)
	return
}
Example #2
0
File: x86.go Project: tsavola/wag
func (mach X86) OpSelect(code gen.RegCoder, a, b, condOperand values.Operand) values.Operand {
	defer code.Consumed(condOperand)

	var cond values.Condition

	switch condOperand.Storage {
	case values.VarMem:
		Cmp.opImmToStack(code, types.I32, condOperand.VarMemOffset(), 0)
		cond = values.Ne

	case values.VarReg, values.TempReg:
		reg := condOperand.Reg()
		Test.opFromReg(code, types.I32, reg, reg)
		cond = values.Ne

	case values.Stack:
		mach.OpAddImmToStackPtr(code, 8) // do before cmp to avoid overwriting flags
		Cmp.opImmToStack(code, types.I32, -8, 0)
		cond = values.Ne

	case values.ConditionFlags:
		cond = condOperand.Condition()

	case values.Imm:
		if condOperand.ImmValue() != 0 {
			code.Consumed(b)
			return a
		} else {
			code.Consumed(a)
			return b
		}

	default:
		panic(condOperand)
	}

	t := a.Type
	targetReg, _ := mach.opMaybeResultReg(code, b, true)

	switch t.Category() {
	case types.Int:
		cmov := conditionInsns[cond].cmov

		switch a.Storage {
		case values.VarMem:
			cmov.opFromStack(code, t, targetReg, a.VarMemOffset())

		default:
			aReg, _, own := mach.opBorrowMaybeScratchReg(code, a, true)
			if own {
				defer code.FreeReg(t, aReg)
			}

			cmov.opFromReg(code, t, targetReg, aReg)
		}

	case types.Float:
		var moveIt links.L
		var end links.L

		cond = values.InvertedConditions[cond]
		notCondJump := conditionInsns[cond].jcc

		switch {
		case cond >= values.MinUnorderedOrCondition:
			Jp.rel8.opStub(code) // move it if unordered
			moveIt.AddSite(code.Len())

			notCondJump.rel8.opStub(code) // break if not cond
			end.AddSite(code.Len())

		case cond >= values.MinOrderedAndCondition:
			Jp.rel8.opStub(code) // break if unordered
			end.AddSite(code.Len())

			notCondJump.rel8.opStub(code) // break if not cond
			end.AddSite(code.Len())

		default:
			notCondJump.rel8.opStub(code) // break if not cond
			end.AddSite(code.Len())
		}

		moveIt.Addr = code.Len()
		mach.updateBranches8(code, &moveIt)

		mach.OpMove(code, targetReg, a, false)

		end.Addr = code.Len()
		mach.updateBranches8(code, &end)

	default:
		panic(t)
	}

	// cmov zero-extends the target unconditionally
	return values.TempRegOperand(t, targetReg, true)
}
Example #3
0
File: x86.go Project: tsavola/wag
// OpMove must not update CPU's condition flags if preserveFlags is set.
//
// X86 implementation note: must not blindly rely on regScratch or regResult in
// this function because we may be moving to one of them.
func (mach X86) OpMove(code gen.Coder, targetReg regs.R, x values.Operand, preserveFlags bool) (zeroExt bool) {
	switch x.Type.Category() {
	case types.Int:
		switch x.Storage {
		case values.Imm:
			if value := x.ImmValue(); value == 0 && !preserveFlags {
				Xor.opFromReg(code, types.I32, targetReg, targetReg)
			} else {
				MovImm64.op(code, x.Type, targetReg, value)
			}
			zeroExt = true

		case values.VarMem:
			Mov.opFromStack(code, x.Type, targetReg, x.VarMemOffset())
			zeroExt = true

		case values.VarReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				Mov.opFromReg(code, x.Type, targetReg, sourceReg)
				zeroExt = true
			}

		case values.TempReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				Mov.opFromReg(code, x.Type, targetReg, sourceReg)
				zeroExt = true
			} else if targetReg == regResult {
				zeroExt = x.RegZeroExt()
			} else {
				panic("moving temporary integer register to itself")
			}

		case values.Stack:
			Pop.op(code, targetReg)

		case values.ConditionFlags:
			if x.Type != types.I32 {
				panic(x)
			}

			var end links.L

			cond := x.Condition()
			setcc := conditionInsns[cond].setcc

			switch {
			case cond >= values.MinUnorderedOrCondition:
				MovImm.opImm(code, x.Type, targetReg, 1) // true
				Jp.rel8.opStub(code)                     // if unordered, else
				end.AddSite(code.Len())                  //
				setcc.opReg(code, targetReg)             // cond

			case cond >= values.MinOrderedAndCondition:
				MovImm.opImm(code, x.Type, targetReg, 0) // false
				Jp.rel8.opStub(code)                     // if unordered, else
				end.AddSite(code.Len())                  //
				setcc.opReg(code, targetReg)             // cond

			default:
				setcc.opReg(code, targetReg)
				Movzx8.opFromReg(code, x.Type, targetReg, targetReg)
			}

			end.Addr = code.Len()
			mach.updateBranches8(code, &end)

			zeroExt = true

		default:
			panic(x)
		}

	case types.Float:
		switch x.Storage {
		case values.Imm:
			if value := x.ImmValue(); value == 0 {
				PxorSSE.opFromReg(code, x.Type, targetReg, targetReg)
			} else {
				MovImm64.op(code, x.Type, regScratch, value) // integer scratch register
				MovSSE.opFromReg(code, x.Type, targetReg, regScratch)
			}

		case values.VarMem:
			MovsSSE.opFromStack(code, x.Type, targetReg, x.VarMemOffset())

		case values.VarReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				MovsSSE.opFromReg(code, x.Type, targetReg, sourceReg)
			}

		case values.TempReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				MovsSSE.opFromReg(code, x.Type, targetReg, sourceReg)
			} else if targetReg != regResult {
				panic("moving temporary float register to itself")
			}

		case values.Stack:
			popFloatOp(code, x.Type, targetReg)

		default:
			panic(x)
		}

	default:
		panic(x)
	}

	code.Consumed(x)

	return
}
Example #4
0
func (mach X86) binaryIntOp(code gen.RegCoder, index uint8, a, b values.Operand) (result values.Operand) {
	if a.Storage == values.Imm && a.ImmValue() == 0 && index == opers.IndexIntSub {
		targetReg, _ := mach.opMaybeResultReg(code, b, false)
		Neg.opReg(code, a.Type, targetReg)
		return values.TempRegOperand(a.Type, targetReg, true)
	}

	switch b.Storage {
	case values.Imm:
		value := b.ImmValue()

		switch {
		case index == opers.IndexIntAdd && value == 1: // assume that we won't see sub -1
			reg, _ := mach.opMaybeResultReg(code, a, false)
			Inc.opReg(code, a.Type, reg)
			return values.TempRegOperand(a.Type, reg, true)

		case index == opers.IndexIntSub && value == 1: // assume that we won't see add -1
			reg, _ := mach.opMaybeResultReg(code, a, false)
			Dec.opReg(code, a.Type, reg)
			return values.TempRegOperand(a.Type, reg, true)

		case value < -0x80000000 || value >= 0x80000000:
			// TODO: merge this with the next outer case
			sourceReg, _, own := mach.opBorrowMaybeScratchReg(code, b, true)
			b = values.RegOperand(own, a.Type, sourceReg)
		}

	case values.Stack, values.ConditionFlags:
		sourceReg, _, own := mach.opBorrowMaybeScratchReg(code, b, true)
		b = values.RegOperand(own, a.Type, sourceReg)
	}

	insn := binaryIntInsns[index]
	targetReg, _ := mach.opMaybeResultReg(code, a, false)
	result = values.TempRegOperand(a.Type, targetReg, true)

	if b.Storage == values.VarMem {
		insn.opFromStack(code, a.Type, targetReg, b.VarMemOffset())
		return
	}

	var sourceReg regs.R

	if b.Storage.IsReg() {
		sourceReg = b.Reg()
	} else {
		if b.Storage == values.Imm {
			if value := b.ImmValue(); value >= -0x80000000 && value < 0x80000000 {
				insn.opImm(code, a.Type, targetReg, int32(b.ImmValue()))
				return
			}
		}
		sourceReg = regScratch
		mach.OpMove(code, sourceReg, b, false)
	}

	insn.opFromReg(code, a.Type, targetReg, sourceReg)
	code.Consumed(b)
	return
}