diff --git a/src/lj_asm.c b/src/lj_asm.c index d395010d..85962ab1 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c @@ -3005,6 +3005,17 @@ static void asm_neg_not(ASMState *as, IRIns *ir, x86Group3 xg) ra_left(as, dest, ir->op1); } +static void asm_min_max(ASMState *as, IRIns *ir, int cc) +{ + Reg right, dest = ra_dest(as, ir, RSET_GPR); + IRRef lref = ir->op1, rref = ir->op2; + if (irref_isk(rref)) { lref = rref; rref = ir->op1; } + right = ra_alloc1(as, rref, rset_exclude(RSET_GPR, dest)); + emit_rr(as, XO_CMOV + (cc<<24), REX_64IR(ir, dest), right); + emit_rr(as, XO_CMP, REX_64IR(ir, dest), right); + ra_left(as, dest, lref); +} + static void asm_bitswap(ASMState *as, IRIns *ir) { Reg dest = ra_dest(as, ir, RSET_GPR); @@ -4067,8 +4078,18 @@ static void asm_ir(ASMState *as, IRIns *ir) break; case IR_ABS: asm_fparith(as, ir, XO_ANDPS); break; - case IR_MIN: asm_fparith(as, ir, XO_MINSD); break; - case IR_MAX: asm_fparith(as, ir, XO_MAXSD); break; + case IR_MIN: + if (irt_isnum(ir->t)) + asm_fparith(as, ir, XO_MINSD); + else + asm_min_max(as, ir, CC_G); + break; + case IR_MAX: + if (irt_isnum(ir->t)) + asm_fparith(as, ir, XO_MAXSD); + else + asm_min_max(as, ir, CC_L); + break; case IR_FPMATH: case IR_ATAN2: case IR_LDEXP: asm_fpmath(as, ir); diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 8077bf84..84957373 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -488,11 +488,19 @@ static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) static void LJ_FASTCALL recff_math_minmax(jit_State *J, RecordFFData *rd) { - TRef tr = lj_ir_tonum(J, J->base[0]); + TRef tr = lj_ir_tonumber(J, J->base[0]); uint32_t op = rd->data; BCReg i; - for (i = 1; J->base[i] != 0; i++) - tr = emitir(IRTN(op), tr, lj_ir_tonum(J, J->base[i])); + for (i = 1; J->base[i] != 0; i++) { + TRef tr2 = lj_ir_tonumber(J, J->base[i]); + IRType t = IRT_INT; + if (!(tref_isinteger(tr) && tref_isinteger(tr2))) { + if (tref_isinteger(tr)) tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); + if (tref_isinteger(tr2)) tr2 = emitir(IRTN(IR_CONV), tr2, IRCONV_NUM_INT); + t = IRT_NUM; + } + tr = emitir(IRT(op, t), tr, tr2); + } J->base[0] = tr; } diff --git a/src/lj_ir.c b/src/lj_ir.c index 64467758..94fe44b1 100644 --- a/src/lj_ir.c +++ b/src/lj_ir.c @@ -401,6 +401,18 @@ void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir) /* -- Convert IR operand types -------------------------------------------- */ +/* Convert from string to number. */ +TRef LJ_FASTCALL lj_ir_tonumber(jit_State *J, TRef tr) +{ + if (!tref_isnumber(tr)) { + if (tref_isstr(tr)) + tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); + else + lj_trace_err(J, LJ_TRERR_BADTYPE); + } + return tr; +} + /* Convert from integer or string to number. */ TRef LJ_FASTCALL lj_ir_tonum(jit_State *J, TRef tr) { diff --git a/src/lj_iropt.h b/src/lj_iropt.h index 1c94e91c..dd1128bc 100644 --- a/src/lj_iropt.h +++ b/src/lj_iropt.h @@ -82,6 +82,7 @@ static LJ_AINLINE TRef lj_ir_knum(jit_State *J, lua_Number n) LJ_FUNC void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir); /* Convert IR operand types. */ +LJ_FUNC TRef LJ_FASTCALL lj_ir_tonumber(jit_State *J, TRef tr); LJ_FUNC TRef LJ_FASTCALL lj_ir_tonum(jit_State *J, TRef tr); LJ_FUNC TRef LJ_FASTCALL lj_ir_tostr(jit_State *J, TRef tr); diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index eb500db9..325b0372 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c @@ -226,6 +226,8 @@ static int32_t kfold_intop(int32_t k1, int32_t k2, IROp op) case IR_BSAR: k1 >>= (k2 & 31); break; case IR_BROL: k1 = (int32_t)lj_rol((uint32_t)k1, (k2 & 31)); break; case IR_BROR: k1 = (int32_t)lj_ror((uint32_t)k1, (k2 & 31)); break; + case IR_MIN: k1 = k1 < k2 ? k1 : k2; break; + case IR_MAX: k1 = k1 > k2 ? k1 : k2; break; default: lua_assert(0); break; } return k1; @@ -242,6 +244,8 @@ LJFOLD(BSHR KINT KINT) LJFOLD(BSAR KINT KINT) LJFOLD(BROL KINT KINT) LJFOLD(BROR KINT KINT) +LJFOLD(MIN KINT KINT) +LJFOLD(MAX KINT KINT) LJFOLDF(kfold_intarith) { return INTFOLD(kfold_intop(fleft->i, fright->i, (IROp)fins->o)); @@ -1434,19 +1438,29 @@ LJFOLDF(reassoc_shift) LJFOLD(MIN MIN KNUM) LJFOLD(MAX MAX KNUM) +LJFOLD(MIN MIN KINT) +LJFOLD(MAX MAX KINT) LJFOLDF(reassoc_minmax_k) { IRIns *irk = IR(fleft->op2); if (irk->o == IR_KNUM) { lua_Number a = ir_knum(irk)->n; - lua_Number b = knumright; - lua_Number y = lj_vm_foldarith(a, b, fins->o - IR_ADD); + lua_Number y = lj_vm_foldarith(a, knumright, fins->o - IR_ADD); if (a == y) /* (x o k1) o k2 ==> x o k1, if (k1 o k2) == k1. */ return LEFTFOLD; PHIBARRIER(fleft); fins->op1 = fleft->op1; fins->op2 = (IRRef1)lj_ir_knum(J, y); return RETRYFOLD; /* (x o k1) o k2 ==> x o (k1 o k2) */ + } else if (irk->o == IR_KINT) { + int32_t a = irk->i; + int32_t y = kfold_intop(a, fright->i, fins->o); + if (a == y) /* (x o k1) o k2 ==> x o k1, if (k1 o k2) == k1. */ + return LEFTFOLD; + PHIBARRIER(fleft); + fins->op1 = fleft->op1; + fins->op2 = (IRRef1)lj_ir_kint(J, y); + return RETRYFOLD; /* (x o k1) o k2 ==> x o (k1 o k2) */ } return NEXTFOLD; } diff --git a/src/lj_target_x86.h b/src/lj_target_x86.h index 37c68f4b..564ffc63 100644 --- a/src/lj_target_x86.h +++ b/src/lj_target_x86.h @@ -234,6 +234,7 @@ typedef enum { XO_MOVSXw = XO_0f(bf), XO_MOVSXd = XO_(63), XO_BSWAP = XO_0f(c8), + XO_CMOV = XO_0f(40), XO_MOVSD = XO_f20f(10), XO_MOVSDto = XO_f20f(11),