// LoadOp makes sure that index gets zero-extended if it's a VarReg operand. func (mach X86) LoadOp(code gen.RegCoder, oper uint16, index values.Operand, resultType types.T, offset uint32) (result values.Operand) { size := oper >> 8 baseReg, indexReg, ownIndexReg, disp := mach.opMemoryAddress(code, size, index, offset) if ownIndexReg { defer code.FreeReg(types.I64, indexReg) } load := memoryLoads[uint8(oper)] targetReg, ok := code.TryAllocReg(resultType) if !ok { targetReg = regResult } result = values.TempRegOperand(resultType, targetReg, load.zeroExt) insnType := load.insnType if insnType == 0 { insnType = resultType } load.insn.opFromIndirect(code, insnType, targetReg, 0, indexReg, baseReg, disp) return }
// OpGetGlobal must not update CPU's condition flags. func (mach X86) OpGetGlobal(code gen.RegCoder, t types.T, offset int32) values.Operand { reg, ok := code.TryAllocReg(t) if !ok { reg = regResult } if t.Category() == types.Int { Mov.opFromIndirect(code, t, reg, 0, NoIndex, regMemoryBase, offset) } else { MovSSE.opFromIndirect(code, t, reg, 0, NoIndex, regMemoryBase, offset) } return values.TempRegOperand(t, reg, true) }
func (mach X86) unaryIntOp(code gen.RegCoder, index uint8, x values.Operand) (result values.Operand) { if index == opers.IndexIntEqz { reg, _, own := mach.opBorrowMaybeScratchReg(code, x, false) if own { defer code.FreeReg(x.Type, reg) } Test.opFromReg(code, x.Type, reg, reg) return values.ConditionFlagsOperand(values.Eq) } var targetReg regs.R sourceReg, _, own := mach.opBorrowMaybeScratchReg(code, x, false) if own { targetReg = sourceReg } else { var ok bool targetReg, ok = code.TryAllocReg(x.Type) if !ok { targetReg = regResult } } result = values.TempRegOperand(x.Type, targetReg, true) insn := unaryIntInsns[index] switch index { case opers.IndexIntClz: insn.opFromReg(code, x.Type, regScratch, sourceReg) MovImm.opImm(code, x.Type, targetReg, -1) Cmove.opFromReg(code, x.Type, regScratch, targetReg) MovImm.opImm(code, x.Type, targetReg, (int32(x.Type.Size())<<3)-1) Sub.opFromReg(code, x.Type, targetReg, regScratch) case opers.IndexIntCtz: insn.opFromReg(code, x.Type, targetReg, sourceReg) MovImm.opImm(code, x.Type, regScratch, int32(x.Type.Size())<<3) Cmove.opFromReg(code, x.Type, targetReg, regScratch) case opers.IndexIntPopcnt: insn.opFromReg(code, x.Type, targetReg, sourceReg) } return }
// opMaybeResultReg returns either the register of the given operand, or the // reserved result register with the value of the operand. The caller has // exclusive ownership of the register. func (mach X86) opMaybeResultReg(code gen.RegCoder, x values.Operand, preserveFlags bool) (reg regs.R, zeroExt bool) { if x.Storage == values.TempReg { reg = x.Reg() zeroExt = x.RegZeroExt() } else { var ok bool reg, ok = code.TryAllocReg(x.Type) if !ok { reg = regResult } if x.Storage != values.Nowhere { mach.OpMove(code, reg, x, preserveFlags) zeroExt = true } } 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) }