зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1289054 - Part 18: Implement the 64bit variant of WasmTruncate on arm, r=bbouvier
This commit is contained in:
Родитель
08728c529c
Коммит
db11d480ae
|
@ -200,6 +200,30 @@ UModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
|
||||||
return x % y;
|
return x % y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
TruncateDoubleToInt64(double input)
|
||||||
|
{
|
||||||
|
// Note: INT64_MAX is not representable in double. It is actually INT64_MAX + 1.
|
||||||
|
// Therefore also sending the failure value.
|
||||||
|
if (input >= double(INT64_MAX))
|
||||||
|
return 0x8000000000000000;
|
||||||
|
if (input < double(INT64_MIN))
|
||||||
|
return 0x8000000000000000;
|
||||||
|
return int64_t(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
TruncateDoubleToUint64(double input)
|
||||||
|
{
|
||||||
|
// Note: UINT64_MAX is not representable in double. It is actually UINT64_MAX + 1.
|
||||||
|
// Therefore also sending the failure value.
|
||||||
|
if (input >= double(UINT64_MAX))
|
||||||
|
return 0x8000000000000000;
|
||||||
|
if (input <= -1.0)
|
||||||
|
return 0x8000000000000000;
|
||||||
|
return uint64_t(input);
|
||||||
|
}
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
static inline void*
|
static inline void*
|
||||||
FuncCast(F* pf, ABIFunctionType type)
|
FuncCast(F* pf, ABIFunctionType type)
|
||||||
|
@ -247,6 +271,10 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
|
||||||
return FuncCast(ModI64, Args_General4);
|
return FuncCast(ModI64, Args_General4);
|
||||||
case SymbolicAddress::UModI64:
|
case SymbolicAddress::UModI64:
|
||||||
return FuncCast(UModI64, Args_General4);
|
return FuncCast(UModI64, Args_General4);
|
||||||
|
case SymbolicAddress::TruncateDoubleToUint64:
|
||||||
|
return FuncCast(TruncateDoubleToUint64, Args_Int64_Double);
|
||||||
|
case SymbolicAddress::TruncateDoubleToInt64:
|
||||||
|
return FuncCast(TruncateDoubleToInt64, Args_Int64_Double);
|
||||||
#if defined(JS_CODEGEN_ARM)
|
#if defined(JS_CODEGEN_ARM)
|
||||||
case SymbolicAddress::aeabi_idivmod:
|
case SymbolicAddress::aeabi_idivmod:
|
||||||
return FuncCast(__aeabi_idivmod, Args_General2);
|
return FuncCast(__aeabi_idivmod, Args_General2);
|
||||||
|
|
|
@ -901,6 +901,8 @@ enum class SymbolicAddress
|
||||||
UDivI64,
|
UDivI64,
|
||||||
ModI64,
|
ModI64,
|
||||||
UModI64,
|
UModI64,
|
||||||
|
TruncateDoubleToInt64,
|
||||||
|
TruncateDoubleToUint64,
|
||||||
Limit
|
Limit
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -762,10 +762,11 @@ enum {
|
||||||
ArgType_General = 0x1,
|
ArgType_General = 0x1,
|
||||||
ArgType_Double = 0x2,
|
ArgType_Double = 0x2,
|
||||||
ArgType_Float32 = 0x3,
|
ArgType_Float32 = 0x3,
|
||||||
|
ArgType_Int64 = 0x4,
|
||||||
|
|
||||||
RetType_Shift = 0x0,
|
RetType_Shift = 0x0,
|
||||||
ArgType_Shift = 0x2,
|
ArgType_Shift = 0x3,
|
||||||
ArgType_Mask = 0x3
|
ArgType_Mask = 0x7
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ABIFunctionType
|
enum ABIFunctionType
|
||||||
|
@ -782,6 +783,9 @@ enum ABIFunctionType
|
||||||
Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
|
Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
|
||||||
Args_General8 = Args_General7 | (ArgType_General << (ArgType_Shift * 8)),
|
Args_General8 = Args_General7 | (ArgType_General << (ArgType_Shift * 8)),
|
||||||
|
|
||||||
|
// int64 f(double)
|
||||||
|
Args_Int64_Double = (ArgType_Int64 << RetType_Shift) | (ArgType_Double << ArgType_Shift),
|
||||||
|
|
||||||
// double f()
|
// double f()
|
||||||
Args_Double_None = ArgType_Double << RetType_Shift,
|
Args_Double_None = ArgType_Double << RetType_Shift,
|
||||||
|
|
||||||
|
|
|
@ -2968,6 +2968,45 @@ CodeGeneratorARM::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir)
|
||||||
masm.bind(ool->rejoin());
|
masm.bind(ool->rejoin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CodeGeneratorARM::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
|
||||||
|
{
|
||||||
|
FloatRegister input = ToFloatRegister(lir->input());
|
||||||
|
FloatRegister inputDouble = input;
|
||||||
|
Register64 output = ToOutRegister64(lir);
|
||||||
|
|
||||||
|
MWasmTruncateToInt64* mir = lir->mir();
|
||||||
|
MIRType fromType = mir->input()->type();
|
||||||
|
|
||||||
|
auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input);
|
||||||
|
addOutOfLineCode(ool, mir);
|
||||||
|
|
||||||
|
ScratchDoubleScope scratchScope(masm);
|
||||||
|
if (fromType == MIRType::Float32) {
|
||||||
|
inputDouble = ScratchDoubleReg;
|
||||||
|
masm.convertFloat32ToDouble(input, inputDouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
masm.Push(input);
|
||||||
|
|
||||||
|
masm.setupUnalignedABICall(output.high);
|
||||||
|
masm.passABIArg(inputDouble, MoveOp::DOUBLE);
|
||||||
|
if (lir->mir()->isUnsigned())
|
||||||
|
masm.callWithABI(wasm::SymbolicAddress::TruncateDoubleToUint64);
|
||||||
|
else
|
||||||
|
masm.callWithABI(wasm::SymbolicAddress::TruncateDoubleToInt64);
|
||||||
|
|
||||||
|
masm.Pop(input);
|
||||||
|
|
||||||
|
masm.ma_cmp(output.high, Imm32(0x80000000));
|
||||||
|
masm.ma_cmp(output.low, Imm32(0x00000000), Assembler::Equal);
|
||||||
|
masm.ma_b(ool->entry(), Assembler::Equal);
|
||||||
|
|
||||||
|
masm.bind(ool->rejoin());
|
||||||
|
|
||||||
|
MOZ_ASSERT(ReturnReg64 == output);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool)
|
CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool)
|
||||||
{
|
{
|
||||||
|
@ -2989,39 +3028,57 @@ CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* oo
|
||||||
// Handle special values.
|
// Handle special values.
|
||||||
Label fail;
|
Label fail;
|
||||||
|
|
||||||
|
// By default test for the following inputs and bail:
|
||||||
|
// signed: ] -Inf, INTXX_MIN - 1.0 ] and [ INTXX_MAX + 1.0 : +Inf [
|
||||||
|
// unsigned: ] -Inf, -1.0 ] and [ UINTXX_MAX + 1.0 : +Inf [
|
||||||
|
// Note: we cannot always represent those exact values. As a result
|
||||||
|
// this changes the actual comparison a bit.
|
||||||
double minValue, maxValue;
|
double minValue, maxValue;
|
||||||
if (ool->isUnsigned()) {
|
Assembler::DoubleCondition minCond = Assembler::DoubleLessThanOrEqual;
|
||||||
minValue = -1;
|
Assembler::DoubleCondition maxCond = Assembler::DoubleGreaterThanOrEqual;
|
||||||
maxValue = double(UINT32_MAX) + 1.0;
|
if (ool->toType() == MIRType::Int64) {
|
||||||
|
if (ool->isUnsigned()) {
|
||||||
|
minValue = -1;
|
||||||
|
maxValue = double(UINT64_MAX) + 1.0;
|
||||||
|
} else {
|
||||||
|
// In the float32/double range there exists no value between
|
||||||
|
// INT64_MIN and INT64_MIN - 1.0. Making INT64_MIN the lower-bound.
|
||||||
|
minValue = double(INT64_MIN);
|
||||||
|
minCond = Assembler::DoubleLessThan;
|
||||||
|
maxValue = double(INT64_MAX) + 1.0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
minValue = double(INT32_MIN) - 1.0;
|
if (ool->isUnsigned()) {
|
||||||
maxValue = double(INT32_MAX) + 1.0;
|
minValue = -1;
|
||||||
|
maxValue = double(UINT32_MAX) + 1.0;
|
||||||
|
} else {
|
||||||
|
if (fromType == MIRType::Float32) {
|
||||||
|
// In the float32 range there exists no value between
|
||||||
|
// INT32_MIN and INT32_MIN - 1.0. Making INT32_MIN the lower-bound.
|
||||||
|
minValue = double(INT32_MIN);
|
||||||
|
minCond = Assembler::DoubleLessThan;
|
||||||
|
} else {
|
||||||
|
minValue = double(INT32_MIN) - 1.0;
|
||||||
|
}
|
||||||
|
maxValue = double(INT32_MAX) + 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromType == MIRType::Double) {
|
if (fromType == MIRType::Double) {
|
||||||
scratch = scratchScope.doubleOverlay();
|
scratch = scratchScope.doubleOverlay();
|
||||||
masm.loadConstantDouble(minValue, scratch);
|
masm.loadConstantDouble(minValue, scratch);
|
||||||
masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &fail);
|
masm.branchDouble(minCond, input, scratch, &fail);
|
||||||
|
|
||||||
masm.loadConstantDouble(maxValue, scratch);
|
masm.loadConstantDouble(maxValue, scratch);
|
||||||
masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, scratch, &fail);
|
masm.branchDouble(maxCond, input, scratch, &fail);
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(fromType == MIRType::Float32);
|
MOZ_ASSERT(fromType == MIRType::Float32);
|
||||||
scratch = scratchScope.singleOverlay();
|
scratch = scratchScope.singleOverlay();
|
||||||
|
|
||||||
// For int32, float(minValue) rounds to INT32_MIN, we want to fail when
|
|
||||||
// input < float(minValue).
|
|
||||||
// For uint32, float(minValue) == -1, we want to fail when input <= -1.
|
|
||||||
auto condition = minValue == -1.0
|
|
||||||
? Assembler::DoubleLessThanOrEqual
|
|
||||||
: Assembler::DoubleLessThan;
|
|
||||||
|
|
||||||
masm.loadConstantFloat32(float(minValue), scratch);
|
masm.loadConstantFloat32(float(minValue), scratch);
|
||||||
masm.branchFloat(condition, input, scratch, &fail);
|
masm.branchFloat(minCond, input, scratch, &fail);
|
||||||
|
|
||||||
// maxValue is exactly represented in both cases.
|
|
||||||
masm.loadConstantFloat32(float(maxValue), scratch);
|
masm.loadConstantFloat32(float(maxValue), scratch);
|
||||||
masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, input, scratch, &fail);
|
masm.branchFloat(maxCond, input, scratch, &fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We had an actual correct value, get back to where we were.
|
// We had an actual correct value, get back to where we were.
|
||||||
|
|
|
@ -177,6 +177,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
||||||
virtual void visitClzI64(LClzI64* ins);
|
virtual void visitClzI64(LClzI64* ins);
|
||||||
virtual void visitCtzI64(LCtzI64* ins);
|
virtual void visitCtzI64(LCtzI64* ins);
|
||||||
virtual void visitNotI64(LNotI64* ins);
|
virtual void visitNotI64(LNotI64* ins);
|
||||||
|
virtual void visitWasmTruncateToInt64(LWasmTruncateToInt64* ins);
|
||||||
|
|
||||||
// Out of line visitors.
|
// Out of line visitors.
|
||||||
void visitOutOfLineBailout(OutOfLineBailout* ool);
|
void visitOutOfLineBailout(OutOfLineBailout* ool);
|
||||||
|
|
|
@ -541,6 +541,21 @@ class LAsmJSAtomicBinopCallout : public LCallInstructionHelper<1, 2, 0>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LWasmTruncateToInt64 : public LCallInstructionHelper<INT64_PIECES, 1, 0>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LIR_HEADER(WasmTruncateToInt64);
|
||||||
|
|
||||||
|
LWasmTruncateToInt64(const LAllocation& in)
|
||||||
|
{
|
||||||
|
setOperand(0, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWasmTruncateToInt64* mir() const {
|
||||||
|
return mir_->toWasmTruncateToInt64();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace jit
|
} // namespace jit
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
_(AsmJSAtomicExchangeCallout) \
|
_(AsmJSAtomicExchangeCallout) \
|
||||||
_(AsmJSAtomicBinopCallout) \
|
_(AsmJSAtomicBinopCallout) \
|
||||||
_(DivOrModI64) \
|
_(DivOrModI64) \
|
||||||
_(UDivOrModI64)
|
_(UDivOrModI64) \
|
||||||
|
_(WasmTruncateToInt64)
|
||||||
|
|
||||||
#endif /* jit_arm_LOpcodes_arm_h */
|
#endif /* jit_arm_LOpcodes_arm_h */
|
||||||
|
|
|
@ -915,7 +915,10 @@ LIRGeneratorARM::visitRandom(MRandom* ins)
|
||||||
void
|
void
|
||||||
LIRGeneratorARM::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
|
LIRGeneratorARM::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
|
||||||
{
|
{
|
||||||
MOZ_CRASH("NY");
|
MDefinition* opd = ins->input();
|
||||||
|
MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
|
||||||
|
|
||||||
|
defineReturn(new(alloc()) LWasmTruncateToInt64(useRegisterAtStart(opd)), ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -2287,6 +2287,7 @@ typedef double (*Prototype_Double_None)();
|
||||||
typedef double (*Prototype_Double_Double)(double arg0);
|
typedef double (*Prototype_Double_Double)(double arg0);
|
||||||
typedef double (*Prototype_Double_Int)(int32_t arg0);
|
typedef double (*Prototype_Double_Int)(int32_t arg0);
|
||||||
typedef int32_t (*Prototype_Int_Double)(double arg0);
|
typedef int32_t (*Prototype_Int_Double)(double arg0);
|
||||||
|
typedef int64_t (*Prototype_Int64_Double)(double arg0);
|
||||||
typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
|
typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
|
||||||
typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
|
typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
|
||||||
int32_t arg3);
|
int32_t arg3);
|
||||||
|
@ -2429,6 +2430,16 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
||||||
setCallResult(result);
|
setCallResult(result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Args_Int64_Double: {
|
||||||
|
double dval0, dval1;
|
||||||
|
int32_t ival;
|
||||||
|
getFpArgs(&dval0, &dval1, &ival);
|
||||||
|
Prototype_Int64_Double target = reinterpret_cast<Prototype_Int64_Double>(external);
|
||||||
|
int64_t result = target(dval0);
|
||||||
|
scratchVolatileRegisters(/* scratchFloat = true */);
|
||||||
|
setCallResult(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Args_Double_None: {
|
case Args_Double_None: {
|
||||||
Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
|
Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
|
||||||
double dresult = target();
|
double dresult = target();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче