зеркало из 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;
|
||||
}
|
||||
|
||||
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>
|
||||
static inline void*
|
||||
FuncCast(F* pf, ABIFunctionType type)
|
||||
|
@ -247,6 +271,10 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
|
|||
return FuncCast(ModI64, Args_General4);
|
||||
case SymbolicAddress::UModI64:
|
||||
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)
|
||||
case SymbolicAddress::aeabi_idivmod:
|
||||
return FuncCast(__aeabi_idivmod, Args_General2);
|
||||
|
|
|
@ -901,6 +901,8 @@ enum class SymbolicAddress
|
|||
UDivI64,
|
||||
ModI64,
|
||||
UModI64,
|
||||
TruncateDoubleToInt64,
|
||||
TruncateDoubleToUint64,
|
||||
Limit
|
||||
};
|
||||
|
||||
|
|
|
@ -762,10 +762,11 @@ enum {
|
|||
ArgType_General = 0x1,
|
||||
ArgType_Double = 0x2,
|
||||
ArgType_Float32 = 0x3,
|
||||
ArgType_Int64 = 0x4,
|
||||
|
||||
RetType_Shift = 0x0,
|
||||
ArgType_Shift = 0x2,
|
||||
ArgType_Mask = 0x3
|
||||
ArgType_Shift = 0x3,
|
||||
ArgType_Mask = 0x7
|
||||
};
|
||||
|
||||
enum ABIFunctionType
|
||||
|
@ -782,6 +783,9 @@ enum ABIFunctionType
|
|||
Args_General7 = Args_General6 | (ArgType_General << (ArgType_Shift * 7)),
|
||||
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()
|
||||
Args_Double_None = ArgType_Double << RetType_Shift,
|
||||
|
||||
|
|
|
@ -2968,6 +2968,45 @@ CodeGeneratorARM::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir)
|
|||
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
|
||||
CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool)
|
||||
{
|
||||
|
@ -2989,39 +3028,57 @@ CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* oo
|
|||
// Handle special values.
|
||||
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;
|
||||
if (ool->isUnsigned()) {
|
||||
minValue = -1;
|
||||
maxValue = double(UINT32_MAX) + 1.0;
|
||||
Assembler::DoubleCondition minCond = Assembler::DoubleLessThanOrEqual;
|
||||
Assembler::DoubleCondition maxCond = Assembler::DoubleGreaterThanOrEqual;
|
||||
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 {
|
||||
minValue = double(INT32_MIN) - 1.0;
|
||||
maxValue = double(INT32_MAX) + 1.0;
|
||||
if (ool->isUnsigned()) {
|
||||
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) {
|
||||
scratch = scratchScope.doubleOverlay();
|
||||
masm.loadConstantDouble(minValue, scratch);
|
||||
masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &fail);
|
||||
masm.branchDouble(minCond, input, scratch, &fail);
|
||||
|
||||
masm.loadConstantDouble(maxValue, scratch);
|
||||
masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, scratch, &fail);
|
||||
masm.branchDouble(maxCond, input, scratch, &fail);
|
||||
} else {
|
||||
MOZ_ASSERT(fromType == MIRType::Float32);
|
||||
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.branchFloat(condition, input, scratch, &fail);
|
||||
masm.branchFloat(minCond, input, scratch, &fail);
|
||||
|
||||
// maxValue is exactly represented in both cases.
|
||||
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.
|
||||
|
|
|
@ -177,6 +177,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
|||
virtual void visitClzI64(LClzI64* ins);
|
||||
virtual void visitCtzI64(LCtzI64* ins);
|
||||
virtual void visitNotI64(LNotI64* ins);
|
||||
virtual void visitWasmTruncateToInt64(LWasmTruncateToInt64* ins);
|
||||
|
||||
// Out of line visitors.
|
||||
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 js
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
_(AsmJSAtomicExchangeCallout) \
|
||||
_(AsmJSAtomicBinopCallout) \
|
||||
_(DivOrModI64) \
|
||||
_(UDivOrModI64)
|
||||
_(UDivOrModI64) \
|
||||
_(WasmTruncateToInt64)
|
||||
|
||||
#endif /* jit_arm_LOpcodes_arm_h */
|
||||
|
|
|
@ -915,7 +915,10 @@ LIRGeneratorARM::visitRandom(MRandom* ins)
|
|||
void
|
||||
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
|
||||
|
|
|
@ -2287,6 +2287,7 @@ typedef double (*Prototype_Double_None)();
|
|||
typedef double (*Prototype_Double_Double)(double arg0);
|
||||
typedef double (*Prototype_Double_Int)(int32_t 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_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
|
||||
int32_t arg3);
|
||||
|
@ -2429,6 +2430,16 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
|||
setCallResult(result);
|
||||
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: {
|
||||
Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
|
||||
double dresult = target();
|
||||
|
|
Загрузка…
Ссылка в новой задаче