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 }
func (mach X86) binaryDivmulOp(code gen.RegCoder, index uint8, a, b values.Operand) values.Operand { insn := binaryDivmulInsns[index] t := a.Type if b.Storage == values.Imm { value := b.ImmValue() switch { case value == -1: reg, _ := mach.opMaybeResultReg(code, a, false) Neg.opReg(code, t, reg) return values.TempRegOperand(t, reg, true) case insn.shiftImm.defined() && value > 0 && isPowerOfTwo(uint64(value)): reg, _ := mach.opMaybeResultReg(code, a, false) insn.shiftImm.op(code, t, reg, log2(uint64(value))) return values.TempRegOperand(t, reg, true) } } division := (index & opers.DivmulMul) == 0 checkZero := true checkOverflow := true if b.Storage.IsReg() { if b.Reg() == regResult { newReg := regScratch if division { var ok bool // can't use scratch reg as divisor since it contains the dividend high bits newReg, ok = code.TryAllocReg(t) if !ok { // borrow a register which we don't need in this function MovMMX.opFromReg(code, types.I64, regScratchMMX, regTextBase) defer MovMMX.opToReg(code, types.I64, regTextBase, regScratchMMX) newReg = regTextBase } } Mov.opFromReg(code, t, newReg, regResult) b = values.RegOperand(true, t, newReg) } } else { if division && b.Storage == values.Imm { value := b.ImmValue() if value != 0 { checkZero = false } if value != -1 { checkOverflow = false } } reg, ok := code.TryAllocReg(t) if !ok { // borrow a register which we don't need in this function MovMMX.opFromReg(code, types.I64, regScratchMMX, regTextBase) defer MovMMX.opToReg(code, types.I64, regTextBase, regScratchMMX) reg = regTextBase } mach.OpMove(code, reg, b, true) b = values.RegOperand(true, t, reg) } mach.OpMove(code, regResult, a, false) remainder := (index & opers.DivmulRem) != 0 var doNot links.L if division { if checkZero { mach.opCheckDivideByZero(code, t, b.Reg()) } if a.Storage == values.Imm { value := a.ImmValue() if t.Size() == types.Size32 { if value != -0x80000000 { checkOverflow = false } } else { if value != -0x8000000000000000 { checkOverflow = false } } } signed := (index & opers.DivmulSign) != 0 if signed && checkOverflow { var do links.L if remainder { Xor.opFromReg(code, types.I32, regScratch, regScratch) // moved to result at the end Cmp.opImm(code, t, b.Reg(), -1) Je.rel8.opStub(code) doNot.AddSite(code.Len()) } else { switch t.Size() { case types.Size32: Cmp.opImm(code, t, regResult, -0x80000000) case types.Size64: MovImm64.op(code, t, regScratch, -0x8000000000000000) Cmp.opFromReg(code, t, regResult, regScratch) default: panic(a) } Jne.rel8.opStub(code) do.AddSite(code.Len()) Cmp.opImm(code, t, b.Reg(), -1) Jne.rel8.opStub(code) do.AddSite(code.Len()) code.OpTrapCall(traps.IntegerOverflow) } do.Addr = code.Len() mach.updateBranches8(code, &do) } if signed { // sign-extend dividend low bits to high bits CdqCqo.op(code, t) } else { // zero-extend dividend high bits Xor.opFromReg(code, types.I32, regScratch, regScratch) } } insn.opReg(code, t, b.Reg()) code.Consumed(b) doNot.Addr = code.Len() mach.updateBranches8(code, &doNot) if remainder { Mov.opFromReg(code, t, regResult, regScratch) } return values.TempRegOperand(t, regResult, true) }