func (mach X86) OpBranchIf(code gen.Coder, x values.Operand, yes bool, addr int32) (sites []int32) { var cond values.Condition if x.Storage == values.ConditionFlags { cond = x.Condition() } else { reg, _, own := mach.opBorrowMaybeScratchReg(code, x, false) if own { defer code.FreeReg(types.I32, reg) } Test.opFromReg(code, types.I32, reg, reg) cond = values.Ne } if !yes { cond = values.InvertedConditions[cond] } var end links.L switch { case cond >= values.MinUnorderedOrCondition: Jp.op(code, addr) sites = append(sites, code.Len()) case cond >= values.MinOrderedAndCondition: Jp.rel8.opStub(code) end.AddSite(code.Len()) } conditionInsns[cond].jcc.op(code, addr) sites = append(sites, code.Len()) end.Addr = code.Len() mach.updateBranches8(code, &end) return }
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) }
// 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 }