[Liftoff] Allow f64 parameters and arguments

This allows liftoff compiled functions to receive f64 values as
parameters and pass f64 values as arguments to called functions.

R=titzer@chromium.org

Bug: v8:6600
Change-Id: Ie7467b424ccdf1ec8b7f7625d9439ab4ea427022
Reviewed-on: https://chromium-review.googlesource.com/926105
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51414}
This commit is contained in:
Clemens Hammacher 2018-02-20 21:08:51 +01:00 committed by Commit Bot
parent 3b9d548c65
commit a65e007623
11 changed files with 73 additions and 34 deletions

View File

@ -173,7 +173,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -173,7 +173,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -684,15 +684,20 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
RegPairHalf half) {
switch (src.loc()) {
case VarState::kStack:
DCHECK_NE(kWasmF64, src.type()); // TODO(clemensh): Implement this.
push(liftoff::GetHalfStackSlot(2 * src_index +
(half == kLowWord ? 0 : 1)));
if (src.type() == kWasmF64) {
DCHECK_EQ(kLowWord, half);
push(liftoff::GetHalfStackSlot(2 * src_index + 1));
}
break;
case VarState::kRegister:
PushCallerFrameSlot(
src.type() == kWasmI64
? (half == kLowWord ? src.reg().low() : src.reg().high())
: src.reg());
if (src.type() == kWasmI64) {
PushCallerFrameSlot(
half == kLowWord ? src.reg().low() : src.reg().high(), kWasmI32);
} else {
PushCallerFrameSlot(src.reg(), src.type());
}
break;
case VarState::KIntConst:
// The high word is the sign extension of the low word.
@ -702,12 +707,23 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
}
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
if (reg.is_gp()) {
push(reg.gp());
} else {
sub(esp, Immediate(kPointerSize));
movss(Operand(esp, 0), reg.fp());
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
switch (type) {
case kWasmI32:
push(reg.gp());
break;
case kWasmF32:
sub(esp, Immediate(sizeof(float)));
movss(Operand(esp, 0), reg.fp());
break;
case kWasmF64:
sub(esp, Immediate(sizeof(double)));
movsd(Operand(esp, 0), reg.fp());
break;
default:
// Also kWasmI64 is unreachable, as it will always be pushed as two halfs.
UNREACHABLE();
}
}

View File

@ -544,7 +544,7 @@ void LiftoffAssembler::PrepareCall(wasm::FunctionSig* sig,
kWasmIntPtr);
*target = new_target.gp();
} else {
PushCallerFrameSlot(LiftoffRegister(*target));
PushCallerFrameSlot(LiftoffRegister(*target), kWasmIntPtr);
*target = no_reg;
}
}
@ -594,8 +594,9 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src,
ValueType type) {
DCHECK_EQ(dst.reg_class(), src.reg_class());
if (kNeedI64RegPair && dst.is_pair()) {
if (dst.low() != src.low()) Move(dst.low_gp(), src.low_gp(), kWasmI32);
if (dst.high() != src.high()) Move(dst.high_gp(), src.high_gp(), kWasmI32);
// Use the {StackTransferRecipe} to move pairs, as the registers in the
// pairs might overlap.
StackTransferRecipe(this).MoveRegister(dst, src, type);
} else if (dst.is_gp()) {
Move(dst.gp(), src.gp(), type);
} else {

View File

@ -401,7 +401,7 @@ class LiftoffAssembler : public TurboAssembler {
// Push a value to the stack (will become a caller frame slot).
inline void PushCallerFrameSlot(const VarState& src, uint32_t src_index,
RegPairHalf half);
inline void PushCallerFrameSlot(LiftoffRegister reg);
inline void PushCallerFrameSlot(LiftoffRegister reg, ValueType type);
inline void PushRegisters(LiftoffRegList);
inline void PopRegisters(LiftoffRegList);

View File

@ -78,6 +78,8 @@ compiler::CallDescriptor* GetLoweredCallDescriptor(
constexpr ValueType kTypesArr_ilf[] = {kWasmI32, kWasmI64, kWasmF32};
constexpr Vector<const ValueType> kTypes_ilf = ArrayVector(kTypesArr_ilf);
constexpr ValueType kTypesArr_ilfd[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64};
constexpr Vector<const ValueType> kTypes_ilfd = ArrayVector(kTypesArr_ilfd);
class LiftoffCompiler {
public:
@ -284,7 +286,7 @@ class LiftoffCompiler {
uint32_t num_params =
static_cast<uint32_t>(decoder->sig_->parameter_count());
for (uint32_t i = 0; i < __ num_locals(); ++i) {
if (!CheckSupportedType(decoder, kTypes_ilf, __ local_type(i), "param"))
if (!CheckSupportedType(decoder, kTypes_ilfd, __ local_type(i), "param"))
return;
}
// Input 0 is the call target, the context is at 1.
@ -316,13 +318,15 @@ class LiftoffCompiler {
__ cache_state()->stack_state.emplace_back(kWasmI64, uint32_t{0});
break;
case kWasmF32:
case kWasmF64:
if (zero_double_reg.is_gp()) {
// Note: This might spill one of the registers used to hold
// parameters.
zero_double_reg = __ GetUnusedRegister(kFpReg);
__ LoadConstant(zero_double_reg, WasmValue(0.f));
// Zero is represented by the bit pattern 0 for both f32 and f64.
__ LoadConstant(zero_double_reg, WasmValue(0.));
}
__ PushRegister(kWasmF32, zero_double_reg);
__ PushRegister(type, zero_double_reg);
break;
default:
UNIMPLEMENTED();
@ -1011,7 +1015,8 @@ class LiftoffCompiler {
LiftoffAssembler::kWasmIntPtr);
} else {
DCHECK(param_loc.IsCallerFrameSlot());
__ PushCallerFrameSlot(LiftoffRegister(args[0]));
__ PushCallerFrameSlot(LiftoffRegister(args[0]),
LiftoffAssembler::kWasmIntPtr);
}
// Allocate the codegen zone if not done before.
@ -1099,7 +1104,7 @@ class LiftoffCompiler {
if (operand.sig->return_count() > 1)
return unsupported(decoder, "multi-return");
if (operand.sig->return_count() == 1 &&
!CheckSupportedType(decoder, kTypes_ilf, operand.sig->GetReturn(0),
!CheckSupportedType(decoder, kTypes_ilfd, operand.sig->GetReturn(0),
"return"))
return;
@ -1141,7 +1146,7 @@ class LiftoffCompiler {
if (operand.sig->return_count() > 1)
return unsupported(decoder, "multi-return");
if (operand.sig->return_count() == 1 &&
!CheckSupportedType(decoder, kTypes_ilf, operand.sig->GetReturn(0),
!CheckSupportedType(decoder, kTypes_ilfd, operand.sig->GetReturn(0),
"return"))
return;

View File

@ -261,7 +261,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -256,7 +256,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -173,7 +173,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -173,7 +173,8 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
BAILOUT("PushCallerFrameSlot");
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg");
}

View File

@ -620,7 +620,7 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
pushq(liftoff::GetStackSlot(src_index));
break;
case VarState::kRegister:
PushCallerFrameSlot(src.reg());
PushCallerFrameSlot(src.reg(), src.type());
break;
case VarState::KIntConst:
pushq(Immediate(src.i32_const()));
@ -628,12 +628,23 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
}
}
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) {
if (reg.is_gp()) {
pushq(reg.gp());
} else {
subp(rsp, Immediate(kPointerSize));
Movsd(Operand(rsp, 0), reg.fp());
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
switch (type) {
case kWasmI32:
case kWasmI64:
pushq(reg.gp());
break;
case kWasmF32:
subp(rsp, Immediate(kPointerSize));
Movss(Operand(rsp, 0), reg.fp());
break;
case kWasmF64:
subp(rsp, Immediate(kPointerSize));
Movsd(Operand(rsp, 0), reg.fp());
break;
default:
UNREACHABLE();
}
}