[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"); BAILOUT("PushCallerFrameSlot");
} }
void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg) { void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
ValueType type) {
BAILOUT("PushCallerFrameSlot reg"); BAILOUT("PushCallerFrameSlot reg");
} }

View File

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

View File

@ -684,15 +684,20 @@ void LiftoffAssembler::PushCallerFrameSlot(const VarState& src,
RegPairHalf half) { RegPairHalf half) {
switch (src.loc()) { switch (src.loc()) {
case VarState::kStack: case VarState::kStack:
DCHECK_NE(kWasmF64, src.type()); // TODO(clemensh): Implement this.
push(liftoff::GetHalfStackSlot(2 * src_index + push(liftoff::GetHalfStackSlot(2 * src_index +
(half == kLowWord ? 0 : 1))); (half == kLowWord ? 0 : 1)));
if (src.type() == kWasmF64) {
DCHECK_EQ(kLowWord, half);
push(liftoff::GetHalfStackSlot(2 * src_index + 1));
}
break; break;
case VarState::kRegister: case VarState::kRegister:
PushCallerFrameSlot( if (src.type() == kWasmI64) {
src.type() == kWasmI64 PushCallerFrameSlot(
? (half == kLowWord ? src.reg().low() : src.reg().high()) half == kLowWord ? src.reg().low() : src.reg().high(), kWasmI32);
: src.reg()); } else {
PushCallerFrameSlot(src.reg(), src.type());
}
break; break;
case VarState::KIntConst: case VarState::KIntConst:
// The high word is the sign extension of the low word. // 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) { void LiftoffAssembler::PushCallerFrameSlot(LiftoffRegister reg,
if (reg.is_gp()) { ValueType type) {
push(reg.gp()); switch (type) {
} else { case kWasmI32:
sub(esp, Immediate(kPointerSize)); push(reg.gp());
movss(Operand(esp, 0), reg.fp()); 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); kWasmIntPtr);
*target = new_target.gp(); *target = new_target.gp();
} else { } else {
PushCallerFrameSlot(LiftoffRegister(*target)); PushCallerFrameSlot(LiftoffRegister(*target), kWasmIntPtr);
*target = no_reg; *target = no_reg;
} }
} }
@ -594,8 +594,9 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src,
ValueType type) { ValueType type) {
DCHECK_EQ(dst.reg_class(), src.reg_class()); DCHECK_EQ(dst.reg_class(), src.reg_class());
if (kNeedI64RegPair && dst.is_pair()) { if (kNeedI64RegPair && dst.is_pair()) {
if (dst.low() != src.low()) Move(dst.low_gp(), src.low_gp(), kWasmI32); // Use the {StackTransferRecipe} to move pairs, as the registers in the
if (dst.high() != src.high()) Move(dst.high_gp(), src.high_gp(), kWasmI32); // pairs might overlap.
StackTransferRecipe(this).MoveRegister(dst, src, type);
} else if (dst.is_gp()) { } else if (dst.is_gp()) {
Move(dst.gp(), src.gp(), type); Move(dst.gp(), src.gp(), type);
} else { } else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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