зеркало из https://github.com/mozilla/gecko-dev.git
Bug 966295: Implement variadic Math.min and Math.max in Odin; r=luke
This commit is contained in:
Родитель
8829c682ee
Коммит
1360c091f9
|
@ -59,8 +59,9 @@ var f = asmLink(asmCompile('glob', USE_ASM + 'var abs=glob.Math.abs; function f(
|
|||
for (n of [-Math.pow(2,31)-1, -Math.pow(2,31), -Math.pow(2,31)+1, -1, 0, 1, Math.pow(2,31)-2, Math.pow(2,31)-1, Math.pow(2,31)])
|
||||
assertEq(f(n), Math.abs(n|0)|0);
|
||||
|
||||
function testBinary(f, g) {
|
||||
var numbers = [NaN, Infinity, -Infinity, -10000, -3.4, -0, 0, 3.4, 10000];
|
||||
var doubleNumbers = [NaN, Infinity, -Infinity, -10000, -3.4, -0, 0, 3.4, 10000];
|
||||
var intNumbers = [-10000, -3, -1, 0, 3, 10000];
|
||||
function testBinary(f, g, numbers) {
|
||||
for (n of numbers)
|
||||
for (o of numbers)
|
||||
assertEq(f(n,o), g(n,o));
|
||||
|
@ -68,11 +69,43 @@ function testBinary(f, g) {
|
|||
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:Math.sin}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:null}});
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:Math.pow}}), Math.pow);
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:Math.pow}}), Math.pow, doubleNumbers);
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:Math.sin}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:null}});
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:Math.atan2}}), Math.atan2);
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:Math.atan2}}), Math.atan2, doubleNumbers);
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d) { d=+d; return +min(d) } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var f32=glob.Math.fround; var min=glob.Math.min; function f(d) { d=f32(d); return +min(d, f32(5)) } return f');
|
||||
assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + 'var i32=new glob.Int32Array(heap); var min=glob.Math.min; function f() { return min(i32[0], 5)|0 } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(x) { x=x|0; return min(3 + x, 5)|0 } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(x) { x=x|0; return min(5, 3 + x)|0 } return f');
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:Math.sin}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:null}});
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:Math.min}}), Math.min, doubleNumbers);
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=d|0;e=e|0; return min(d,e)|0} return f'), {Math:{min:Math.min}}), Math.min, intNumbers);
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:Math.sin}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:null}});
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:Math.max}}), Math.max, doubleNumbers);
|
||||
testBinary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=d|0;e=e|0; return max(d,e)|0} return f'), {Math:{max:Math.max}}), Math.max, intNumbers);
|
||||
|
||||
function testTernary(f, g, numbers) {
|
||||
for (n of numbers)
|
||||
for (o of numbers)
|
||||
for (p of numbers)
|
||||
assertEq(f(n,o,p), g(n,o,p));
|
||||
}
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=g|0; return +min(d,e,g) } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=+g; return max(d,e,g)|0 } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=+g; return min(d,e,g)|0 } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return +max(d,e,g) } return f');
|
||||
testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return max(d,e,g)|0 } return f'), {Math:{max:Math.max}}), Math.max, intNumbers);
|
||||
testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=+d;e=+e;g=+g; return +max(d,e,g) } return f'), {Math:{max:Math.max}}), Math.max, doubleNumbers);
|
||||
testTernary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return min(d,e,g)|0 } return f'), {Math:{min:Math.min}}), Math.min, intNumbers);
|
||||
testTernary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=+g; return +min(d,e,g) } return f'), {Math:{min:Math.min}}), Math.min, doubleNumbers);
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var sin=glob.Math.sin; function f(d) { d=+d; d = sin(d); } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + 'var sin=glob.Math.sin; function f(d) { d=+d; var i=0; i = sin(d)|0; } return f');
|
||||
|
|
|
@ -1204,6 +1204,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
|||
!addStandardLibraryMathName("atan2", AsmJSMathBuiltin_atan2) ||
|
||||
!addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul) ||
|
||||
!addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround) ||
|
||||
!addStandardLibraryMathName("min", AsmJSMathBuiltin_min) ||
|
||||
!addStandardLibraryMathName("max", AsmJSMathBuiltin_max) ||
|
||||
!addStandardLibraryMathName("E", M_E) ||
|
||||
!addStandardLibraryMathName("LN10", M_LN10) ||
|
||||
!addStandardLibraryMathName("LN2", M_LN2) ||
|
||||
|
@ -2209,6 +2211,14 @@ class FunctionCompiler
|
|||
return ins;
|
||||
}
|
||||
|
||||
MDefinition *minMax(MDefinition *lhs, MDefinition *rhs, MIRType type, bool isMax) {
|
||||
if (!curBlock_)
|
||||
return nullptr;
|
||||
MMinMax *ins = MMinMax::New(alloc(), lhs, rhs, type, isMax);
|
||||
curBlock_->add(ins);
|
||||
return ins;
|
||||
}
|
||||
|
||||
MDefinition *mul(MDefinition *lhs, MDefinition *rhs, MIRType type, MMul::Mode mode)
|
||||
{
|
||||
if (!curBlock_)
|
||||
|
@ -3792,6 +3802,51 @@ CheckMathSqrt(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition
|
|||
return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars());
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckMathMinMax(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDefinition **def, Type *type, bool isMax)
|
||||
{
|
||||
if (CallArgListLength(callNode) < 2)
|
||||
return f.fail(callNode, "Math.min/max must be passed at least 2 arguments");
|
||||
|
||||
ParseNode *firstArg = CallArgList(callNode);
|
||||
MDefinition *firstDef;
|
||||
Type firstType;
|
||||
if (!CheckExpr(f, firstArg, &firstDef, &firstType))
|
||||
return false;
|
||||
|
||||
bool opIsDouble = firstType.isMaybeDouble();
|
||||
bool opIsInteger = firstType.isInt();
|
||||
MIRType opType = firstType.toMIRType();
|
||||
|
||||
if (!opIsDouble && !opIsInteger)
|
||||
return f.failf(firstArg, "%s is not a subtype of double? or int", firstType.toChars());
|
||||
|
||||
MDefinition *lastDef = firstDef;
|
||||
ParseNode *nextArg = NextNode(firstArg);
|
||||
for (unsigned i = 1; i < CallArgListLength(callNode); i++, nextArg = NextNode(nextArg)) {
|
||||
MDefinition *nextDef;
|
||||
Type nextType;
|
||||
if (!CheckExpr(f, nextArg, &nextDef, &nextType))
|
||||
return false;
|
||||
|
||||
if (opIsDouble && !nextType.isMaybeDouble())
|
||||
return f.failf(nextArg, "%s is not a subtype of double?", nextType.toChars());
|
||||
if (opIsInteger && !nextType.isInt())
|
||||
return f.failf(nextArg, "%s is not a subtype of int", nextType.toChars());
|
||||
|
||||
lastDef = f.minMax(lastDef, nextDef, opType, isMax);
|
||||
}
|
||||
|
||||
if (opIsDouble && retType != RetType::Double)
|
||||
return f.failf(callNode, "return type is double, used as %s", retType.toType().toChars());
|
||||
if (opIsInteger && retType != RetType::Signed)
|
||||
return f.failf(callNode, "return type is int, used as %s", retType.toType().toChars());
|
||||
|
||||
*type = opIsDouble ? Type::Double : Type::Signed;
|
||||
*def = lastDef;
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*CheckArgType)(FunctionCompiler &f, ParseNode *argNode, Type type);
|
||||
|
||||
static bool
|
||||
|
@ -4085,6 +4140,8 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinF
|
|||
case AsmJSMathBuiltin_abs: return CheckMathAbs(f, callNode, retType, def, type);
|
||||
case AsmJSMathBuiltin_sqrt: return CheckMathSqrt(f, callNode, retType, def, type);
|
||||
case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, retType, def, type);
|
||||
case AsmJSMathBuiltin_min: return CheckMathMinMax(f, callNode, retType, def, type, /* isMax = */ false);
|
||||
case AsmJSMathBuiltin_max: return CheckMathMinMax(f, callNode, retType, def, type, /* isMax = */ true);
|
||||
case AsmJSMathBuiltin_sin: arity = 1; doubleCallee = AsmJSImm_SinD; floatCallee = AsmJSImm_SinF; break;
|
||||
case AsmJSMathBuiltin_cos: arity = 1; doubleCallee = AsmJSImm_CosD; floatCallee = AsmJSImm_CosF; break;
|
||||
case AsmJSMathBuiltin_tan: arity = 1; doubleCallee = AsmJSImm_TanD; floatCallee = AsmJSImm_TanF; break;
|
||||
|
|
|
@ -166,6 +166,8 @@ ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleVa
|
|||
case AsmJSMathBuiltin_log: native = math_log; break;
|
||||
case AsmJSMathBuiltin_pow: native = js_math_pow; break;
|
||||
case AsmJSMathBuiltin_sqrt: native = js_math_sqrt; break;
|
||||
case AsmJSMathBuiltin_min: native = js_math_min; break;
|
||||
case AsmJSMathBuiltin_max: native = js_math_max; break;
|
||||
case AsmJSMathBuiltin_abs: native = js_math_abs; break;
|
||||
case AsmJSMathBuiltin_atan2: native = math_atan2; break;
|
||||
case AsmJSMathBuiltin_imul: native = math_imul; break;
|
||||
|
|
|
@ -41,7 +41,7 @@ enum AsmJSMathBuiltinFunction
|
|||
AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
|
||||
AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
|
||||
AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
|
||||
AsmJSMathBuiltin_fround
|
||||
AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max
|
||||
};
|
||||
|
||||
// Static-link data is used to patch a module either after it has been
|
||||
|
|
Загрузка…
Ссылка в новой задаче