Revert "[turbofan] Implement on-stack returns (Intel)"
This reverts commit 1e49864fa7
.
Reason for revert: Crashing test on the waterfall https://logs.chromium.org/v/?s=chromium%2Fbb%2Fclient.v8%2FV8_Linux_gcc_4.8%2F16871%2F%2B%2Frecipes%2Fsteps%2FCheck%2F0%2Flogs%2FReturnMultipleRandom%2F0
Original change's description:
> [turbofan] Implement on-stack returns (Intel)
>
> Add the ability to return (multiple) return values on the stack:
>
> - Extend stack frames with a new buffer region for return slots.
> This region is located at the end of a caller's frame such that
> its slots can be indexed as caller frame slots in a callee
> (located beyond its parameters) and assigned return values.
> - Adjust stack frame constructon and deconstruction accordingly.
> - Extend linkage computation to support register plus stack returns.
> - Reserve return slots in caller frame when respective calls occur.
> - Introduce and generate architecture instructions ('peek') for
> reading back results from return slots in the caller.
> - Aggressive tests.
> - Some minor clean-up.
>
> So far, only ia32 and x64 are implemented.
>
> Change-Id: I9532ad13aa307c1dec40548c5b84600fe2f762ce
> Reviewed-on: https://chromium-review.googlesource.com/766371
> Commit-Queue: Andreas Haas <ahaas@chromium.org>
> Reviewed-by: Ben Titzer <titzer@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49994}
TBR=titzer@chromium.org,rossberg@chromium.org,ahaas@chromium.org
Change-Id: Ib257e92448942f8ef07d5ef246f9381f4784f014
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/819637
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50000}
This commit is contained in:
parent
e55f3ce64f
commit
943ccb9895
@ -1596,27 +1596,22 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke any stack arguments.
|
||||
for (size_t n = 0; n < arguments->size(); ++n) {
|
||||
PushParameter input = (*arguments)[n];
|
||||
if (input.node) {
|
||||
if (input.node()) {
|
||||
int slot = static_cast<int>(n);
|
||||
Emit(kArmPoke | MiscField::encode(slot), g.NoOutput(),
|
||||
g.UseRegister(input.node));
|
||||
g.UseRegister(input.node()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Push any stack arguments.
|
||||
for (PushParameter input : base::Reversed(*arguments)) {
|
||||
// Skip any alignment holes in pushed nodes.
|
||||
if (input.node == nullptr) continue;
|
||||
Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node));
|
||||
if (input.node() == nullptr) continue;
|
||||
Emit(kArmPush, g.NoOutput(), g.UseRegister(input.node()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
// TODO(ahaas): Port.
|
||||
}
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
|
||||
|
||||
|
@ -1805,7 +1805,7 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke the arguments into the stack.
|
||||
ArchOpcode poke = to_native_stack ? kArm64PokeCSP : kArm64PokeJSSP;
|
||||
while (slot >= 0) {
|
||||
Emit(poke, g.NoOutput(), g.UseRegister((*arguments)[slot].node),
|
||||
Emit(poke, g.NoOutput(), g.UseRegister((*arguments)[slot].node()),
|
||||
g.TempImmediate(slot));
|
||||
slot--;
|
||||
// TODO(ahaas): Poke arguments in pairs if two subsequent arguments have the
|
||||
@ -1816,11 +1816,6 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
// TODO(ahaas): Port.
|
||||
}
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
|
||||
|
||||
|
@ -13,10 +13,8 @@ namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
Frame::Frame(int fixed_frame_size_in_slots)
|
||||
: fixed_slot_count_(fixed_frame_size_in_slots),
|
||||
frame_slot_count_(fixed_frame_size_in_slots),
|
||||
: frame_slot_count_(fixed_frame_size_in_slots),
|
||||
spill_slot_count_(0),
|
||||
return_slot_count_(0),
|
||||
allocated_registers_(nullptr),
|
||||
allocated_double_registers_(nullptr) {}
|
||||
|
||||
|
@ -22,7 +22,7 @@ class CallDescriptor;
|
||||
// into them. Mutable state associated with the frame is stored separately in
|
||||
// FrameAccessState.
|
||||
//
|
||||
// Frames are divided up into four regions.
|
||||
// Frames are divided up into three regions.
|
||||
// - The first is the fixed header, which always has a constant size and can be
|
||||
// predicted before code generation begins depending on the type of code being
|
||||
// generated.
|
||||
@ -33,15 +33,11 @@ class CallDescriptor;
|
||||
// reserved after register allocation, since its size can only be precisely
|
||||
// determined after register allocation once the number of used callee-saved
|
||||
// register is certain.
|
||||
// - The fourth region is a scratch area for return values from other functions
|
||||
// called, if multiple returns cannot all be passed in registers. This region
|
||||
// Must be last in a stack frame, so that it is positioned immediately below
|
||||
// the stack frame of a callee to store to.
|
||||
//
|
||||
// The frame region immediately below the fixed header contains spill slots
|
||||
// starting at slot 4 for JSFunctions. The callee-saved frame region below that
|
||||
// starts at 4+spill_slot_count_. Callee stack slots correspond to
|
||||
// parameters that are accessible through negative slot ids.
|
||||
// starts at 4+spill_slot_count_. Callee stack slots corresponding to
|
||||
// parameters are accessible through negative slot ids.
|
||||
//
|
||||
// Every slot of a caller or callee frame is accessible by the register
|
||||
// allocator and gap resolver with a SpillSlotOperand containing its
|
||||
@ -77,13 +73,7 @@ class CallDescriptor;
|
||||
// |- - - - - - - - -| | |
|
||||
// | ... | Callee-saved |
|
||||
// |- - - - - - - - -| | |
|
||||
// m+r+3 | callee-saved r | v |
|
||||
// +-----------------+---- |
|
||||
// m+r+4 | return 0 | ^ |
|
||||
// |- - - - - - - - -| | |
|
||||
// | ... | Return |
|
||||
// |- - - - - - - - -| | |
|
||||
// | return q-1 | v v
|
||||
// m+r+3 | callee-saved r | v v
|
||||
// -----+-----------------+----- <-- stack ptr -------------
|
||||
//
|
||||
class Frame : public ZoneObject {
|
||||
@ -91,9 +81,8 @@ class Frame : public ZoneObject {
|
||||
explicit Frame(int fixed_frame_size_in_slots);
|
||||
|
||||
inline int GetTotalFrameSlotCount() const { return frame_slot_count_; }
|
||||
inline int GetFixedSlotCount() const { return fixed_slot_count_; }
|
||||
|
||||
inline int GetSpillSlotCount() const { return spill_slot_count_; }
|
||||
inline int GetReturnSlotCount() const { return return_slot_count_; }
|
||||
|
||||
void SetAllocatedRegisters(BitVector* regs) {
|
||||
DCHECK_NULL(allocated_registers_);
|
||||
@ -123,25 +112,19 @@ class Frame : public ZoneObject {
|
||||
}
|
||||
|
||||
int AllocateSpillSlot(int width, int alignment = 0) {
|
||||
DCHECK_EQ(frame_slot_count_,
|
||||
fixed_slot_count_ + spill_slot_count_ + return_slot_count_);
|
||||
int frame_slot_count_before = frame_slot_count_;
|
||||
if (alignment > kPointerSize) {
|
||||
// Slots are pointer sized, so alignment greater than a pointer size
|
||||
// requires allocating additional slots.
|
||||
width += alignment - kPointerSize;
|
||||
if (alignment <= kPointerSize) {
|
||||
AllocateAlignedFrameSlots(width);
|
||||
} else {
|
||||
// We need to allocate more place for spill slot
|
||||
// in case we need an aligned spill slot to be
|
||||
// able to properly align start of spill slot
|
||||
// and still have enough place to hold all the
|
||||
// data
|
||||
AllocateAlignedFrameSlots(width + alignment - kPointerSize);
|
||||
}
|
||||
AllocateAlignedFrameSlots(width);
|
||||
spill_slot_count_ += frame_slot_count_ - frame_slot_count_before;
|
||||
return frame_slot_count_ - return_slot_count_ - 1;
|
||||
}
|
||||
|
||||
void EnsureReturnSlots(int count) {
|
||||
if (count > return_slot_count_) {
|
||||
count -= return_slot_count_;
|
||||
frame_slot_count_ += count;
|
||||
return_slot_count_ += count;
|
||||
}
|
||||
return frame_slot_count_ - 1;
|
||||
}
|
||||
|
||||
int AlignFrame(int alignment = kDoubleSize);
|
||||
@ -169,10 +152,8 @@ class Frame : public ZoneObject {
|
||||
}
|
||||
|
||||
private:
|
||||
int fixed_slot_count_;
|
||||
int frame_slot_count_;
|
||||
int spill_slot_count_;
|
||||
int return_slot_count_;
|
||||
BitVector* allocated_registers_;
|
||||
BitVector* allocated_double_registers_;
|
||||
|
||||
|
@ -53,7 +53,7 @@ MoveOperands* Split(MoveOperands* move, MachineRepresentation smaller_rep,
|
||||
src_index = src_loc.register_code() * aliases;
|
||||
} else {
|
||||
src_index = src_loc.index();
|
||||
// For operands that occupy multiple slots, the index refers to the last
|
||||
// For operands that occuply multiple slots, the index refers to the last
|
||||
// slot. On little-endian architectures, we start at the high slot and use a
|
||||
// negative step so that register-to-slot moves are in the correct order.
|
||||
src_step = -slot_size;
|
||||
|
@ -2006,7 +2006,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
}
|
||||
break;
|
||||
case kIA32Poke: {
|
||||
int slot = MiscField::decode(instr->opcode());
|
||||
int const slot = MiscField::decode(instr->opcode());
|
||||
if (HasImmediateInput(instr, 0)) {
|
||||
__ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
|
||||
} else {
|
||||
@ -2014,27 +2014,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kIA32PeekFloat32: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ movss(i.OutputFloatRegister(), Operand(ebp, offset));
|
||||
break;
|
||||
}
|
||||
case kIA32PeekFloat64: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ movsd(i.OutputDoubleRegister(), Operand(ebp, offset));
|
||||
break;
|
||||
}
|
||||
case kIA32Peek: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ mov(i.OutputRegister(), Operand(ebp, offset));
|
||||
break;
|
||||
}
|
||||
case kSSEF32x4Splat: {
|
||||
DCHECK_EQ(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
|
||||
XMMRegister dst = i.OutputSimd128Register();
|
||||
@ -3514,9 +3493,8 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// Skip callee-saved and return slots, which are created below.
|
||||
// Skip callee-saved slots, which are pushed below.
|
||||
shrink_slots -= base::bits::CountPopulation(saves);
|
||||
shrink_slots -= frame()->GetReturnSlotCount();
|
||||
if (shrink_slots > 0) {
|
||||
__ sub(esp, Immediate(shrink_slots * kPointerSize));
|
||||
}
|
||||
@ -3528,11 +3506,6 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
if (((1 << i) & saves)) __ push(Register::from_code(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate return slots (located after callee-saved).
|
||||
if (frame()->GetReturnSlotCount() > 0) {
|
||||
__ sub(esp, Immediate(frame()->GetReturnSlotCount() * kPointerSize));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
@ -3541,10 +3514,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
const RegList saves = descriptor->CalleeSavedRegisters();
|
||||
// Restore registers.
|
||||
if (saves != 0) {
|
||||
const int returns = frame()->GetReturnSlotCount();
|
||||
if (returns != 0) {
|
||||
__ add(esp, Immediate(returns * kPointerSize));
|
||||
}
|
||||
for (int i = 0; i < Register::kNumRegisters; i++) {
|
||||
if (!((1 << i) & saves)) continue;
|
||||
__ pop(Register::from_code(i));
|
||||
|
@ -111,9 +111,6 @@ namespace compiler {
|
||||
V(IA32PushFloat32) \
|
||||
V(IA32PushFloat64) \
|
||||
V(IA32Poke) \
|
||||
V(IA32Peek) \
|
||||
V(IA32PeekFloat32) \
|
||||
V(IA32PeekFloat64) \
|
||||
V(IA32StackCheck) \
|
||||
V(SSEF32x4Splat) \
|
||||
V(AVXF32x4Splat) \
|
||||
|
@ -263,9 +263,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
return instr->HasOutput() ? kIsLoadOperation : kHasSideEffect;
|
||||
|
||||
case kIA32StackCheck:
|
||||
case kIA32Peek:
|
||||
case kIA32PeekFloat32:
|
||||
case kIA32PeekFloat64:
|
||||
return kIsLoadOperation;
|
||||
|
||||
case kIA32Push:
|
||||
|
@ -1114,11 +1114,11 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke any stack arguments.
|
||||
for (size_t n = 0; n < arguments->size(); ++n) {
|
||||
PushParameter input = (*arguments)[n];
|
||||
if (input.node) {
|
||||
if (input.node()) {
|
||||
int const slot = static_cast<int>(n);
|
||||
InstructionOperand value = g.CanBeImmediate(node)
|
||||
? g.UseImmediate(input.node)
|
||||
: g.UseRegister(input.node);
|
||||
? g.UseImmediate(input.node())
|
||||
: g.UseRegister(input.node());
|
||||
Emit(kIA32Poke | MiscField::encode(slot), g.NoOutput(), value);
|
||||
}
|
||||
}
|
||||
@ -1127,27 +1127,28 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
int effect_level = GetEffectLevel(node);
|
||||
for (PushParameter input : base::Reversed(*arguments)) {
|
||||
// Skip any alignment holes in pushed nodes.
|
||||
if (input.node == nullptr) continue;
|
||||
if (g.CanBeMemoryOperand(kIA32Push, node, input.node, effect_level)) {
|
||||
Node* input_node = input.node();
|
||||
if (input.node() == nullptr) continue;
|
||||
if (g.CanBeMemoryOperand(kIA32Push, node, input_node, effect_level)) {
|
||||
InstructionOperand outputs[1];
|
||||
InstructionOperand inputs[4];
|
||||
size_t input_count = 0;
|
||||
InstructionCode opcode = kIA32Push;
|
||||
AddressingMode mode = g.GetEffectiveAddressMemoryOperand(
|
||||
input.node, inputs, &input_count);
|
||||
input_node, inputs, &input_count);
|
||||
opcode |= AddressingModeField::encode(mode);
|
||||
Emit(opcode, 0, outputs, input_count, inputs);
|
||||
} else {
|
||||
InstructionOperand value =
|
||||
g.CanBeImmediate(input.node)
|
||||
? g.UseImmediate(input.node)
|
||||
g.CanBeImmediate(input.node())
|
||||
? g.UseImmediate(input.node())
|
||||
: IsSupported(ATOM) ||
|
||||
sequence()->IsFP(GetVirtualRegister(input.node))
|
||||
? g.UseRegister(input.node)
|
||||
: g.Use(input.node);
|
||||
if (input.location.GetType() == MachineType::Float32()) {
|
||||
sequence()->IsFP(GetVirtualRegister(input.node()))
|
||||
? g.UseRegister(input.node())
|
||||
: g.Use(input.node());
|
||||
if (input.type() == MachineType::Float32()) {
|
||||
Emit(kIA32PushFloat32, g.NoOutput(), value);
|
||||
} else if (input.location.GetType() == MachineType::Float64()) {
|
||||
} else if (input.type() == MachineType::Float64()) {
|
||||
Emit(kIA32PushFloat64, g.NoOutput(), value);
|
||||
} else {
|
||||
Emit(kIA32Push, g.NoOutput(), value);
|
||||
@ -1157,33 +1158,6 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
IA32OperandGenerator g(this);
|
||||
|
||||
int reverse_slot = 0;
|
||||
for (PushParameter output : *results) {
|
||||
if (!output.location.IsCallerFrameSlot()) continue;
|
||||
reverse_slot += output.location.GetSizeInPointers();
|
||||
// Skip any alignment holes in nodes.
|
||||
if (output.node == nullptr) continue;
|
||||
DCHECK(!descriptor->IsCFunctionCall());
|
||||
if (output.location.GetType() == MachineType::Float32()) {
|
||||
MarkAsFloat32(output.node);
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kIA32PeekFloat32 | MiscField::encode(reverse_slot), result);
|
||||
} else if (output.location.GetType() == MachineType::Float64()) {
|
||||
MarkAsFloat64(output.node);
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kIA32PeekFloat64 | MiscField::encode(reverse_slot - 1), result);
|
||||
} else {
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kIA32Peek | MiscField::encode(reverse_slot), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
|
||||
|
||||
|
@ -668,7 +668,7 @@ struct CallBuffer {
|
||||
|
||||
const CallDescriptor* descriptor;
|
||||
FrameStateDescriptor* frame_state_descriptor;
|
||||
ZoneVector<PushParameter> output_nodes;
|
||||
NodeVector output_nodes;
|
||||
InstructionOperandVector outputs;
|
||||
InstructionOperandVector instruction_args;
|
||||
ZoneVector<PushParameter> pushed_nodes;
|
||||
@ -702,28 +702,17 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
if (buffer->descriptor->ReturnCount() > 0) {
|
||||
// Collect the projections that represent multiple outputs from this call.
|
||||
if (buffer->descriptor->ReturnCount() == 1) {
|
||||
PushParameter result = {call, buffer->descriptor->GetReturnLocation(0)};
|
||||
buffer->output_nodes.push_back(result);
|
||||
buffer->output_nodes.push_back(call);
|
||||
} else {
|
||||
buffer->output_nodes.resize(buffer->descriptor->ReturnCount());
|
||||
int stack_count = 0;
|
||||
buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), nullptr);
|
||||
for (Edge const edge : call->use_edges()) {
|
||||
if (!NodeProperties::IsValueEdge(edge)) continue;
|
||||
Node* node = edge.from();
|
||||
DCHECK_EQ(IrOpcode::kProjection, node->opcode());
|
||||
size_t const index = ProjectionIndexOf(node->op());
|
||||
|
||||
DCHECK_EQ(IrOpcode::kProjection, edge.from()->opcode());
|
||||
size_t const index = ProjectionIndexOf(edge.from()->op());
|
||||
DCHECK_LT(index, buffer->output_nodes.size());
|
||||
DCHECK(!buffer->output_nodes[index].node);
|
||||
PushParameter result = {node,
|
||||
buffer->descriptor->GetReturnLocation(index)};
|
||||
buffer->output_nodes[index] = result;
|
||||
|
||||
if (result.location.IsCallerFrameSlot()) {
|
||||
stack_count += result.location.GetSizeInPointers();
|
||||
}
|
||||
DCHECK(!buffer->output_nodes[index]);
|
||||
buffer->output_nodes[index] = edge.from();
|
||||
}
|
||||
frame_->EnsureReturnSlots(stack_count);
|
||||
}
|
||||
|
||||
// Filter out the outputs that aren't live because no projection uses them.
|
||||
@ -733,22 +722,22 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
: buffer->frame_state_descriptor->state_combine()
|
||||
.ConsumedOutputCount();
|
||||
for (size_t i = 0; i < buffer->output_nodes.size(); i++) {
|
||||
bool output_is_live = buffer->output_nodes[i].node != nullptr ||
|
||||
bool output_is_live = buffer->output_nodes[i] != nullptr ||
|
||||
i < outputs_needed_by_framestate;
|
||||
if (output_is_live) {
|
||||
LinkageLocation location = buffer->output_nodes[i].location;
|
||||
MachineRepresentation rep = location.GetType().representation();
|
||||
MachineRepresentation rep =
|
||||
buffer->descriptor->GetReturnType(static_cast<int>(i))
|
||||
.representation();
|
||||
LinkageLocation location =
|
||||
buffer->descriptor->GetReturnLocation(static_cast<int>(i));
|
||||
|
||||
Node* output = buffer->output_nodes[i].node;
|
||||
Node* output = buffer->output_nodes[i];
|
||||
InstructionOperand op = output == nullptr
|
||||
? g.TempLocation(location)
|
||||
: g.DefineAsLocation(output, location);
|
||||
MarkAsRepresentation(rep, op);
|
||||
|
||||
if (!UnallocatedOperand::cast(op).HasFixedSlotPolicy()) {
|
||||
buffer->outputs.push_back(op);
|
||||
buffer->output_nodes[i].node = nullptr;
|
||||
}
|
||||
buffer->outputs.push_back(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -853,8 +842,8 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
if (static_cast<size_t>(stack_index) >= buffer->pushed_nodes.size()) {
|
||||
buffer->pushed_nodes.resize(stack_index + 1);
|
||||
}
|
||||
PushParameter param = {*iter, location};
|
||||
buffer->pushed_nodes[stack_index] = param;
|
||||
PushParameter parameter(*iter, buffer->descriptor->GetInputType(index));
|
||||
buffer->pushed_nodes[stack_index] = parameter;
|
||||
pushed_count++;
|
||||
} else {
|
||||
buffer->instruction_args.push_back(op);
|
||||
@ -2444,8 +2433,6 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
|
||||
&buffer.instruction_args.front());
|
||||
if (instruction_selection_failed()) return;
|
||||
call_instr->MarkAsCall();
|
||||
|
||||
EmitPrepareResults(&(buffer.output_nodes), descriptor, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitCallWithCallerSavedRegisters(
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/instruction-scheduler.h"
|
||||
#include "src/compiler/instruction.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/globals.h"
|
||||
@ -31,13 +30,17 @@ class StateObjectDeduplicator;
|
||||
|
||||
// This struct connects nodes of parameters which are going to be pushed on the
|
||||
// call stack with their parameter index in the call descriptor of the callee.
|
||||
struct PushParameter {
|
||||
PushParameter(Node* n = nullptr,
|
||||
LinkageLocation l = LinkageLocation::ForAnyRegister())
|
||||
: node(n), location(l) {}
|
||||
class PushParameter {
|
||||
public:
|
||||
PushParameter() : node_(nullptr), type_(MachineType::None()) {}
|
||||
PushParameter(Node* node, MachineType type) : node_(node), type_(type) {}
|
||||
|
||||
Node* node;
|
||||
LinkageLocation location;
|
||||
Node* node() const { return node_; }
|
||||
MachineType type() const { return type_; }
|
||||
|
||||
private:
|
||||
Node* node_;
|
||||
MachineType type_;
|
||||
};
|
||||
|
||||
enum class FrameStateInputKind { kAny, kStackSlot };
|
||||
@ -350,8 +353,6 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
|
||||
|
||||
void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
|
||||
const CallDescriptor* descriptor, Node* node);
|
||||
void EmitPrepareResults(ZoneVector<compiler::PushParameter>* results,
|
||||
const CallDescriptor* descriptor, Node* node);
|
||||
|
||||
void EmitIdentity(Node* node);
|
||||
bool CanProduceSignalingNaN(Node* node);
|
||||
|
@ -316,10 +316,9 @@ void Int64Lowering::LowerNode(Node* node) {
|
||||
case IrOpcode::kTailCall: {
|
||||
CallDescriptor* descriptor =
|
||||
const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
|
||||
bool returns_require_lowering =
|
||||
GetReturnCountAfterLowering(descriptor) !=
|
||||
static_cast<int>(descriptor->ReturnCount());
|
||||
if (DefaultLowering(node) || returns_require_lowering) {
|
||||
if (DefaultLowering(node) ||
|
||||
(descriptor->ReturnCount() == 1 &&
|
||||
descriptor->GetReturnType(0) == MachineType::Int64())) {
|
||||
// Tail calls do not have return values, so adjusting the call
|
||||
// descriptor is enough.
|
||||
auto new_descriptor = GetI32WasmCallDescriptor(zone(), descriptor);
|
||||
|
@ -197,14 +197,12 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
RegList callee_saved_registers,
|
||||
RegList callee_saved_fp_registers, Flags flags,
|
||||
const char* debug_name = "",
|
||||
const RegList allocatable_registers = 0,
|
||||
size_t stack_return_count = 0)
|
||||
const RegList allocatable_registers = 0)
|
||||
: kind_(kind),
|
||||
target_type_(target_type),
|
||||
target_loc_(target_loc),
|
||||
location_sig_(location_sig),
|
||||
stack_param_count_(stack_param_count),
|
||||
stack_return_count_(stack_return_count),
|
||||
properties_(properties),
|
||||
callee_saved_registers_(callee_saved_registers),
|
||||
callee_saved_fp_registers_(callee_saved_fp_registers),
|
||||
@ -234,9 +232,6 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
// The number of stack parameters to the call.
|
||||
size_t StackParameterCount() const { return stack_param_count_; }
|
||||
|
||||
// The number of stack return values from the call.
|
||||
size_t StackReturnCount() const { return stack_return_count_; }
|
||||
|
||||
// The number of parameters to the JS function call.
|
||||
size_t JSParameterCount() const {
|
||||
DCHECK(IsJSFunctionCall());
|
||||
@ -323,7 +318,6 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
const LinkageLocation target_loc_;
|
||||
const LocationSignature* const location_sig_;
|
||||
const size_t stack_param_count_;
|
||||
const size_t stack_return_count_;
|
||||
const Operator::Properties properties_;
|
||||
const RegList callee_saved_registers_;
|
||||
const RegList callee_saved_fp_registers_;
|
||||
|
@ -1181,8 +1181,8 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke any stack arguments.
|
||||
int slot = kCArgSlotCount;
|
||||
for (PushParameter input : (*arguments)) {
|
||||
if (input.node) {
|
||||
Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node),
|
||||
if (input.node()) {
|
||||
Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
|
||||
g.TempImmediate(slot << kPointerSizeLog2));
|
||||
++slot;
|
||||
}
|
||||
@ -1196,19 +1196,14 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
}
|
||||
for (size_t n = 0; n < arguments->size(); ++n) {
|
||||
PushParameter input = (*arguments)[n];
|
||||
if (input.node) {
|
||||
Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node),
|
||||
if (input.node()) {
|
||||
Emit(kMipsStoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
|
||||
g.TempImmediate(n << kPointerSizeLog2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
// TODO(ahaas): Port.
|
||||
}
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
|
||||
|
||||
|
@ -1676,7 +1676,7 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke any stack arguments.
|
||||
int slot = kCArgSlotCount;
|
||||
for (PushParameter input : (*arguments)) {
|
||||
Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node),
|
||||
Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
|
||||
g.TempImmediate(slot << kPointerSizeLog2));
|
||||
++slot;
|
||||
}
|
||||
@ -1688,19 +1688,14 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
}
|
||||
for (size_t n = 0; n < arguments->size(); ++n) {
|
||||
PushParameter input = (*arguments)[n];
|
||||
if (input.node) {
|
||||
Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node),
|
||||
if (input.node()) {
|
||||
Emit(kMips64StoreToStackSlot, g.NoOutput(), g.UseRegister(input.node()),
|
||||
g.TempImmediate(static_cast<int>(n << kPointerSizeLog2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
// TODO(ahaas): Port.
|
||||
}
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
|
||||
|
||||
|
@ -134,6 +134,7 @@ void RawMachineAssembler::Return(Node* value) {
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void RawMachineAssembler::Return(Node* v1, Node* v2) {
|
||||
Node* values[] = {Int32Constant(0), v1, v2};
|
||||
Node* ret = MakeNode(common()->Return(2), 3, values);
|
||||
@ -141,6 +142,7 @@ void RawMachineAssembler::Return(Node* v1, Node* v2) {
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3) {
|
||||
Node* values[] = {Int32Constant(0), v1, v2, v3};
|
||||
Node* ret = MakeNode(common()->Return(3), 4, values);
|
||||
@ -148,24 +150,6 @@ void RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3) {
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
void RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3, Node* v4) {
|
||||
Node* values[] = {Int32Constant(0), v1, v2, v3, v4};
|
||||
Node* ret = MakeNode(common()->Return(4), 5, values);
|
||||
schedule()->AddReturn(CurrentBlock(), ret);
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
void RawMachineAssembler::Return(int count, Node* vs[]) {
|
||||
typedef Node* Node_ptr;
|
||||
Node** values = new Node_ptr[count + 1];
|
||||
values[0] = Int32Constant(0);
|
||||
for (int i = 0; i < count; ++i) values[i + 1] = vs[i];
|
||||
Node* ret = MakeNode(common()->Return(count), count + 1, values);
|
||||
schedule()->AddReturn(CurrentBlock(), ret);
|
||||
current_block_ = nullptr;
|
||||
delete[] values;
|
||||
}
|
||||
|
||||
void RawMachineAssembler::PopAndReturn(Node* pop, Node* value) {
|
||||
Node* values[] = {pop, value};
|
||||
Node* ret = MakeNode(common()->Return(1), 2, values);
|
||||
@ -188,14 +172,6 @@ void RawMachineAssembler::PopAndReturn(Node* pop, Node* v1, Node* v2,
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
void RawMachineAssembler::PopAndReturn(Node* pop, Node* v1, Node* v2, Node* v3,
|
||||
Node* v4) {
|
||||
Node* values[] = {pop, v1, v2, v3, v4};
|
||||
Node* ret = MakeNode(common()->Return(4), 5, values);
|
||||
schedule()->AddReturn(CurrentBlock(), ret);
|
||||
current_block_ = nullptr;
|
||||
}
|
||||
|
||||
void RawMachineAssembler::DebugAbort(Node* message) {
|
||||
AddNode(machine()->DebugAbort(), message);
|
||||
}
|
||||
|
@ -828,12 +828,9 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
|
||||
void Return(Node* value);
|
||||
void Return(Node* v1, Node* v2);
|
||||
void Return(Node* v1, Node* v2, Node* v3);
|
||||
void Return(Node* v1, Node* v2, Node* v3, Node* v4);
|
||||
void Return(int count, Node* v[]);
|
||||
void PopAndReturn(Node* pop, Node* value);
|
||||
void PopAndReturn(Node* pop, Node* v1, Node* v2);
|
||||
void PopAndReturn(Node* pop, Node* v1, Node* v2, Node* v3);
|
||||
void PopAndReturn(Node* pop, Node* v1, Node* v2, Node* v3, Node* v4);
|
||||
void Bind(RawMachineLabel* label);
|
||||
void Deoptimize(Node* state);
|
||||
void DebugAbort(Node* message);
|
||||
|
@ -47,7 +47,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == ia32 ===================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS esi, eax, edx, ecx, ebx
|
||||
#define GP_RETURN_REGISTERS eax, edx
|
||||
#define GP_RETURN_REGISTERS eax, edx, ecx
|
||||
#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
|
||||
#define FP_RETURN_REGISTERS xmm1, xmm2
|
||||
|
||||
@ -56,7 +56,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == x64 ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS rsi, rax, rdx, rcx, rbx, rdi
|
||||
#define GP_RETURN_REGISTERS rax, rdx
|
||||
#define GP_RETURN_REGISTERS rax, rdx, rcx
|
||||
#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
|
||||
#define FP_RETURN_REGISTERS xmm1, xmm2
|
||||
|
||||
@ -65,7 +65,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == arm ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r3, r0, r1, r2
|
||||
#define GP_RETURN_REGISTERS r0, r1
|
||||
#define GP_RETURN_REGISTERS r0, r1, r3
|
||||
#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
|
||||
#define FP_RETURN_REGISTERS d0, d1
|
||||
|
||||
@ -74,7 +74,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == arm64 ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS x7, x0, x1, x2, x3, x4, x5, x6
|
||||
#define GP_RETURN_REGISTERS x0, x1
|
||||
#define GP_RETURN_REGISTERS x0, x1, x2
|
||||
#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
|
||||
#define FP_RETURN_REGISTERS d0, d1
|
||||
|
||||
@ -83,7 +83,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == mips ===================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS a0, a1, a2, a3
|
||||
#define GP_RETURN_REGISTERS v0, v1
|
||||
#define GP_RETURN_REGISTERS v0, v1, t7
|
||||
#define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
|
||||
#define FP_RETURN_REGISTERS f2, f4
|
||||
|
||||
@ -92,7 +92,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == mips64 =================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
|
||||
#define GP_RETURN_REGISTERS v0, v1
|
||||
#define GP_RETURN_REGISTERS v0, v1, t3
|
||||
#define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
|
||||
#define FP_RETURN_REGISTERS f2, f4
|
||||
|
||||
@ -101,7 +101,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == ppc & ppc64 ============================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r10, r3, r4, r5, r6, r7, r8, r9
|
||||
#define GP_RETURN_REGISTERS r3, r4
|
||||
#define GP_RETURN_REGISTERS r3, r4, r5
|
||||
#define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
|
||||
#define FP_RETURN_REGISTERS d1, d2
|
||||
|
||||
@ -110,7 +110,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == s390x ==================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r6, r2, r3, r4, r5
|
||||
#define GP_RETURN_REGISTERS r2, r3
|
||||
#define GP_RETURN_REGISTERS r2, r3, r4
|
||||
#define FP_PARAM_REGISTERS d0, d2, d4, d6
|
||||
#define FP_RETURN_REGISTERS d0, d2, d4, d6
|
||||
|
||||
@ -119,7 +119,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == s390 ===================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r6, r2, r3, r4, r5
|
||||
#define GP_RETURN_REGISTERS r2, r3
|
||||
#define GP_RETURN_REGISTERS r2, r3, r4
|
||||
#define FP_PARAM_REGISTERS d0, d2
|
||||
#define FP_RETURN_REGISTERS d0, d2
|
||||
|
||||
@ -158,8 +158,6 @@ struct Allocator {
|
||||
|
||||
int stack_offset;
|
||||
|
||||
void AdjustStackOffset(int offset) { stack_offset += offset; }
|
||||
|
||||
LinkageLocation Next(ValueType type) {
|
||||
if (IsFloatingPoint(type)) {
|
||||
// Allocate a floating point register/stack location.
|
||||
@ -228,28 +226,25 @@ CallDescriptor* GetWasmCallDescriptor(Zone* zone, wasm::FunctionSig* fsig) {
|
||||
LocationSignature::Builder locations(zone, fsig->return_count(),
|
||||
fsig->parameter_count() + 1);
|
||||
|
||||
// Add register and/or stack parameter(s).
|
||||
Allocator params = parameter_registers;
|
||||
|
||||
// The wasm_context.
|
||||
locations.AddParam(params.Next(MachineType::PointerRepresentation()));
|
||||
|
||||
const int parameter_count = static_cast<int>(fsig->parameter_count());
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
ValueType param = fsig->GetParam(i);
|
||||
auto l = params.Next(param);
|
||||
locations.AddParam(l);
|
||||
}
|
||||
Allocator rets = return_registers;
|
||||
|
||||
// Add return location(s).
|
||||
Allocator rets = return_registers;
|
||||
rets.AdjustStackOffset(params.stack_offset);
|
||||
|
||||
const int return_count = static_cast<int>(locations.return_count_);
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
ValueType ret = fsig->GetReturn(i);
|
||||
auto l = rets.Next(ret);
|
||||
locations.AddReturn(l);
|
||||
locations.AddReturn(rets.Next(ret));
|
||||
}
|
||||
|
||||
Allocator params = parameter_registers;
|
||||
|
||||
// Add parameter for the wasm_context.
|
||||
locations.AddParam(params.Next(MachineType::PointerRepresentation()));
|
||||
|
||||
// Add register and/or stack parameter(s).
|
||||
const int parameter_count = static_cast<int>(fsig->parameter_count());
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
ValueType param = fsig->GetParam(i);
|
||||
locations.AddParam(params.Next(param));
|
||||
}
|
||||
|
||||
const RegList kCalleeSaveRegisters = 0;
|
||||
@ -265,19 +260,17 @@ CallDescriptor* GetWasmCallDescriptor(Zone* zone, wasm::FunctionSig* fsig) {
|
||||
? CallDescriptor::kCallWasmFunction
|
||||
: CallDescriptor::kCallCodeObject;
|
||||
|
||||
return new (zone) CallDescriptor( // --
|
||||
kind, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
params.stack_offset, // stack_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
flags, // flags
|
||||
"wasm-call", // debug name
|
||||
0, // allocatable registers
|
||||
rets.stack_offset - params.stack_offset); // stack_return_count
|
||||
return new (zone) CallDescriptor( // --
|
||||
kind, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
params.stack_offset, // stack_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
flags, // flags
|
||||
"wasm-call");
|
||||
}
|
||||
|
||||
CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
@ -302,20 +295,8 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
|
||||
LocationSignature::Builder locations(zone, return_count, parameter_count);
|
||||
|
||||
Allocator params = parameter_registers;
|
||||
for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
|
||||
if (descriptor->GetParameterType(i) == input_type) {
|
||||
for (size_t j = 0; j < num_replacements; j++) {
|
||||
locations.AddParam(params.Next(output_type));
|
||||
}
|
||||
} else {
|
||||
locations.AddParam(
|
||||
params.Next(descriptor->GetParameterType(i).representation()));
|
||||
}
|
||||
}
|
||||
|
||||
Allocator rets = return_registers;
|
||||
rets.AdjustStackOffset(params.stack_offset);
|
||||
|
||||
for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
|
||||
if (descriptor->GetReturnType(i) == input_type) {
|
||||
for (size_t j = 0; j < num_replacements; j++) {
|
||||
@ -327,19 +308,30 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
}
|
||||
}
|
||||
|
||||
return new (zone) CallDescriptor( // --
|
||||
descriptor->kind(), // kind
|
||||
descriptor->GetInputType(0), // target MachineType
|
||||
descriptor->GetInputLocation(0), // target location
|
||||
locations.Build(), // location_sig
|
||||
params.stack_offset, // stack_parameter_count
|
||||
descriptor->properties(), // properties
|
||||
descriptor->CalleeSavedRegisters(), // callee-saved registers
|
||||
descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
|
||||
descriptor->flags(), // flags
|
||||
descriptor->debug_name(), // debug name
|
||||
descriptor->AllocatableRegisters(), // allocatable registers
|
||||
rets.stack_offset - params.stack_offset); // stack_return_count
|
||||
Allocator params = parameter_registers;
|
||||
|
||||
for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
|
||||
if (descriptor->GetParameterType(i) == input_type) {
|
||||
for (size_t j = 0; j < num_replacements; j++) {
|
||||
locations.AddParam(params.Next(output_type));
|
||||
}
|
||||
} else {
|
||||
locations.AddParam(
|
||||
params.Next(descriptor->GetParameterType(i).representation()));
|
||||
}
|
||||
}
|
||||
|
||||
return new (zone) CallDescriptor( // --
|
||||
descriptor->kind(), // kind
|
||||
descriptor->GetInputType(0), // target MachineType
|
||||
descriptor->GetInputLocation(0), // target location
|
||||
locations.Build(), // location_sig
|
||||
params.stack_offset, // stack_parameter_count
|
||||
descriptor->properties(), // properties
|
||||
descriptor->CalleeSavedRegisters(), // callee-saved registers
|
||||
descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
|
||||
descriptor->flags(), // flags
|
||||
descriptor->debug_name());
|
||||
}
|
||||
|
||||
CallDescriptor* GetI32WasmCallDescriptor(Zone* zone,
|
||||
|
@ -2231,7 +2231,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
}
|
||||
break;
|
||||
case kX64Poke: {
|
||||
int slot = MiscField::decode(instr->opcode());
|
||||
int const slot = MiscField::decode(instr->opcode());
|
||||
if (HasImmediateInput(instr, 0)) {
|
||||
__ movq(Operand(rsp, slot * kPointerSize), i.InputImmediate(0));
|
||||
} else {
|
||||
@ -2239,27 +2239,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kX64PeekFloat32: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ Movss(i.OutputFloatRegister(), Operand(rbp, offset));
|
||||
break;
|
||||
}
|
||||
case kX64PeekFloat64: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ Movsd(i.OutputDoubleRegister(), Operand(rbp, offset));
|
||||
break;
|
||||
}
|
||||
case kX64Peek: {
|
||||
int reverse_slot = MiscField::decode(instr->opcode());
|
||||
int offset =
|
||||
FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
|
||||
__ movq(i.OutputRegister(), Operand(rbp, offset));
|
||||
break;
|
||||
}
|
||||
case kX64I32x4Splat: {
|
||||
XMMRegister dst = i.OutputSimd128Register();
|
||||
__ movd(dst, i.InputRegister(0));
|
||||
@ -3149,10 +3128,9 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
// Skip callee-saved and return slots, which are created below.
|
||||
// Skip callee-saved slots, which are pushed below.
|
||||
shrink_slots -= base::bits::CountPopulation(saves);
|
||||
shrink_slots -= base::bits::CountPopulation(saves_fp);
|
||||
shrink_slots -= frame()->GetReturnSlotCount();
|
||||
if (shrink_slots > 0) {
|
||||
__ subq(rsp, Immediate(shrink_slots * kPointerSize));
|
||||
}
|
||||
@ -3179,11 +3157,6 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ pushq(Register::from_code(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate return slots (located after callee-saved).
|
||||
if (frame()->GetReturnSlotCount() > 0) {
|
||||
__ subq(rsp, Immediate(frame()->GetReturnSlotCount() * kPointerSize));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
@ -3192,10 +3165,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
|
||||
// Restore registers.
|
||||
const RegList saves = descriptor->CalleeSavedRegisters();
|
||||
if (saves != 0) {
|
||||
const int returns = frame()->GetReturnSlotCount();
|
||||
if (returns != 0) {
|
||||
__ addq(rsp, Immediate(returns * kPointerSize));
|
||||
}
|
||||
for (int i = 0; i < Register::kNumRegisters; i++) {
|
||||
if (!((1 << i) & saves)) continue;
|
||||
__ popq(Register::from_code(i));
|
||||
|
@ -143,9 +143,6 @@ namespace compiler {
|
||||
V(X64Inc32) \
|
||||
V(X64Push) \
|
||||
V(X64Poke) \
|
||||
V(X64Peek) \
|
||||
V(X64PeekFloat32) \
|
||||
V(X64PeekFloat64) \
|
||||
V(X64StackCheck) \
|
||||
V(X64I32x4Splat) \
|
||||
V(X64I32x4ExtractLane) \
|
||||
|
@ -240,9 +240,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
return instr->HasOutput() ? kIsLoadOperation : kHasSideEffect;
|
||||
|
||||
case kX64StackCheck:
|
||||
case kX64Peek:
|
||||
case kX64PeekFloat32:
|
||||
case kX64PeekFloat64:
|
||||
return kIsLoadOperation;
|
||||
|
||||
case kX64Push:
|
||||
|
@ -1538,11 +1538,11 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Poke any stack arguments.
|
||||
for (size_t n = 0; n < arguments->size(); ++n) {
|
||||
PushParameter input = (*arguments)[n];
|
||||
if (input.node) {
|
||||
if (input.node()) {
|
||||
int slot = static_cast<int>(n);
|
||||
InstructionOperand value = g.CanBeImmediate(input.node)
|
||||
? g.UseImmediate(input.node)
|
||||
: g.UseRegister(input.node);
|
||||
InstructionOperand value = g.CanBeImmediate(input.node())
|
||||
? g.UseImmediate(input.node())
|
||||
: g.UseRegister(input.node());
|
||||
Emit(kX64Poke | MiscField::encode(slot), g.NoOutput(), value);
|
||||
}
|
||||
}
|
||||
@ -1550,56 +1550,31 @@ void InstructionSelector::EmitPrepareArguments(
|
||||
// Push any stack arguments.
|
||||
int effect_level = GetEffectLevel(node);
|
||||
for (PushParameter input : base::Reversed(*arguments)) {
|
||||
if (g.CanBeImmediate(input.node)) {
|
||||
Emit(kX64Push, g.NoOutput(), g.UseImmediate(input.node));
|
||||
Node* input_node = input.node();
|
||||
if (g.CanBeImmediate(input_node)) {
|
||||
Emit(kX64Push, g.NoOutput(), g.UseImmediate(input_node));
|
||||
} else if (IsSupported(ATOM) ||
|
||||
sequence()->IsFP(GetVirtualRegister(input.node))) {
|
||||
sequence()->IsFP(GetVirtualRegister(input_node))) {
|
||||
// TODO(titzer): X64Push cannot handle stack->stack double moves
|
||||
// because there is no way to encode fixed double slots.
|
||||
Emit(kX64Push, g.NoOutput(), g.UseRegister(input.node));
|
||||
} else if (g.CanBeMemoryOperand(kX64Push, node, input.node,
|
||||
Emit(kX64Push, g.NoOutput(), g.UseRegister(input_node));
|
||||
} else if (g.CanBeMemoryOperand(kX64Push, node, input_node,
|
||||
effect_level)) {
|
||||
InstructionOperand outputs[1];
|
||||
InstructionOperand inputs[4];
|
||||
size_t input_count = 0;
|
||||
InstructionCode opcode = kX64Push;
|
||||
AddressingMode mode = g.GetEffectiveAddressMemoryOperand(
|
||||
input.node, inputs, &input_count);
|
||||
input_node, inputs, &input_count);
|
||||
opcode |= AddressingModeField::encode(mode);
|
||||
Emit(opcode, 0, outputs, input_count, inputs);
|
||||
} else {
|
||||
Emit(kX64Push, g.NoOutput(), g.Use(input.node));
|
||||
Emit(kX64Push, g.NoOutput(), g.Use(input_node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareResults(ZoneVector<PushParameter>* results,
|
||||
const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
|
||||
int reverse_slot = 0;
|
||||
for (PushParameter output : *results) {
|
||||
if (!output.location.IsCallerFrameSlot()) continue;
|
||||
reverse_slot += output.location.GetSizeInPointers();
|
||||
// Skip any alignment holes in nodes.
|
||||
if (output.node == nullptr) continue;
|
||||
DCHECK(!descriptor->IsCFunctionCall());
|
||||
if (output.location.GetType() == MachineType::Float32()) {
|
||||
MarkAsFloat32(output.node);
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kX64PeekFloat32 | MiscField::encode(reverse_slot), result);
|
||||
} else if (output.location.GetType() == MachineType::Float64()) {
|
||||
MarkAsFloat64(output.node);
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kX64PeekFloat64 | MiscField::encode(reverse_slot), result);
|
||||
} else {
|
||||
InstructionOperand result = g.DefineAsRegister(output.node);
|
||||
Emit(kX64Peek | MiscField::encode(reverse_slot), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
|
||||
|
||||
|
@ -157,18 +157,6 @@
|
||||
'test-api/Float64Array': [SKIP],
|
||||
}], # 'arch == arm64 and mode == debug and simulator_run'
|
||||
|
||||
##############################################################################
|
||||
# TODO(ahaas): Port multiple retrn values to ARM and MIPS
|
||||
['arch == arm or arch == arm64 or arch == mips or arch == mips64 or arch == mipsel or arch == mips64el', {
|
||||
'test-multiple-return/*': [SKIP],
|
||||
}],
|
||||
['system == windows and arch == x64', {
|
||||
'test-multiple-return/ReturnMultipleInt32': [SKIP],
|
||||
'test-multiple-return/ReturnMultipleInt64': [SKIP],
|
||||
'test-multiple-return/ReturnMultipleFloat32': [SKIP],
|
||||
'test-multiple-return/ReturnMultipleFloat64': [SKIP],
|
||||
}],
|
||||
|
||||
##############################################################################
|
||||
['asan == True', {
|
||||
# Skip tests not suitable for ASAN.
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/bits.h"
|
||||
@ -13,7 +12,6 @@
|
||||
#include "src/codegen.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/machine-type.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
@ -26,455 +24,90 @@ namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
int index(MachineType type) { return static_cast<int>(type.representation()); }
|
||||
|
||||
int size(MachineType type) {
|
||||
return 1 << ElementSizeLog2Of(type.representation());
|
||||
}
|
||||
|
||||
bool is_float(MachineType type) {
|
||||
MachineRepresentation rep = type.representation();
|
||||
return rep == MachineRepresentation::kFloat32 ||
|
||||
rep == MachineRepresentation::kFloat64;
|
||||
}
|
||||
|
||||
int num_registers(MachineType type) {
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
case MachineRepresentation::kWord64:
|
||||
return config->num_allocatable_general_registers();
|
||||
case MachineRepresentation::kFloat32:
|
||||
return config->num_allocatable_float_registers();
|
||||
case MachineRepresentation::kFloat64:
|
||||
return config->num_allocatable_double_registers();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const int* codes(MachineType type) {
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
case MachineRepresentation::kWord64:
|
||||
return config->allocatable_general_codes();
|
||||
case MachineRepresentation::kFloat32:
|
||||
return config->allocatable_float_codes();
|
||||
case MachineRepresentation::kFloat64:
|
||||
return config->allocatable_double_codes();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
CallDescriptor* CreateMonoCallDescriptor(Zone* zone, int return_count,
|
||||
int param_count, MachineType type) {
|
||||
CallDescriptor* GetCallDescriptor(Zone* zone, int return_count,
|
||||
int param_count) {
|
||||
LocationSignature::Builder locations(zone, return_count, param_count);
|
||||
const RegisterConfiguration* config = RegisterConfiguration::Default();
|
||||
|
||||
int span = std::max(1, size(type) / kPointerSize);
|
||||
int stack_params = 0;
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
LinkageLocation location = LinkageLocation::ForAnyRegister();
|
||||
if (i < num_registers(type)) {
|
||||
location = LinkageLocation::ForRegister(codes(type)[i], type);
|
||||
} else {
|
||||
int slot = span * (i - param_count);
|
||||
location = LinkageLocation::ForCallerFrameSlot(slot, type);
|
||||
stack_params += span;
|
||||
}
|
||||
locations.AddParam(location);
|
||||
// Add return location(s).
|
||||
CHECK(return_count <= config->num_allocatable_general_registers());
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
locations.AddReturn(LinkageLocation::ForRegister(
|
||||
config->allocatable_general_codes()[i], MachineType::AnyTagged()));
|
||||
}
|
||||
|
||||
int stack_returns = 0;
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
LinkageLocation location = LinkageLocation::ForAnyRegister();
|
||||
if (i < num_registers(type)) {
|
||||
location = LinkageLocation::ForRegister(codes(type)[i], type);
|
||||
} else {
|
||||
int slot = span * (num_registers(type) - i) - stack_params - 1;
|
||||
location = LinkageLocation::ForCallerFrameSlot(slot, type);
|
||||
stack_returns += span;
|
||||
}
|
||||
locations.AddReturn(location);
|
||||
// Add register and/or stack parameter(s).
|
||||
CHECK(param_count <= config->num_allocatable_general_registers());
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
locations.AddParam(LinkageLocation::ForRegister(
|
||||
config->allocatable_general_codes()[i], MachineType::AnyTagged()));
|
||||
}
|
||||
|
||||
const RegList kCalleeSaveRegisters = 0;
|
||||
const RegList kCalleeSaveFPRegisters = 0;
|
||||
|
||||
// The target for wasm calls is always a code object.
|
||||
MachineType target_type = MachineType::AnyTagged();
|
||||
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
|
||||
LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
|
||||
return new (zone) CallDescriptor( // --
|
||||
CallDescriptor::kCallCodeObject, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
stack_params, // on-stack parameter count
|
||||
0, // js_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
CallDescriptor::kNoFlags, // flags
|
||||
"c-call", // debug name
|
||||
0, // allocatable registers
|
||||
stack_returns); // on-stack return count
|
||||
"c-call");
|
||||
}
|
||||
|
||||
MachineType RandomType(v8::base::RandomNumberGenerator* rng) {
|
||||
switch (rng->NextInt(4)) {
|
||||
case 0:
|
||||
#if (!V8_TARGET_ARCH_32_BIT)
|
||||
return MachineType::Int64();
|
||||
// Else fall through.
|
||||
#endif
|
||||
case 1:
|
||||
return MachineType::Int32();
|
||||
case 2:
|
||||
return MachineType::Float32();
|
||||
case 3:
|
||||
return MachineType::Float64();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
LinkageLocation alloc(MachineType type, int* int_count, int* float_count,
|
||||
int* stack_slots) {
|
||||
int* count = is_float(type) ? float_count : int_count;
|
||||
LinkageLocation location = LinkageLocation::ForAnyRegister(); // Dummy.
|
||||
if (*count < num_registers(type)) {
|
||||
location = LinkageLocation::ForRegister(codes(type)[*count], type);
|
||||
} else {
|
||||
location = LinkageLocation::ForCallerFrameSlot(-*stack_slots - 1, type);
|
||||
*stack_slots += std::max(1, size(type) / kPointerSize);
|
||||
}
|
||||
++*count;
|
||||
return location;
|
||||
}
|
||||
|
||||
CallDescriptor* CreateRandomCallDescriptor(
|
||||
Zone* zone, int return_count, int param_count,
|
||||
v8::base::RandomNumberGenerator* rng) {
|
||||
LocationSignature::Builder locations(zone, return_count, param_count);
|
||||
|
||||
int stack_slots = 0;
|
||||
int int_params = 0;
|
||||
int float_params = 0;
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
MachineType type = RandomType(rng);
|
||||
LinkageLocation location =
|
||||
alloc(type, &int_params, &float_params, &stack_slots);
|
||||
locations.AddParam(location);
|
||||
}
|
||||
int stack_params = stack_slots;
|
||||
|
||||
int int_returns = 0;
|
||||
int float_returns = 0;
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
MachineType type = RandomType(rng);
|
||||
LinkageLocation location =
|
||||
alloc(type, &int_returns, &float_returns, &stack_slots);
|
||||
locations.AddReturn(location);
|
||||
}
|
||||
int stack_returns = stack_slots - stack_params;
|
||||
|
||||
MachineType target_type = MachineType::AnyTagged();
|
||||
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
|
||||
return new (zone) CallDescriptor( // --
|
||||
CallDescriptor::kCallCodeObject, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
locations.Build(), // location_sig
|
||||
stack_params, // on-stack parameter count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
0, // callee-saved registers
|
||||
0, // callee-saved fp regs
|
||||
CallDescriptor::kNoFlags, // flags
|
||||
"c-call", // debug name
|
||||
0, // allocatable registers
|
||||
stack_returns); // on-stack return count
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Node* Constant(RawMachineAssembler& m, MachineType type, int value) {
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
return m.Int32Constant(static_cast<int32_t>(value));
|
||||
case MachineRepresentation::kWord64:
|
||||
return m.Int64Constant(static_cast<int64_t>(value));
|
||||
case MachineRepresentation::kFloat32:
|
||||
return m.Float32Constant(static_cast<float>(value));
|
||||
case MachineRepresentation::kFloat64:
|
||||
return m.Float64Constant(static_cast<double>(value));
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Node* Add(RawMachineAssembler& m, MachineType type, Node* a, Node* b) {
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
return m.Int32Add(a, b);
|
||||
case MachineRepresentation::kWord64:
|
||||
return m.Int64Add(a, b);
|
||||
case MachineRepresentation::kFloat32:
|
||||
return m.Float32Add(a, b);
|
||||
case MachineRepresentation::kFloat64:
|
||||
return m.Float64Add(a, b);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
TEST(ReturnThreeValues) {
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
CallDescriptor* desc = GetCallDescriptor(&zone, 3, 2);
|
||||
HandleAndZoneScope handles;
|
||||
RawMachineAssembler m(handles.main_isolate(),
|
||||
new (handles.main_zone()) Graph(handles.main_zone()),
|
||||
desc, MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
|
||||
Node* Sub(RawMachineAssembler& m, MachineType type, Node* a, Node* b) {
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
return m.Int32Sub(a, b);
|
||||
case MachineRepresentation::kWord64:
|
||||
return m.Int64Sub(a, b);
|
||||
case MachineRepresentation::kFloat32:
|
||||
return m.Float32Sub(a, b);
|
||||
case MachineRepresentation::kFloat64:
|
||||
return m.Float64Sub(a, b);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
Node* add = m.Int32Add(p0, p1);
|
||||
Node* sub = m.Int32Sub(p0, p1);
|
||||
Node* mul = m.Int32Mul(p0, p1);
|
||||
m.Return(add, sub, mul);
|
||||
|
||||
Node* Mul(RawMachineAssembler& m, MachineType type, Node* a, Node* b) {
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
return m.Int32Mul(a, b);
|
||||
case MachineRepresentation::kWord64:
|
||||
return m.Int64Mul(a, b);
|
||||
case MachineRepresentation::kFloat32:
|
||||
return m.Float32Mul(a, b);
|
||||
case MachineRepresentation::kFloat64:
|
||||
return m.Float64Mul(a, b);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) {
|
||||
switch (type.representation()) {
|
||||
case MachineRepresentation::kWord32:
|
||||
return a;
|
||||
case MachineRepresentation::kWord64:
|
||||
return m.TruncateInt64ToInt32(a);
|
||||
case MachineRepresentation::kFloat32:
|
||||
return m.TruncateFloat32ToInt32(a);
|
||||
case MachineRepresentation::kFloat64:
|
||||
return m.RoundFloat64ToInt32(a);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void TestReturnMultipleValues(MachineType type) {
|
||||
const int kMaxCount = 20;
|
||||
for (int count = 0; count < kMaxCount; ++count) {
|
||||
printf("\n==== type = %s, count = %d ====\n\n\n",
|
||||
MachineReprToString(type.representation()), count);
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
CallDescriptor* desc = CreateMonoCallDescriptor(&zone, count, 2, type);
|
||||
HandleAndZoneScope handles;
|
||||
RawMachineAssembler m(handles.main_isolate(),
|
||||
new (handles.main_zone()) Graph(handles.main_zone()),
|
||||
desc, MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
|
||||
Node* p0 = m.Parameter(0);
|
||||
Node* p1 = m.Parameter(1);
|
||||
typedef Node* Node_ptr;
|
||||
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (i % 3 == 0) returns[i] = Add(m, type, p0, p1);
|
||||
if (i % 3 == 1) returns[i] = Sub(m, type, p0, p1);
|
||||
if (i % 3 == 2) returns[i] = Mul(m, type, p0, p1);
|
||||
}
|
||||
m.Return(count, returns.get());
|
||||
|
||||
CompilationInfo info(ArrayVector("testing"), handles.main_zone(),
|
||||
Code::STUB);
|
||||
Handle<Code> code = Pipeline::GenerateCodeForTesting(
|
||||
&info, handles.main_isolate(), desc, m.graph(), m.Export());
|
||||
CompilationInfo info(ArrayVector("testing"), handles.main_zone(), Code::STUB);
|
||||
Handle<Code> code = Pipeline::GenerateCodeForTesting(
|
||||
&info, handles.main_isolate(), desc, m.graph(), m.Export());
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble("multi_value", os);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int a = 47, b = 12;
|
||||
int expect = 0;
|
||||
for (int i = 0, sign = +1; i < count; ++i) {
|
||||
if (i % 3 == 0) expect += sign * (a + b);
|
||||
if (i % 3 == 1) expect += sign * (a - b);
|
||||
if (i % 3 == 2) expect += sign * (a * b);
|
||||
if (i % 4 == 0) sign = -sign;
|
||||
}
|
||||
|
||||
RawMachineAssemblerTester<int32_t> mt;
|
||||
Node* na = Constant(mt, type, a);
|
||||
Node* nb = Constant(mt, type, b);
|
||||
Node* ret_multi =
|
||||
mt.AddNode(mt.common()->Call(desc), mt.HeapConstant(code), na, nb);
|
||||
Node* ret = Constant(mt, type, 0);
|
||||
bool sign = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Node* x = (count == 1)
|
||||
? ret_multi
|
||||
: mt.AddNode(mt.common()->Projection(i), ret_multi);
|
||||
ret = sign ? Sub(mt, type, ret, x) : Add(mt, type, ret, x);
|
||||
if (i % 4 == 0) sign = !sign;
|
||||
}
|
||||
mt.Return(ToInt32(mt, type, ret));
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
Handle<Code> code2 = mt.GetCode();
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code2->Disassemble("multi_value_call", os);
|
||||
}
|
||||
#endif
|
||||
CHECK_EQ(expect, mt.Call());
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble("three_value", os);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_MULTI(Type, type) \
|
||||
TEST(ReturnMultiple##Type) { TestReturnMultipleValues(type); }
|
||||
|
||||
TEST_MULTI(Int32, MachineType::Int32())
|
||||
#if (!V8_TARGET_ARCH_32_BIT)
|
||||
TEST_MULTI(Int64, MachineType::Int64())
|
||||
#endif
|
||||
TEST_MULTI(Float32, MachineType::Float32())
|
||||
TEST_MULTI(Float64, MachineType::Float64())
|
||||
|
||||
#undef TEST_MULTI
|
||||
|
||||
TEST(ReturnMultipleRandom) {
|
||||
// TODO(titzer): Test without RNG?
|
||||
v8::base::RandomNumberGenerator* rng(CcTest::random_number_generator());
|
||||
|
||||
const int kNumberOfRuns = 10;
|
||||
for (int run = 0; run < kNumberOfRuns; ++run) {
|
||||
printf("\n==== Run %d ====\n\n", run);
|
||||
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator, ZONE_NAME);
|
||||
|
||||
// Create randomized descriptor.
|
||||
int param_count = rng->NextInt(20);
|
||||
int return_count = rng->NextInt(10);
|
||||
CallDescriptor* desc =
|
||||
CreateRandomCallDescriptor(&zone, return_count, param_count, rng);
|
||||
|
||||
printf("[");
|
||||
for (size_t j = 0; j < desc->ParameterCount(); ++j) {
|
||||
printf(" %s",
|
||||
MachineReprToString(desc->GetParameterType(j).representation()));
|
||||
}
|
||||
printf(" ] -> [");
|
||||
for (size_t j = 0; j < desc->ReturnCount(); ++j) {
|
||||
printf(" %s",
|
||||
MachineReprToString(desc->GetReturnType(j).representation()));
|
||||
}
|
||||
printf(" ]\n\n");
|
||||
|
||||
// Count parameters of each type.
|
||||
const size_t num_types =
|
||||
static_cast<size_t>(MachineRepresentation::kLastRepresentation) + 1;
|
||||
std::unique_ptr<int[]> counts(new int[num_types]);
|
||||
for (size_t i = 0; i < num_types; ++i) {
|
||||
counts[i] = 0;
|
||||
}
|
||||
for (size_t i = 0; i < desc->ParameterCount(); ++i) {
|
||||
++counts[index(desc->GetParameterType(i))];
|
||||
}
|
||||
|
||||
// Generate random inputs.
|
||||
std::unique_ptr<int[]> inputs(new int[desc->ParameterCount()]);
|
||||
std::unique_ptr<int[]> outputs(new int[desc->ReturnCount()]);
|
||||
for (size_t i = 0; i < desc->ParameterCount(); ++i) {
|
||||
inputs[i] = rng->NextInt(10000);
|
||||
}
|
||||
|
||||
HandleAndZoneScope handles;
|
||||
RawMachineAssembler m(handles.main_isolate(),
|
||||
new (handles.main_zone()) Graph(handles.main_zone()),
|
||||
desc, MachineType::PointerRepresentation(),
|
||||
InstructionSelector::SupportedMachineOperatorFlags());
|
||||
|
||||
// Generate Callee, returning random picks of its parameters.
|
||||
typedef Node* Node_ptr;
|
||||
std::unique_ptr<Node_ptr[]> params(
|
||||
new Node_ptr[desc->ParameterCount() + 1]);
|
||||
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[desc->ReturnCount()]);
|
||||
for (size_t i = 0; i < desc->ParameterCount(); ++i) {
|
||||
params[i] = m.Parameter(i);
|
||||
}
|
||||
for (size_t i = 0; i < desc->ReturnCount(); ++i) {
|
||||
MachineType type = desc->GetReturnType(i);
|
||||
// Find a random same-type parameter to return. Use a constant if none.
|
||||
if (counts[index(type)] == 0) {
|
||||
returns[i] = Constant(m, type, 42);
|
||||
outputs[i] = 42;
|
||||
} else {
|
||||
int n = rng->NextInt(counts[index(type)]);
|
||||
int k;
|
||||
for (k = 0;; ++k) {
|
||||
if (desc->GetParameterType(k) == desc->GetReturnType(i) && --n < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
returns[i] = params[k];
|
||||
outputs[i] = inputs[k];
|
||||
}
|
||||
}
|
||||
m.Return(static_cast<int>(desc->ReturnCount()), returns.get());
|
||||
|
||||
CompilationInfo info(ArrayVector("testing"), handles.main_zone(),
|
||||
Code::STUB);
|
||||
Handle<Code> code = Pipeline::GenerateCodeForTesting(
|
||||
&info, handles.main_isolate(), desc, m.graph(), m.Export());
|
||||
RawMachineAssemblerTester<int32_t> mt;
|
||||
Node* a = mt.Int32Constant(123);
|
||||
Node* b = mt.Int32Constant(456);
|
||||
Node* ret3 = mt.AddNode(mt.common()->Call(desc), mt.HeapConstant(code), a, b);
|
||||
Node* x = mt.AddNode(mt.common()->Projection(0), ret3);
|
||||
Node* y = mt.AddNode(mt.common()->Projection(1), ret3);
|
||||
Node* z = mt.AddNode(mt.common()->Projection(2), ret3);
|
||||
Node* ret = mt.Int32Add(mt.Int32Add(x, y), z);
|
||||
mt.Return(ret);
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble("multi_value", os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Generate caller.
|
||||
int expect = 0;
|
||||
RawMachineAssemblerTester<int32_t> mt;
|
||||
params[0] = mt.HeapConstant(code);
|
||||
for (size_t i = 0; i < desc->ParameterCount(); ++i) {
|
||||
params[i + 1] = Constant(mt, desc->GetParameterType(i), inputs[i]);
|
||||
}
|
||||
Node* ret_multi =
|
||||
mt.AddNode(mt.common()->Call(desc),
|
||||
static_cast<int>(desc->ParameterCount() + 1), params.get());
|
||||
Node* ret = Constant(mt, MachineType::Int32(), 0);
|
||||
for (size_t i = 0; i < desc->ReturnCount(); ++i) {
|
||||
if (rng->NextInt(3) == 0) continue; // Skip random outputs.
|
||||
Node* x = (desc->ReturnCount() == 1)
|
||||
? ret_multi
|
||||
: mt.AddNode(mt.common()->Projection(i), ret_multi);
|
||||
ret = mt.Int32Add(ret, ToInt32(mt, desc->GetReturnType(i), x));
|
||||
expect += outputs[i];
|
||||
}
|
||||
mt.Return(ret);
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
Handle<Code> code2 = mt.GetCode();
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code2->Disassemble("multi_value_call", os);
|
||||
}
|
||||
#endif
|
||||
CHECK_EQ(expect, mt.Call());
|
||||
Handle<Code> code2 = mt.GetCode();
|
||||
if (FLAG_print_code) {
|
||||
OFStream os(stdout);
|
||||
code2->Disassemble("three_value_call", os);
|
||||
}
|
||||
#endif
|
||||
CHECK_EQ((123 + 456) + (123 - 456) + (123 * 456), mt.Call());
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -198,12 +198,6 @@
|
||||
'asm/embenchen/lua_binarytrees': [SKIP],
|
||||
}], # novfp3 == True
|
||||
|
||||
##############################################################################
|
||||
# TODO(ahaas): Port multiple return values to ARM and MIPS
|
||||
['arch == arm or arch == arm64 or arch == mips or arch == mips64 or arch == mipsel or arch == mips64el', {
|
||||
'wasm/multi-value': [SKIP],
|
||||
}],
|
||||
|
||||
##############################################################################
|
||||
['gc_stress == True', {
|
||||
# Skip tests not suitable for GC stress.
|
||||
|
Loading…
Reference in New Issue
Block a user