Revert of [turbofan] Various fixes to allow unboxed doubles as arguments in registers and on the stack. (patchset #7 id:120001 of https://codereview.chromium.org/1263033004/ )
Reason for revert: This CL breaks MIPS (roll blocker). https://build.chromium.org/p/client.v8/builders/V8%20Linux%20-%20mipsel%20-%20sim/builds/2061/steps/Check/logs/Run_Int32_Select_1 Original issue's description: > [turbofan] Various fixes to allow unboxed doubles as arguments in registers and on the stack. > > R=jarin@chromium.org > BUG= > > Committed: https://crrev.com/71409be5395f867bbca0f6998bf6caa175cd8192 > Cr-Commit-Position: refs/heads/master@{#30091} TBR=jarin@chromium.org,titzer@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG= Review URL: https://codereview.chromium.org/1284853002 Cr-Commit-Position: refs/heads/master@{#30101}
This commit is contained in:
parent
a946401a7d
commit
31a3f68da9
@ -147,9 +147,12 @@ class ArmOperandConverter final : public InstructionOperandConverter {
|
||||
|
||||
MemOperand ToMemOperand(InstructionOperand* op) const {
|
||||
DCHECK(op != NULL);
|
||||
DCHECK(!op->IsRegister());
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
@ -989,8 +992,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
} else {
|
||||
frame()->SetPCOnStack(false);
|
||||
}
|
||||
|
||||
if (info()->is_osr()) {
|
||||
@ -1018,7 +1019,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
// Remove this frame's spill slots first.
|
||||
@ -1041,17 +1041,23 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
}
|
||||
__ LeaveFrame(StackFrame::MANUAL);
|
||||
__ Ret();
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ b(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ LeaveFrame(StackFrame::MANUAL);
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count != 0) {
|
||||
__ Drop(pop_count);
|
||||
}
|
||||
__ Ret();
|
||||
}
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
__ Ret(pop_count);
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,9 +184,12 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
|
||||
|
||||
MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const {
|
||||
DCHECK(op != NULL);
|
||||
DCHECK(!op->IsRegister());
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
|
||||
offset.offset());
|
||||
}
|
||||
@ -1115,8 +1118,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
} else {
|
||||
frame()->SetPCOnStack(false);
|
||||
}
|
||||
|
||||
if (info()->is_osr()) {
|
||||
@ -1148,7 +1149,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
// Remove this frame's spill slots first.
|
||||
@ -1169,19 +1169,24 @@ void CodeGenerator::AssembleReturn() {
|
||||
|
||||
__ Mov(csp, fp);
|
||||
__ Pop(fp, lr);
|
||||
__ Ret();
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ B(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ Bind(&return_label_);
|
||||
__ Mov(jssp, fp);
|
||||
__ Pop(fp, lr);
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count != 0) {
|
||||
__ Drop(pop_count);
|
||||
}
|
||||
__ Ret();
|
||||
}
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
__ Drop(pop_count);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,8 +22,7 @@ class Frame : public ZoneObject {
|
||||
spill_slot_count_(0),
|
||||
osr_stack_slot_count_(0),
|
||||
allocated_registers_(NULL),
|
||||
allocated_double_registers_(NULL),
|
||||
pc_on_stack_(true) {}
|
||||
allocated_double_registers_(NULL) {}
|
||||
|
||||
inline int GetSpillSlotCount() { return spill_slot_count_; }
|
||||
|
||||
@ -72,17 +71,12 @@ class Frame : public ZoneObject {
|
||||
spill_slot_count_ = static_cast<int>(slot_count);
|
||||
}
|
||||
|
||||
void SetPCOnStack(bool val) { pc_on_stack_ = val; }
|
||||
|
||||
int PCOnStackSize() { return pc_on_stack_ ? kRegisterSize : 0; }
|
||||
|
||||
private:
|
||||
int register_save_area_size_;
|
||||
int spill_slot_count_;
|
||||
int osr_stack_slot_count_;
|
||||
BitVector* allocated_registers_;
|
||||
BitVector* allocated_double_registers_;
|
||||
bool pc_on_stack_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Frame);
|
||||
};
|
||||
|
@ -46,10 +46,10 @@ class IA32OperandConverter : public InstructionOperandConverter {
|
||||
return Operand(ToDoubleRegister(op));
|
||||
}
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
return Operand(offset.from_stack_pointer() ? esp : ebp,
|
||||
offset.offset() + extra);
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), extra);
|
||||
return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
|
||||
}
|
||||
|
||||
Operand HighOperand(InstructionOperand* op) {
|
||||
@ -1325,26 +1325,31 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
}
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
} else {
|
||||
// No saved registers.
|
||||
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
}
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ jmp(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count == 0) {
|
||||
__ ret(0);
|
||||
} else {
|
||||
__ Ret(pop_count * kPointerSize, ebx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
__ ret(0);
|
||||
}
|
||||
size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
|
||||
// Might need ecx for scratch if pop_size is too big.
|
||||
DCHECK_EQ(0, descriptor->CalleeSavedRegisters() & ecx.bit());
|
||||
__ Ret(static_cast<int>(pop_size), ecx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
|
||||
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
|
||||
// TODO(svenpanne) Output properties etc. and be less cryptic.
|
||||
return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
|
||||
<< "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
|
||||
<< "j" << d.JSParameterCount() << "i" << d.InputCount() << "f"
|
||||
<< d.FrameStateCount() << "t" << d.SupportsTailCalls();
|
||||
}
|
||||
|
||||
@ -189,7 +189,8 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
|
||||
}
|
||||
|
||||
|
||||
FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame) const {
|
||||
FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame,
|
||||
int extra) const {
|
||||
if (frame->GetSpillSlotCount() > 0 || incoming_->IsJSFunctionCall() ||
|
||||
incoming_->kind() == CallDescriptor::kCallAddress) {
|
||||
int offset;
|
||||
@ -197,11 +198,12 @@ FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame) const {
|
||||
if (spill_slot >= 0) {
|
||||
// Local or spill slot. Skip the frame pointer, function, and
|
||||
// context in the fixed part of the frame.
|
||||
offset = -(spill_slot + 1) * kPointerSize - register_save_area_size;
|
||||
offset =
|
||||
-(spill_slot + 1) * kPointerSize - register_save_area_size + extra;
|
||||
} else {
|
||||
// Incoming parameter. Skip the return address.
|
||||
offset = -(spill_slot + 1) * kPointerSize + kFPOnStackSize +
|
||||
frame->PCOnStackSize();
|
||||
kPCOnStackSize + extra;
|
||||
}
|
||||
return FrameOffset::FromFramePointer(offset);
|
||||
} else {
|
||||
@ -209,7 +211,7 @@ FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame) const {
|
||||
DCHECK(spill_slot < 0); // Must be a parameter.
|
||||
int register_save_area_size = frame->GetRegisterSaveAreaSize();
|
||||
int offset = register_save_area_size - (spill_slot + 1) * kPointerSize +
|
||||
frame->PCOnStackSize();
|
||||
kPCOnStackSize + extra;
|
||||
return FrameOffset::FromStackPointer(offset);
|
||||
}
|
||||
}
|
||||
|
@ -313,8 +313,9 @@ class Linkage : public ZoneObject {
|
||||
// Get the frame offset for a given spill slot. The location depends on the
|
||||
// calling convention and the specific frame layout, and may thus be
|
||||
// architecture-specific. Negative spill slots indicate arguments on the
|
||||
// caller's frame.
|
||||
FrameOffset GetFrameOffset(int spill_slot, Frame* frame) const;
|
||||
// caller's frame. The {extra} parameter indicates an additional offset from
|
||||
// the frame offset, e.g. to index into part of a double slot.
|
||||
FrameOffset GetFrameOffset(int spill_slot, Frame* frame, int extra = 0) const;
|
||||
|
||||
static int FrameStateInputCount(Runtime::FunctionId function);
|
||||
|
||||
|
@ -116,11 +116,6 @@ inline int ElementSizeOf(MachineType machine_type) {
|
||||
return 1 << shift;
|
||||
}
|
||||
|
||||
inline bool IsFloatingPoint(MachineType type) {
|
||||
MachineType rep = RepresentationOf(type);
|
||||
return rep == kRepFloat32 || rep == kRepFloat64;
|
||||
}
|
||||
|
||||
typedef Signature<MachineType> MachineSignature;
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -106,9 +106,12 @@ class MipsOperandConverter final : public InstructionOperandConverter {
|
||||
|
||||
MemOperand ToMemOperand(InstructionOperand* op) const {
|
||||
DCHECK(op != NULL);
|
||||
DCHECK(!op->IsRegister());
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
@ -1097,8 +1100,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
} else {
|
||||
frame()->SetPCOnStack(false);
|
||||
}
|
||||
|
||||
if (info()->is_osr()) {
|
||||
@ -1126,7 +1127,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
// Remove this frame's spill slots first.
|
||||
@ -1143,19 +1143,22 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
__ Ret();
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ Branch(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count != 0) {
|
||||
__ DropAndRet(pop_count);
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pop_count != 0) {
|
||||
__ DropAndRet(pop_count);
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
|
@ -106,9 +106,12 @@ class MipsOperandConverter final : public InstructionOperandConverter {
|
||||
|
||||
MemOperand ToMemOperand(InstructionOperand* op) const {
|
||||
DCHECK(op != NULL);
|
||||
DCHECK(!op->IsRegister());
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
@ -1173,8 +1176,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
__ StubPrologue();
|
||||
frame()->SetRegisterSaveAreaSize(
|
||||
StandardFrameConstants::kFixedFrameSizeFromFp);
|
||||
} else {
|
||||
frame()->SetPCOnStack(false);
|
||||
}
|
||||
|
||||
if (info()->is_osr()) {
|
||||
@ -1202,7 +1203,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
// Remove this frame's spill slots first.
|
||||
@ -1219,19 +1219,22 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
__ Ret();
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ Branch(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count != 0) {
|
||||
__ DropAndRet(pop_count);
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pop_count != 0) {
|
||||
__ DropAndRet(pop_count);
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
|
@ -99,9 +99,12 @@ class PPCOperandConverter final : public InstructionOperandConverter {
|
||||
|
||||
MemOperand ToMemOperand(InstructionOperand* op) const {
|
||||
DCHECK(op != NULL);
|
||||
DCHECK(!op->IsRegister());
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
@ -1357,7 +1360,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
// Remove this frame's spill slots first.
|
||||
@ -1376,17 +1378,21 @@ void CodeGenerator::AssembleReturn() {
|
||||
const RegList saves = descriptor->CalleeSavedRegisters() & ~frame_saves;
|
||||
__ MultiPop(saves);
|
||||
}
|
||||
__ LeaveFrame(StackFrame::MANUAL);
|
||||
__ Ret();
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ b(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
__ LeaveFrame(StackFrame::MANUAL, pop_count * kPointerSize);
|
||||
__ Ret();
|
||||
}
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
__ LeaveFrame(StackFrame::MANUAL, pop_count * kPointerSize);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,22 +100,6 @@ void RawMachineAssembler::Return(Node* value) {
|
||||
}
|
||||
|
||||
|
||||
Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function,
|
||||
Node** args) {
|
||||
int param_count =
|
||||
static_cast<int>(desc->GetMachineSignature()->parameter_count());
|
||||
Node** buffer = zone()->NewArray<Node*>(param_count + 1);
|
||||
int index = 0;
|
||||
buffer[index++] = function;
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
buffer[index++] = args[i];
|
||||
}
|
||||
Node* call = graph()->NewNode(common()->Call(desc), param_count + 1, buffer);
|
||||
schedule()->AddNode(CurrentBlock(), call);
|
||||
return call;
|
||||
}
|
||||
|
||||
|
||||
Node* RawMachineAssembler::CallFunctionStub0(Node* function, Node* receiver,
|
||||
Node* context, Node* frame_state,
|
||||
CallFunctionFlags flags) {
|
||||
|
@ -479,28 +479,25 @@ class RawMachineAssembler {
|
||||
return HeapConstant(isolate()->factory()->InternalizeUtf8String(string));
|
||||
}
|
||||
|
||||
// Call a given call descriptor and the given arguments.
|
||||
Node* CallN(CallDescriptor* desc, Node* function, Node** args);
|
||||
|
||||
// Call through CallFunctionStub with lazy deopt and frame-state.
|
||||
Node* CallFunctionStub0(Node* function, Node* receiver, Node* context,
|
||||
Node* frame_state, CallFunctionFlags flags);
|
||||
// Call to a JS function with zero arguments.
|
||||
// Call to a JS function with zero parameters.
|
||||
Node* CallJS0(Node* function, Node* receiver, Node* context,
|
||||
Node* frame_state);
|
||||
// Call to a runtime function with zero arguments.
|
||||
// Call to a runtime function with zero parameters.
|
||||
Node* CallRuntime1(Runtime::FunctionId function, Node* arg0, Node* context,
|
||||
Node* frame_state);
|
||||
// Call to a C function with zero arguments.
|
||||
// Call to a C function with zero parameters.
|
||||
Node* CallCFunction0(MachineType return_type, Node* function);
|
||||
// Call to a C function with one parameter.
|
||||
Node* CallCFunction1(MachineType return_type, MachineType arg0_type,
|
||||
Node* function, Node* arg0);
|
||||
// Call to a C function with two arguments.
|
||||
// Call to a C function with two parameters.
|
||||
Node* CallCFunction2(MachineType return_type, MachineType arg0_type,
|
||||
MachineType arg1_type, Node* function, Node* arg0,
|
||||
Node* arg1);
|
||||
// Call to a C function with eight arguments.
|
||||
// Call to a C function with eight parameters.
|
||||
Node* CallCFunction8(MachineType return_type, MachineType arg0_type,
|
||||
MachineType arg1_type, MachineType arg2_type,
|
||||
MachineType arg3_type, MachineType arg4_type,
|
||||
|
@ -155,7 +155,7 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
|
||||
int vreg = unallocated->virtual_register();
|
||||
constraint->virtual_register_ = vreg;
|
||||
if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
|
||||
constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot;
|
||||
constraint->type_ = kFixedSlot;
|
||||
constraint->value_ = unallocated->fixed_slot_index();
|
||||
} else {
|
||||
switch (unallocated->extended_policy()) {
|
||||
@ -185,7 +185,11 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
|
||||
}
|
||||
break;
|
||||
case UnallocatedOperand::MUST_HAVE_SLOT:
|
||||
constraint->type_ = sequence()->IsFloat(vreg) ? kDoubleSlot : kSlot;
|
||||
if (sequence()->IsFloat(vreg)) {
|
||||
constraint->type_ = kDoubleSlot;
|
||||
} else {
|
||||
constraint->type_ = kSlot;
|
||||
}
|
||||
break;
|
||||
case UnallocatedOperand::SAME_AS_FIRST_INPUT:
|
||||
constraint->type_ = kSameAsFirst;
|
||||
|
@ -1242,11 +1242,8 @@ InstructionOperand* ConstraintBuilder::AllocateFixed(
|
||||
machine_type = data()->MachineTypeFor(virtual_register);
|
||||
}
|
||||
if (operand->HasFixedSlotPolicy()) {
|
||||
AllocatedOperand::AllocatedKind kind =
|
||||
IsFloatingPoint(machine_type) ? AllocatedOperand::DOUBLE_STACK_SLOT
|
||||
: AllocatedOperand::STACK_SLOT;
|
||||
allocated =
|
||||
AllocatedOperand(kind, machine_type, operand->fixed_slot_index());
|
||||
allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, machine_type,
|
||||
operand->fixed_slot_index());
|
||||
} else if (operand->HasFixedRegisterPolicy()) {
|
||||
allocated = AllocatedOperand(AllocatedOperand::REGISTER, machine_type,
|
||||
operand->fixed_register_index());
|
||||
|
@ -48,10 +48,10 @@ class X64OperandConverter : public InstructionOperandConverter {
|
||||
|
||||
Operand ToOperand(InstructionOperand* op, int extra = 0) {
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
return Operand(offset.from_stack_pointer() ? rsp : rbp,
|
||||
offset.offset() + extra);
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), extra);
|
||||
return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
|
||||
}
|
||||
|
||||
static size_t NextOffset(size_t* offset) {
|
||||
@ -1219,10 +1219,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
} else {
|
||||
if (instr->InputAt(0)->IsRegister()) {
|
||||
__ pushq(i.InputRegister(0));
|
||||
} else if (instr->InputAt(0)->IsDoubleRegister()) {
|
||||
// TODO(titzer): use another machine instruction?
|
||||
__ subq(rsp, Immediate(kDoubleSize));
|
||||
__ movsd(Operand(rsp, 0), i.InputDoubleRegister(0));
|
||||
} else {
|
||||
__ pushq(i.InputOperand(0));
|
||||
}
|
||||
@ -1558,26 +1554,31 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
}
|
||||
__ popq(rbp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
} else {
|
||||
// No saved registers.
|
||||
__ movq(rsp, rbp); // Move stack pointer back to frame pointer.
|
||||
__ popq(rbp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
}
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ jmp(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ movq(rsp, rbp); // Move stack pointer back to frame pointer.
|
||||
__ popq(rbp); // Pop caller's frame pointer.
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count == 0) {
|
||||
__ Ret();
|
||||
} else {
|
||||
__ Ret(pop_count * kPointerSize, rbx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
__ Ret();
|
||||
}
|
||||
size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
|
||||
// Might need rcx for scratch if pop_size is too big.
|
||||
DCHECK_EQ(0, descriptor->CalleeSavedRegisters() & rcx.bit());
|
||||
__ Ret(static_cast<int>(pop_size), rcx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,12 +38,15 @@ class X87OperandConverter : public InstructionOperandConverter {
|
||||
if (op->IsRegister()) {
|
||||
DCHECK(extra == 0);
|
||||
return Operand(ToRegister(op));
|
||||
} else if (op->IsDoubleRegister()) {
|
||||
DCHECK(extra == 0);
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
FrameOffset offset =
|
||||
linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame());
|
||||
return Operand(offset.from_stack_pointer() ? esp : ebp,
|
||||
offset.offset() + extra);
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), extra);
|
||||
return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
|
||||
}
|
||||
|
||||
Operand HighOperand(InstructionOperand* op) {
|
||||
@ -1565,7 +1568,6 @@ void CodeGenerator::AssemblePrologue() {
|
||||
void CodeGenerator::AssembleReturn() {
|
||||
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
int stack_slots = frame()->GetSpillSlotCount();
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (descriptor->kind() == CallDescriptor::kCallAddress) {
|
||||
const RegList saves = descriptor->CalleeSavedRegisters();
|
||||
if (frame()->GetRegisterSaveAreaSize() > 0) {
|
||||
@ -1581,26 +1583,30 @@ void CodeGenerator::AssembleReturn() {
|
||||
}
|
||||
}
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
} else {
|
||||
// No saved registers.
|
||||
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
__ ret(0);
|
||||
}
|
||||
} else if (descriptor->IsJSFunctionCall() || needs_frame_) {
|
||||
// Canonicalize JSFunction return sites for now.
|
||||
if (return_label_.is_bound()) {
|
||||
__ jmp(&return_label_);
|
||||
return;
|
||||
} else {
|
||||
__ bind(&return_label_);
|
||||
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
|
||||
__ pop(ebp); // Pop caller's frame pointer.
|
||||
int pop_count = static_cast<int>(descriptor->StackParameterCount());
|
||||
if (pop_count == 0) {
|
||||
__ ret(0);
|
||||
} else {
|
||||
__ Ret(pop_count * kPointerSize, ebx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pop_count == 0) {
|
||||
__ ret(0);
|
||||
} else {
|
||||
__ Ret(pop_count * kPointerSize, ebx);
|
||||
__ ret(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,6 @@
|
||||
'compiler/test-run-jsexceptions.cc',
|
||||
'compiler/test-run-jsops.cc',
|
||||
'compiler/test-run-machops.cc',
|
||||
'compiler/test-run-native-calls.cc',
|
||||
'compiler/test-run-properties.cc',
|
||||
'compiler/test-run-stackcheck.cc',
|
||||
'compiler/test-run-stubs.cc',
|
||||
|
@ -69,10 +69,6 @@ class CSignature : public MachineSignature {
|
||||
}
|
||||
}
|
||||
|
||||
static CSignature* FromMachine(Zone* zone, MachineSignature* msig) {
|
||||
return reinterpret_cast<CSignature*>(msig);
|
||||
}
|
||||
|
||||
static CSignature* New(Zone* zone, MachineType ret,
|
||||
MachineType p1 = kMachNone, MachineType p2 = kMachNone,
|
||||
MachineType p3 = kMachNone, MachineType p4 = kMachNone,
|
||||
|
@ -304,21 +304,6 @@ class CallHelper {
|
||||
Isolate* isolate_;
|
||||
};
|
||||
|
||||
// A call helper that calls the given code object assuming C calling convention.
|
||||
template <typename T>
|
||||
class CodeRunner : public CallHelper<T> {
|
||||
public:
|
||||
CodeRunner(Isolate* isolate, Handle<Code> code, CSignature* csig)
|
||||
: CallHelper<T>(isolate, csig), code_(code) {}
|
||||
virtual ~CodeRunner() {}
|
||||
|
||||
virtual byte* Generate() { return code_->entry(); }
|
||||
|
||||
private:
|
||||
Handle<Code> code_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -28,12 +28,6 @@ class GraphAndBuilders {
|
||||
main_machine_(zone),
|
||||
main_simplified_(zone) {}
|
||||
|
||||
Graph* graph() const { return main_graph_; }
|
||||
Zone* zone() const { return graph()->zone(); }
|
||||
CommonOperatorBuilder* common() { return &main_common_; }
|
||||
MachineOperatorBuilder* machine() { return &main_machine_; }
|
||||
SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
|
||||
|
||||
protected:
|
||||
// Prefixed with main_ to avoid naming conflicts.
|
||||
Graph* main_graph_;
|
||||
@ -45,7 +39,7 @@ class GraphAndBuilders {
|
||||
|
||||
template <typename ReturnType>
|
||||
class GraphBuilderTester : public HandleAndZoneScope,
|
||||
public GraphAndBuilders,
|
||||
private GraphAndBuilders,
|
||||
public CallHelper<ReturnType> {
|
||||
public:
|
||||
explicit GraphBuilderTester(MachineType p0 = kMachNone,
|
||||
@ -73,7 +67,12 @@ class GraphBuilderTester : public HandleAndZoneScope,
|
||||
}
|
||||
|
||||
Isolate* isolate() { return main_isolate(); }
|
||||
Graph* graph() const { return main_graph_; }
|
||||
Zone* zone() const { return graph()->zone(); }
|
||||
Factory* factory() { return isolate()->factory(); }
|
||||
CommonOperatorBuilder* common() { return &main_common_; }
|
||||
MachineOperatorBuilder* machine() { return &main_machine_; }
|
||||
SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
|
||||
|
||||
// Initialize graph and builder.
|
||||
void Begin(int num_parameters) {
|
||||
|
@ -1,634 +0,0 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-type.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
#include "test/cctest/compiler/graph-builder-tester.h"
|
||||
#include "test/cctest/compiler/value-helper.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef RawMachineAssembler::Label MLabel;
|
||||
|
||||
#if !V8_TARGET_ARCH_ARM64
|
||||
// TODO(titzer): fix native stack parameters on arm64
|
||||
#define NATIVE_STACK_PARAMS_OK
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// Picks a representative set of registers from the allocatable set.
|
||||
// If there are less than 100 possible pairs, do them all, otherwise try
|
||||
// to select a representative set.
|
||||
class RegisterPairs {
|
||||
public:
|
||||
RegisterPairs()
|
||||
: max_(std::min(100, Register::kMaxNumAllocatableRegisters *
|
||||
Register::kMaxNumAllocatableRegisters)),
|
||||
counter_(0) {}
|
||||
|
||||
bool More() { return counter_ < max_; }
|
||||
|
||||
void Next(int* r0, int* r1, bool same_is_ok) {
|
||||
do {
|
||||
// Find the next pair.
|
||||
if (exhaustive()) {
|
||||
*r0 = counter_ % Register::kMaxNumAllocatableRegisters;
|
||||
*r1 = counter_ / Register::kMaxNumAllocatableRegisters;
|
||||
} else {
|
||||
// Try each register at least once for both r0 and r1.
|
||||
int index = counter_ / 2;
|
||||
if (counter_ & 1) {
|
||||
*r0 = index % Register::kMaxNumAllocatableRegisters;
|
||||
*r1 = index / Register::kMaxNumAllocatableRegisters;
|
||||
} else {
|
||||
*r1 = index % Register::kMaxNumAllocatableRegisters;
|
||||
*r0 = index / Register::kMaxNumAllocatableRegisters;
|
||||
}
|
||||
}
|
||||
counter_++;
|
||||
if (same_is_ok) break;
|
||||
if (*r0 == *r1) {
|
||||
if (counter_ >= max_) {
|
||||
// For the last hurrah, reg#0 with reg#n-1
|
||||
*r0 = 0;
|
||||
*r1 = Register::kMaxNumAllocatableRegisters - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
DCHECK(*r0 >= 0 && *r0 < Register::kMaxNumAllocatableRegisters);
|
||||
DCHECK(*r1 >= 0 && *r1 < Register::kMaxNumAllocatableRegisters);
|
||||
printf("pair = %d, %d\n", *r0, *r1);
|
||||
}
|
||||
|
||||
private:
|
||||
int max_;
|
||||
int counter_;
|
||||
bool exhaustive() {
|
||||
return max_ == (Register::kMaxNumAllocatableRegisters *
|
||||
Register::kMaxNumAllocatableRegisters);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Helper for allocating either an GP or FP reg, or the next stack slot.
|
||||
struct Allocator {
|
||||
Allocator(int* gp, int gpc, int* fp, int fpc)
|
||||
: gp_count(gpc),
|
||||
gp_offset(0),
|
||||
gp_regs(gp),
|
||||
fp_count(fpc),
|
||||
fp_offset(0),
|
||||
fp_regs(fp),
|
||||
stack_offset(0) {}
|
||||
|
||||
int gp_count;
|
||||
int gp_offset;
|
||||
int* gp_regs;
|
||||
|
||||
int fp_count;
|
||||
int fp_offset;
|
||||
int* fp_regs;
|
||||
|
||||
int stack_offset;
|
||||
|
||||
LinkageLocation Next(MachineType type) {
|
||||
if (IsFloatingPoint(type)) {
|
||||
// Allocate a floating point register/stack location.
|
||||
if (fp_offset < fp_count) {
|
||||
return LinkageLocation::ForRegister(fp_regs[fp_offset++]);
|
||||
} else {
|
||||
int offset = -1 - stack_offset;
|
||||
stack_offset += Words(type);
|
||||
return LinkageLocation::ForCallerFrameSlot(offset);
|
||||
}
|
||||
} else {
|
||||
// Allocate a general purpose register/stack location.
|
||||
if (gp_offset < gp_count) {
|
||||
return LinkageLocation::ForRegister(gp_regs[gp_offset++]);
|
||||
} else {
|
||||
int offset = -1 - stack_offset;
|
||||
stack_offset += Words(type);
|
||||
return LinkageLocation::ForCallerFrameSlot(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool IsFloatingPoint(MachineType type) {
|
||||
return RepresentationOf(type) == kRepFloat32 ||
|
||||
RepresentationOf(type) == kRepFloat64;
|
||||
}
|
||||
int Words(MachineType type) {
|
||||
int size = ElementSizeOf(type);
|
||||
return size <= kPointerSize ? 1 : size / kPointerSize;
|
||||
}
|
||||
void Reset() {
|
||||
fp_offset = 0;
|
||||
gp_offset = 0;
|
||||
stack_offset = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RegisterConfig {
|
||||
public:
|
||||
RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {}
|
||||
|
||||
CallDescriptor* Create(Zone* zone, MachineSignature* msig) {
|
||||
rets.Reset();
|
||||
params.Reset();
|
||||
|
||||
LocationSignature::Builder locations(zone, msig->return_count(),
|
||||
msig->parameter_count());
|
||||
// Add return location(s).
|
||||
const int return_count = static_cast<int>(locations.return_count_);
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
locations.AddReturn(rets.Next(msig->GetReturn(i)));
|
||||
}
|
||||
|
||||
// Add register and/or stack parameter(s).
|
||||
const int parameter_count = static_cast<int>(msig->parameter_count());
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
locations.AddParam(params.Next(msig->GetParam(i)));
|
||||
}
|
||||
|
||||
const RegList kCalleeSaveRegisters = 0;
|
||||
const RegList kCalleeSaveFPRegisters = 0;
|
||||
|
||||
MachineType target_type = compiler::kMachAnyTagged;
|
||||
LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
|
||||
int stack_param_count = params.stack_offset;
|
||||
return new (zone) CallDescriptor( // --
|
||||
CallDescriptor::kCallCodeObject, // kind
|
||||
target_type, // target MachineType
|
||||
target_loc, // target location
|
||||
msig, // machine_sig
|
||||
locations.Build(), // location_sig
|
||||
stack_param_count, // stack_parameter_count
|
||||
compiler::Operator::kNoProperties, // properties
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
CallDescriptor::kNoFlags, // flags
|
||||
"c-call");
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator& params;
|
||||
Allocator& rets;
|
||||
};
|
||||
|
||||
const int kMaxParamCount = 64;
|
||||
|
||||
MachineType kIntTypes[kMaxParamCount + 1] = {
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32,
|
||||
kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32};
|
||||
|
||||
|
||||
// For making uniform int32 signatures shorter.
|
||||
class Int32Signature : public MachineSignature {
|
||||
public:
|
||||
explicit Int32Signature(int param_count)
|
||||
: MachineSignature(1, param_count, kIntTypes) {
|
||||
CHECK(param_count <= kMaxParamCount);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Handle<Code> CompileGraph(const char* name, CallDescriptor* desc, Graph* graph,
|
||||
Schedule* schedule = nullptr) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
Handle<Code> code =
|
||||
Pipeline::GenerateCodeForTesting(isolate, desc, graph, schedule);
|
||||
CHECK(!code.is_null());
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
code->Disassemble(name, os);
|
||||
}
|
||||
#endif
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> WrapWithCFunction(Handle<Code> inner, CallDescriptor* desc) {
|
||||
Zone zone;
|
||||
MachineSignature* msig =
|
||||
const_cast<MachineSignature*>(desc->GetMachineSignature());
|
||||
int param_count = static_cast<int>(msig->parameter_count());
|
||||
GraphAndBuilders caller(&zone);
|
||||
{
|
||||
GraphAndBuilders& b = caller;
|
||||
Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3));
|
||||
b.graph()->SetStart(start);
|
||||
Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner);
|
||||
Node* target = b.graph()->NewNode(b.common()->HeapConstant(unique));
|
||||
|
||||
// Add arguments to the call.
|
||||
Node** args = zone.NewArray<Node*>(param_count + 3);
|
||||
int index = 0;
|
||||
args[index++] = target;
|
||||
for (int i = 0; i < param_count; i++) {
|
||||
args[index] = b.graph()->NewNode(b.common()->Parameter(i), start);
|
||||
index++;
|
||||
}
|
||||
args[index++] = start; // effect.
|
||||
args[index++] = start; // control.
|
||||
|
||||
// Build the call and return nodes.
|
||||
Node* call =
|
||||
b.graph()->NewNode(b.common()->Call(desc), param_count + 3, args);
|
||||
Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start);
|
||||
b.graph()->SetEnd(ret);
|
||||
}
|
||||
|
||||
CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig);
|
||||
|
||||
return CompileGraph("wrapper", cdesc, caller.graph());
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
static void TestInt32Sub(CallDescriptor* desc) {
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
Zone zone;
|
||||
GraphAndBuilders inner(&zone);
|
||||
{
|
||||
// Build the add function.
|
||||
GraphAndBuilders& b = inner;
|
||||
Node* start = b.graph()->NewNode(b.common()->Start(5));
|
||||
b.graph()->SetStart(start);
|
||||
Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start);
|
||||
Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start);
|
||||
Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1);
|
||||
Node* ret = b.graph()->NewNode(b.common()->Return(), add, start, start);
|
||||
b.graph()->SetEnd(ret);
|
||||
}
|
||||
|
||||
Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph());
|
||||
Handle<Code> wrapper = WrapWithCFunction(inner_code, desc);
|
||||
MachineSignature* msig =
|
||||
const_cast<MachineSignature*>(desc->GetMachineSignature());
|
||||
CodeRunner<int32_t> runnable(isolate, wrapper,
|
||||
CSignature::FromMachine(&zone, msig));
|
||||
|
||||
FOR_INT32_INPUTS(i) {
|
||||
FOR_INT32_INPUTS(j) {
|
||||
int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) -
|
||||
static_cast<uint32_t>(*j));
|
||||
int32_t result = runnable.Call(*i, *j);
|
||||
CHECK_EQ(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NATIVE_STACK_PARAMS_OK
|
||||
static void CopyTwentyInt32(CallDescriptor* desc) {
|
||||
const int kNumParams = 20;
|
||||
int32_t input[kNumParams];
|
||||
int32_t output[kNumParams];
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
Handle<Code> inner = Handle<Code>::null();
|
||||
{
|
||||
// Writes all parameters into the output buffer.
|
||||
Zone zone;
|
||||
Graph graph(&zone);
|
||||
RawMachineAssembler raw(isolate, &graph, desc);
|
||||
Node* base = raw.PointerConstant(output);
|
||||
for (int i = 0; i < kNumParams; i++) {
|
||||
Node* offset = raw.Int32Constant(i * sizeof(int32_t));
|
||||
raw.Store(kMachInt32, base, offset, raw.Parameter(i));
|
||||
}
|
||||
raw.Return(raw.Int32Constant(42));
|
||||
inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export());
|
||||
}
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
Handle<Code> wrapper = Handle<Code>::null();
|
||||
{
|
||||
// Loads parameters from the input buffer and calls the above code.
|
||||
Zone zone;
|
||||
Graph graph(&zone);
|
||||
CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
|
||||
RawMachineAssembler raw(isolate, &graph, cdesc);
|
||||
Node* base = raw.PointerConstant(input);
|
||||
Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner);
|
||||
Node* target = raw.HeapConstant(unique);
|
||||
Node** args = zone.NewArray<Node*>(kNumParams);
|
||||
for (int i = 0; i < kNumParams; i++) {
|
||||
Node* offset = raw.Int32Constant(i * sizeof(int32_t));
|
||||
args[i] = raw.Load(kMachInt32, base, offset);
|
||||
}
|
||||
|
||||
Node* call = raw.CallN(desc, target, args);
|
||||
raw.Return(call);
|
||||
wrapper =
|
||||
CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph, raw.Export());
|
||||
}
|
||||
|
||||
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
|
||||
|
||||
// Run the code, checking it correctly implements the memcpy.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
uint32_t base = 1111111111u * i;
|
||||
for (int j = 0; j < kNumParams; j++) {
|
||||
input[j] = static_cast<int32_t>(base + 13 * j);
|
||||
}
|
||||
|
||||
memset(output, 0, sizeof(output));
|
||||
CHECK_EQ(42, runnable.Call());
|
||||
|
||||
for (int j = 0; j < kNumParams; j++) {
|
||||
CHECK_EQ(input[j], output[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // NATIVE_STACK_PARAMS_OK
|
||||
|
||||
|
||||
static void Test_RunInt32SubWithRet(int retreg) {
|
||||
Int32Signature sig(2);
|
||||
Zone zone;
|
||||
RegisterPairs pairs;
|
||||
while (pairs.More()) {
|
||||
int parray[2];
|
||||
int rarray[] = {retreg};
|
||||
pairs.Next(&parray[0], &parray[1], false);
|
||||
Allocator params(parray, 2, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
TestInt32Sub(desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Separate tests for parallelization.
|
||||
#define TEST_INT32_SUB_WITH_RET(x) \
|
||||
TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \
|
||||
if (Register::kMaxNumAllocatableRegisters > x) Test_RunInt32SubWithRet(x); \
|
||||
}
|
||||
|
||||
|
||||
TEST_INT32_SUB_WITH_RET(0)
|
||||
TEST_INT32_SUB_WITH_RET(1)
|
||||
TEST_INT32_SUB_WITH_RET(2)
|
||||
TEST_INT32_SUB_WITH_RET(3)
|
||||
TEST_INT32_SUB_WITH_RET(4)
|
||||
TEST_INT32_SUB_WITH_RET(5)
|
||||
TEST_INT32_SUB_WITH_RET(6)
|
||||
TEST_INT32_SUB_WITH_RET(7)
|
||||
TEST_INT32_SUB_WITH_RET(8)
|
||||
TEST_INT32_SUB_WITH_RET(9)
|
||||
TEST_INT32_SUB_WITH_RET(10)
|
||||
TEST_INT32_SUB_WITH_RET(11)
|
||||
TEST_INT32_SUB_WITH_RET(12)
|
||||
TEST_INT32_SUB_WITH_RET(13)
|
||||
TEST_INT32_SUB_WITH_RET(14)
|
||||
TEST_INT32_SUB_WITH_RET(15)
|
||||
TEST_INT32_SUB_WITH_RET(16)
|
||||
TEST_INT32_SUB_WITH_RET(17)
|
||||
TEST_INT32_SUB_WITH_RET(18)
|
||||
TEST_INT32_SUB_WITH_RET(19)
|
||||
|
||||
|
||||
TEST(Run_Int32Sub_all_allocatable_single) {
|
||||
#ifdef NATIVE_STACK_PARAMS_OK
|
||||
Int32Signature sig(2);
|
||||
RegisterPairs pairs;
|
||||
while (pairs.More()) {
|
||||
Zone zone;
|
||||
int parray[1];
|
||||
int rarray[1];
|
||||
pairs.Next(&rarray[0], &parray[0], true);
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
TestInt32Sub(desc);
|
||||
}
|
||||
#endif // NATIVE_STACK_PARAMS_OK
|
||||
}
|
||||
|
||||
|
||||
TEST(Run_CopyTwentyInt32_all_allocatable_pairs) {
|
||||
#ifdef NATIVE_STACK_PARAMS_OK
|
||||
Int32Signature sig(20);
|
||||
RegisterPairs pairs;
|
||||
while (pairs.More()) {
|
||||
Zone zone;
|
||||
int parray[2];
|
||||
int rarray[] = {0};
|
||||
pairs.Next(&parray[0], &parray[1], false);
|
||||
Allocator params(parray, 2, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
CopyTwentyInt32(desc);
|
||||
}
|
||||
#endif // NATIVE_STACK_PARAMS_OK
|
||||
}
|
||||
|
||||
|
||||
#ifdef NATIVE_STACK_PARAMS_OK
|
||||
int ParamCount(CallDescriptor* desc) {
|
||||
return static_cast<int>(desc->GetMachineSignature()->parameter_count());
|
||||
}
|
||||
|
||||
|
||||
// Super mega helper routine to generate a computation with a given
|
||||
// call descriptor, compile the code, wrap the code, and pass various inputs,
|
||||
// comparing against a reference implementation.
|
||||
static void Run_Int32_Computation(
|
||||
CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&),
|
||||
int32_t (*compute)(CallDescriptor*, int32_t* inputs), int seed = 1) {
|
||||
int num_params = ParamCount(desc);
|
||||
CHECK_LE(num_params, kMaxParamCount);
|
||||
int32_t input[kMaxParamCount];
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
Handle<Code> inner = Handle<Code>::null();
|
||||
{
|
||||
// Build the graph for the computation.
|
||||
Zone zone;
|
||||
Graph graph(&zone);
|
||||
RawMachineAssembler raw(isolate, &graph, desc);
|
||||
build(desc, raw);
|
||||
inner = CompileGraph("Compute", desc, &graph, raw.Export());
|
||||
}
|
||||
|
||||
CSignature0<int32_t> csig;
|
||||
Handle<Code> wrapper = Handle<Code>::null();
|
||||
{
|
||||
// Wrap the above code with a callable function that loads from {input}.
|
||||
Zone zone;
|
||||
Graph graph(&zone);
|
||||
CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig);
|
||||
RawMachineAssembler raw(isolate, &graph, cdesc);
|
||||
Node* base = raw.PointerConstant(input);
|
||||
Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner);
|
||||
Node* target = raw.HeapConstant(unique);
|
||||
Node** args = zone.NewArray<Node*>(kMaxParamCount);
|
||||
for (int i = 0; i < num_params; i++) {
|
||||
Node* offset = raw.Int32Constant(i * sizeof(int32_t));
|
||||
args[i] = raw.Load(kMachInt32, base, offset);
|
||||
}
|
||||
|
||||
Node* call = raw.CallN(desc, target, args);
|
||||
raw.Return(call);
|
||||
wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export());
|
||||
}
|
||||
|
||||
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
|
||||
|
||||
// Run the code, checking it against the reference.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// Use pseudo-random values for each run, but the first run gets args
|
||||
// 100, 101, 102, 103... for easier diagnosis.
|
||||
uint32_t base = 1111111111u * i * seed;
|
||||
for (int j = 0; j < kMaxParamCount; j++) {
|
||||
input[j] = static_cast<int32_t>(100 + base + j);
|
||||
}
|
||||
int32_t expected = compute(desc, input);
|
||||
int32_t result = runnable.Call();
|
||||
|
||||
CHECK_EQ(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
|
||||
79, 83, 89, 97, 101, 103, 107, 109, 113};
|
||||
|
||||
|
||||
static void Build_Int32_WeightedSum(CallDescriptor* desc,
|
||||
RawMachineAssembler& raw) {
|
||||
Node* result = raw.Int32Constant(0);
|
||||
for (int i = 0; i < ParamCount(desc); i++) {
|
||||
Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i]));
|
||||
result = raw.Int32Add(result, term);
|
||||
}
|
||||
raw.Return(result);
|
||||
}
|
||||
|
||||
|
||||
static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) {
|
||||
uint32_t result = 0;
|
||||
for (int i = 0; i < ParamCount(desc); i++) {
|
||||
result += static_cast<uint32_t>(input[i]) * coeff[i];
|
||||
}
|
||||
return static_cast<int32_t>(result);
|
||||
}
|
||||
|
||||
|
||||
static void Test_Int32_WeightedSum_of_size(int count) {
|
||||
Int32Signature sig(count);
|
||||
for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) {
|
||||
Zone zone;
|
||||
|
||||
int parray[] = {p0};
|
||||
int rarray[] = {0};
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
Run_Int32_Computation(desc, Build_Int32_WeightedSum,
|
||||
Compute_Int32_WeightedSum, 257 + count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Separate tests for parallelization.
|
||||
#define TEST_INT32_WEIGHTEDSUM(x) \
|
||||
TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); }
|
||||
|
||||
|
||||
TEST_INT32_WEIGHTEDSUM(1)
|
||||
TEST_INT32_WEIGHTEDSUM(2)
|
||||
TEST_INT32_WEIGHTEDSUM(3)
|
||||
TEST_INT32_WEIGHTEDSUM(4)
|
||||
TEST_INT32_WEIGHTEDSUM(5)
|
||||
TEST_INT32_WEIGHTEDSUM(7)
|
||||
TEST_INT32_WEIGHTEDSUM(9)
|
||||
TEST_INT32_WEIGHTEDSUM(11)
|
||||
TEST_INT32_WEIGHTEDSUM(17)
|
||||
TEST_INT32_WEIGHTEDSUM(19)
|
||||
|
||||
|
||||
template <int which>
|
||||
static void Build_Int32_Select(CallDescriptor* desc, RawMachineAssembler& raw) {
|
||||
raw.Return(raw.Parameter(which));
|
||||
}
|
||||
|
||||
|
||||
template <int which>
|
||||
static int32_t Compute_Int32_Select(CallDescriptor* desc, int32_t* inputs) {
|
||||
return inputs[which];
|
||||
}
|
||||
|
||||
|
||||
template <int which>
|
||||
void Test_Int32_Select() {
|
||||
int parray[] = {0};
|
||||
int rarray[] = {0};
|
||||
Allocator params(parray, 1, nullptr, 0);
|
||||
Allocator rets(rarray, 1, nullptr, 0);
|
||||
RegisterConfig config(params, rets);
|
||||
|
||||
Zone zone;
|
||||
for (int i = which + 1; i <= 64; i++) {
|
||||
Int32Signature sig(i);
|
||||
CallDescriptor* desc = config.Create(&zone, &sig);
|
||||
Run_Int32_Computation(desc, Build_Int32_Select<which>,
|
||||
Compute_Int32_Select<which>, 1025 + which);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Separate tests for parallelization.
|
||||
#define TEST_INT32_SELECT(x) \
|
||||
TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); }
|
||||
|
||||
|
||||
TEST_INT32_SELECT(0)
|
||||
TEST_INT32_SELECT(1)
|
||||
TEST_INT32_SELECT(2)
|
||||
TEST_INT32_SELECT(3)
|
||||
TEST_INT32_SELECT(4)
|
||||
TEST_INT32_SELECT(5)
|
||||
TEST_INT32_SELECT(6)
|
||||
TEST_INT32_SELECT(11)
|
||||
TEST_INT32_SELECT(15)
|
||||
TEST_INT32_SELECT(19)
|
||||
TEST_INT32_SELECT(45)
|
||||
TEST_INT32_SELECT(62)
|
||||
TEST_INT32_SELECT(63)
|
||||
#endif // NATIVE_STACK_PARAMS_OK
|
||||
|
||||
|
||||
TEST(TheLastTestForLint) {
|
||||
// Yes, thank you.
|
||||
}
|
Loading…
Reference in New Issue
Block a user