MIPS64: Add turbofan support for mips64.

TEST=
BUG=
R=danno@chromium.org, paul.lind@imgtec.com

Review URL: https://codereview.chromium.org/732403002

Cr-Commit-Position: refs/heads/master@{#25424}
This commit is contained in:
Dusan Milosavljevic 2014-11-19 16:44:39 +01:00
parent f07b0f214b
commit ae9130ebbb
12 changed files with 3262 additions and 1 deletions

View File

@ -15,6 +15,8 @@
#include "src/compiler/ia32/instruction-codes-ia32.h"
#elif V8_TARGET_ARCH_MIPS
#include "src/compiler/mips/instruction-codes-mips.h"
#elif V8_TARGET_ARCH_MIPS64
#include "src/compiler/mips64/instruction-codes-mips64.h"
#elif V8_TARGET_ARCH_X64
#include "src/compiler/x64/instruction-codes-x64.h"
#else

View File

@ -0,0 +1,5 @@
paul.lind@imgtec.com
gergely.kis@imgtec.com
akos.palfi@imgtec.com
balazs.kilvady@imgtec.com
dusan.milosavljevic@imgtec.com

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
// 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.
#ifndef V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
#define V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_
namespace v8 {
namespace internal {
namespace compiler {
// MIPS64-specific opcodes that specify which assembly sequence to emit.
// Most opcodes specify a single instruction.
#define TARGET_ARCH_OPCODE_LIST(V) \
V(Mips64Add) \
V(Mips64Dadd) \
V(Mips64Sub) \
V(Mips64Dsub) \
V(Mips64Mul) \
V(Mips64MulHigh) \
V(Mips64MulHighU) \
V(Mips64Dmul) \
V(Mips64Div) \
V(Mips64Ddiv) \
V(Mips64DivU) \
V(Mips64DdivU) \
V(Mips64Mod) \
V(Mips64Dmod) \
V(Mips64ModU) \
V(Mips64DmodU) \
V(Mips64And) \
V(Mips64Or) \
V(Mips64Xor) \
V(Mips64Shl) \
V(Mips64Shr) \
V(Mips64Sar) \
V(Mips64Ext) \
V(Mips64Dext) \
V(Mips64Dshl) \
V(Mips64Dshr) \
V(Mips64Dsar) \
V(Mips64Ror) \
V(Mips64Dror) \
V(Mips64Mov) \
V(Mips64Tst) \
V(Mips64Tst32) \
V(Mips64Cmp) \
V(Mips64Cmp32) \
V(Mips64CmpD) \
V(Mips64AddD) \
V(Mips64SubD) \
V(Mips64MulD) \
V(Mips64DivD) \
V(Mips64ModD) \
V(Mips64SqrtD) \
V(Mips64FloorD) \
V(Mips64CeilD) \
V(Mips64RoundTruncateD) \
V(Mips64CvtSD) \
V(Mips64CvtDS) \
V(Mips64TruncWD) \
V(Mips64TruncUwD) \
V(Mips64CvtDW) \
V(Mips64CvtDUw) \
V(Mips64Lb) \
V(Mips64Lbu) \
V(Mips64Sb) \
V(Mips64Lh) \
V(Mips64Lhu) \
V(Mips64Sh) \
V(Mips64Ld) \
V(Mips64Lw) \
V(Mips64Sw) \
V(Mips64Sd) \
V(Mips64Lwc1) \
V(Mips64Swc1) \
V(Mips64Ldc1) \
V(Mips64Sdc1) \
V(Mips64Push) \
V(Mips64StoreWriteBarrier)
// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
// are encoded into the InstructionCode of the instruction and tell the
// code generator after register allocation which assembler method to call.
//
// We use the following local notation for addressing modes:
//
// R = register
// O = register or stack slot
// D = double register
// I = immediate (handle, external, int32)
// MRI = [register + immediate]
// MRR = [register + register]
// TODO(plind): Add the new r6 address modes.
#define TARGET_ADDRESSING_MODE_LIST(V) \
V(MRI) /* [%r0 + K] */ \
V(MRR) /* [%r0 + %r1] */
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_MIPS_INSTRUCTION_CODES_MIPS_H_

View File

@ -0,0 +1,994 @@
// 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/base/bits.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
namespace v8 {
namespace internal {
namespace compiler {
#define TRACE_UNIMPL() \
PrintF("UNIMPLEMENTED instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
#define TRACE() PrintF("instr_sel: %s at line %d\n", __FUNCTION__, __LINE__)
// Adds Mips-specific methods for generating InstructionOperands.
class Mips64OperandGenerator FINAL : public OperandGenerator {
public:
explicit Mips64OperandGenerator(InstructionSelector* selector)
: OperandGenerator(selector) {}
InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
if (CanBeImmediate(node, opcode)) {
return UseImmediate(node);
}
return UseRegister(node);
}
bool CanBeImmediate(Node* node, InstructionCode opcode) {
int64_t value;
if (node->opcode() == IrOpcode::kInt32Constant)
value = OpParameter<int32_t>(node);
else if (node->opcode() == IrOpcode::kInt64Constant)
value = OpParameter<int64_t>(node);
else
return false;
switch (ArchOpcodeField::decode(opcode)) {
case kMips64Shl:
case kMips64Sar:
case kMips64Shr:
return is_uint5(value);
case kMips64Dshl:
case kMips64Dsar:
case kMips64Dshr:
return is_uint6(value);
case kMips64Xor:
return is_uint16(value);
case kMips64Ldc1:
case kMips64Sdc1:
return is_int16(value + kIntSize);
default:
return is_int16(value);
}
}
bool CanBeImmediate(Node* node, InstructionCode opcode,
FlagsContinuation* cont) {
int64_t value;
if (node->opcode() == IrOpcode::kInt32Constant)
value = OpParameter<int32_t>(node);
else if (node->opcode() == IrOpcode::kInt64Constant)
value = OpParameter<int64_t>(node);
else
return false;
switch (ArchOpcodeField::decode(opcode)) {
case kMips64Cmp32:
switch (cont->condition()) {
case kUnsignedLessThan:
case kUnsignedGreaterThanOrEqual:
case kUnsignedLessThanOrEqual:
case kUnsignedGreaterThan:
// Immediate operands for unsigned 32-bit compare operations
// should not be sign-extended.
return is_uint15(value);
default:
return false;
}
default:
return is_int16(value);
}
}
private:
bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
TRACE_UNIMPL();
return false;
}
};
static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
Mips64OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
Mips64OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)));
}
static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
Mips64OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)),
g.UseOperand(node->InputAt(1), opcode));
}
static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand* inputs[4];
size_t input_count = 0;
InstructionOperand* outputs[2];
size_t output_count = 0;
inputs[input_count++] = g.UseRegister(m.left().node());
inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
}
outputs[output_count++] = g.DefineAsRegister(node);
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0, input_count);
DCHECK_NE(0, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
outputs, input_count, inputs);
if (cont->IsBranch()) instr->MarkAsControl();
}
static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode) {
FlagsContinuation cont;
VisitBinop(selector, node, opcode, &cont);
}
void InstructionSelector::VisitLoad(Node* node) {
MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
Mips64OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
ArchOpcode opcode;
switch (rep) {
case kRepFloat32:
opcode = kMips64Lwc1;
break;
case kRepFloat64:
opcode = kMips64Ldc1;
break;
case kRepBit: // Fall through.
case kRepWord8:
opcode = typ == kTypeUint32 ? kMips64Lbu : kMips64Lb;
break;
case kRepWord16:
opcode = typ == kTypeUint32 ? kMips64Lhu : kMips64Lh;
break;
case kRepWord32:
opcode = kMips64Lw;
break;
case kRepTagged: // Fall through.
case kRepWord64:
opcode = kMips64Ld;
break;
default:
UNREACHABLE();
return;
}
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
} else {
InstructionOperand* addr_reg = g.TempRegister();
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
g.UseRegister(index), g.UseRegister(base));
// Emit desired load opcode, using temp addr_reg.
Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
}
}
void InstructionSelector::VisitStore(Node* node) {
Mips64OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
MachineType rep = RepresentationOf(store_rep.machine_type());
if (store_rep.write_barrier_kind() == kFullWriteBarrier) {
DCHECK(rep == kRepTagged);
// TODO(dcarney): refactor RecordWrite function to take temp registers
// and pass them here instead of using fixed regs
// TODO(dcarney): handle immediate indices.
InstructionOperand* temps[] = {g.TempRegister(t1), g.TempRegister(t2)};
Emit(kMips64StoreWriteBarrier, NULL, g.UseFixed(base, t0),
g.UseFixed(index, t1), g.UseFixed(value, t2), arraysize(temps), temps);
return;
}
DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind());
ArchOpcode opcode;
switch (rep) {
case kRepFloat32:
opcode = kMips64Swc1;
break;
case kRepFloat64:
opcode = kMips64Sdc1;
break;
case kRepBit: // Fall through.
case kRepWord8:
opcode = kMips64Sb;
break;
case kRepWord16:
opcode = kMips64Sh;
break;
case kRepWord32:
opcode = kMips64Sw;
break;
case kRepTagged: // Fall through.
case kRepWord64:
opcode = kMips64Sd;
break;
default:
UNREACHABLE();
return;
}
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
} else {
InstructionOperand* addr_reg = g.TempRegister();
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
g.UseRegister(index), g.UseRegister(base));
// Emit desired store opcode, using temp addr_reg.
Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, addr_reg,
g.TempImmediate(0), g.UseRegister(value));
}
}
void InstructionSelector::VisitWord32And(Node* node) {
VisitBinop(this, node, kMips64And);
}
void InstructionSelector::VisitWord64And(Node* node) {
VisitBinop(this, node, kMips64And);
}
void InstructionSelector::VisitWord32Or(Node* node) {
VisitBinop(this, node, kMips64Or);
}
void InstructionSelector::VisitWord64Or(Node* node) {
VisitBinop(this, node, kMips64Or);
}
void InstructionSelector::VisitWord32Xor(Node* node) {
VisitBinop(this, node, kMips64Xor);
}
void InstructionSelector::VisitWord64Xor(Node* node) {
VisitBinop(this, node, kMips64Xor);
}
void InstructionSelector::VisitWord32Shl(Node* node) {
VisitRRO(this, kMips64Shl, node);
}
void InstructionSelector::VisitWord32Shr(Node* node) {
VisitRRO(this, kMips64Shr, node);
}
void InstructionSelector::VisitWord32Sar(Node* node) {
VisitRRO(this, kMips64Sar, node);
}
void InstructionSelector::VisitWord64Shl(Node* node) {
VisitRRO(this, kMips64Dshl, node);
}
void InstructionSelector::VisitWord64Shr(Node* node) {
VisitRRO(this, kMips64Dshr, node);
}
void InstructionSelector::VisitWord64Sar(Node* node) {
VisitRRO(this, kMips64Dsar, node);
}
void InstructionSelector::VisitWord32Ror(Node* node) {
VisitRRO(this, kMips64Ror, node);
}
void InstructionSelector::VisitWord64Ror(Node* node) {
VisitRRO(this, kMips64Dror, node);
}
void InstructionSelector::VisitInt32Add(Node* node) {
Mips64OperandGenerator g(this);
// TODO(plind): Consider multiply & add optimization from arm port.
VisitBinop(this, node, kMips64Add);
}
void InstructionSelector::VisitInt64Add(Node* node) {
Mips64OperandGenerator g(this);
// TODO(plind): Consider multiply & add optimization from arm port.
VisitBinop(this, node, kMips64Dadd);
}
void InstructionSelector::VisitInt32Sub(Node* node) {
VisitBinop(this, node, kMips64Sub);
}
void InstructionSelector::VisitInt64Sub(Node* node) {
VisitBinop(this, node, kMips64Dsub);
}
void InstructionSelector::VisitInt32Mul(Node* node) {
Mips64OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.right().HasValue() && m.right().Value() > 0) {
int32_t value = m.right().Value();
if (base::bits::IsPowerOfTwo32(value)) {
Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value)));
return;
}
if (base::bits::IsPowerOfTwo32(value - 1)) {
InstructionOperand* temp = g.TempRegister();
Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
Emit(kMips64Add | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
return;
}
if (base::bits::IsPowerOfTwo32(value + 1)) {
InstructionOperand* temp = g.TempRegister();
Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
return;
}
}
Emit(kMips64Mul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitInt32MulHigh(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64MulHigh, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)));
}
void InstructionSelector::VisitUint32MulHigh(Node* node) {
Mips64OperandGenerator g(this);
InstructionOperand* const dmul_operand = g.TempRegister();
Emit(kMips64MulHighU, dmul_operand, g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)));
Emit(kMips64Ext, g.DefineAsRegister(node), dmul_operand, g.TempImmediate(0),
g.TempImmediate(32));
}
void InstructionSelector::VisitInt64Mul(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
// TODO(dusmil): Add optimization for shifts larger than 32.
if (m.right().HasValue() && m.right().Value() > 0) {
int64_t value = m.right().Value();
if (base::bits::IsPowerOfTwo32(value)) {
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value)));
return;
}
if (base::bits::IsPowerOfTwo32(value - 1)) {
InstructionOperand* temp = g.TempRegister();
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()), temp);
return;
}
if (base::bits::IsPowerOfTwo32(value + 1)) {
InstructionOperand* temp = g.TempRegister();
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
return;
}
}
Emit(kMips64Dmul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitInt32Div(Node* node) {
Mips64OperandGenerator g(this);
Int32BinopMatcher m(node);
Emit(kMips64Div, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitUint32Div(Node* node) {
Mips64OperandGenerator g(this);
Int32BinopMatcher m(node);
Emit(kMips64DivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitInt32Mod(Node* node) {
Mips64OperandGenerator g(this);
Int32BinopMatcher m(node);
Emit(kMips64Mod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitUint32Mod(Node* node) {
Mips64OperandGenerator g(this);
Int32BinopMatcher m(node);
Emit(kMips64ModU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitInt64Div(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
Emit(kMips64Ddiv, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitUint64Div(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
Emit(kMips64DdivU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitInt64Mod(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
Emit(kMips64Dmod, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitUint64Mod(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
Emit(kMips64DmodU, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()));
}
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64CvtDS, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64CvtDW, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64CvtDUw, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64TruncWD, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64TruncUwD, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0));
}
void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0), g.TempImmediate(32));
}
void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Ext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0), g.TempImmediate(32));
}
void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64CvtSD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Add(Node* node) {
VisitRRR(this, kMips64AddD, node);
}
void InstructionSelector::VisitFloat64Sub(Node* node) {
VisitRRR(this, kMips64SubD, node);
}
void InstructionSelector::VisitFloat64Mul(Node* node) {
VisitRRR(this, kMips64MulD, node);
}
void InstructionSelector::VisitFloat64Div(Node* node) {
VisitRRR(this, kMips64DivD, node);
}
void InstructionSelector::VisitFloat64Mod(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64ModD, g.DefineAsFixed(node, f0),
g.UseFixed(node->InputAt(0), f12),
g.UseFixed(node->InputAt(1), f14))->MarkAsCall();
}
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64SqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitFloat64Floor(Node* node) {
VisitRR(this, kMips64FloorD, node);
}
void InstructionSelector::VisitFloat64Ceil(Node* node) {
VisitRR(this, kMips64CeilD, node);
}
void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
VisitRR(this, kMips64RoundTruncateD, node);
}
void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitCall(Node* node) {
Mips64OperandGenerator g(this);
CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
FrameStateDescriptor* frame_state_descriptor = NULL;
if (descriptor->NeedsFrameState()) {
frame_state_descriptor =
GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
}
CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
// Compute InstructionOperands for inputs and outputs.
InitializeCallBuffer(node, &buffer, true, false);
// TODO(dcarney): might be possible to use claim/poke instead
// Push any stack arguments.
for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
input != buffer.pushed_nodes.rend(); input++) {
// TODO(plind): inefficient for MIPS, use MultiPush here.
// - Also need to align the stack. See arm64.
// - Maybe combine with arg slot stuff in DirectCEntry stub.
Emit(kMips64Push, NULL, g.UseRegister(*input));
}
// Select the appropriate opcode based on the call type.
InstructionCode opcode;
switch (descriptor->kind()) {
case CallDescriptor::kCallCodeObject: {
opcode = kArchCallCodeObject;
break;
}
case CallDescriptor::kCallJSFunction:
opcode = kArchCallJSFunction;
break;
default:
UNREACHABLE();
return;
}
opcode |= MiscField::encode(descriptor->flags());
// Emit the call instruction.
Instruction* call_instr =
Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
buffer.instruction_args.size(), &buffer.instruction_args.front());
call_instr->MarkAsCall();
}
namespace {
// Shared routine for multiple compare operations.
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand* left, InstructionOperand* right,
FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
}
}
// Shared routine for multiple float compare operations.
void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
VisitCompare(selector, kMips64CmpD, g.UseRegister(left), g.UseRegister(right),
cont);
}
// Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont,
bool commutative) {
Mips64OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
// Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, opcode, cont)) {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
cont);
} else if (g.CanBeImmediate(left, opcode, cont)) {
if (!commutative) cont->Commute();
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
cont);
} else {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
cont);
}
}
void VisitWord32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
VisitWordCompare(selector, node, kMips64Cmp32, cont, false);
}
void VisitWord64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
VisitWordCompare(selector, node, kMips64Cmp, cont, false);
}
} // namespace
void EmitWordCompareZero(InstructionSelector* selector, InstructionCode opcode,
Node* value, FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
InstructionOperand* const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
g.Label(cont->true_block()),
g.Label(cont->false_block()))->MarkAsControl();
} else {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0));
}
}
// Shared routine for word comparisons against zero.
void VisitWordCompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) {
// Initially set comparison against 0 to be 64-bit variant for branches that
// cannot combine.
InstructionCode opcode = kMips64Cmp;
while (selector->CanCover(user, value)) {
if (user->opcode() == IrOpcode::kWord32Equal) {
opcode = kMips64Cmp32;
}
switch (value->opcode()) {
case IrOpcode::kWord32Equal: {
// Combine with comparisons against 0 by simply inverting the
// continuation.
Int32BinopMatcher m(value);
if (m.right().Is(0)) {
user = value;
value = m.left().node();
cont->Negate();
opcode = kMips64Cmp32;
continue;
}
cont->OverwriteAndNegateIfEqual(kEqual);
return VisitWord32Compare(selector, value, cont);
}
case IrOpcode::kInt32LessThan:
cont->OverwriteAndNegateIfEqual(kSignedLessThan);
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kInt32LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kUint32LessThan:
cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kUint32LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
return VisitWord32Compare(selector, value, cont);
case IrOpcode::kWord64Equal: {
// Combine with comparisons against 0 by simply inverting the
// continuation.
Int64BinopMatcher m(value);
if (m.right().Is(0)) {
user = value;
value = m.left().node();
cont->Negate();
continue;
}
cont->OverwriteAndNegateIfEqual(kEqual);
return VisitWord64Compare(selector, value, cont);
}
case IrOpcode::kInt64LessThan:
cont->OverwriteAndNegateIfEqual(kSignedLessThan);
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kInt64LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kUint64LessThan:
cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
return VisitWord64Compare(selector, value, cont);
case IrOpcode::kFloat64Equal:
cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
return VisitFloat64Compare(selector, value, cont);
case IrOpcode::kFloat64LessThan:
cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
return VisitFloat64Compare(selector, value, cont);
case IrOpcode::kFloat64LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
return VisitFloat64Compare(selector, value, cont);
case IrOpcode::kProjection:
// Check if this is the overflow output projection of an
// <Operation>WithOverflow node.
if (OpParameter<size_t>(value) == 1u) {
// We cannot combine the <Operation>WithOverflow with this branch
// unless the 0th projection (the use of the actual value of the
// <Operation> is either NULL, which means there's no use of the
// actual value, or was already defined, which means it is scheduled
// *AFTER* this branch).
Node* node = value->InputAt(0);
Node* result = node->FindProjection(0);
if (result == NULL || selector->IsDefined(result)) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(selector, node, kMips64Dadd, cont);
case IrOpcode::kInt32SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(selector, node, kMips64Dsub, cont);
default:
break;
}
}
}
break;
case IrOpcode::kWord32And:
return VisitWordCompare(selector, value, kMips64Tst32, cont, true);
case IrOpcode::kWord64And:
return VisitWordCompare(selector, value, kMips64Tst, cont, true);
default:
break;
}
break;
}
// Continuation could not be combined with a compare, emit compare against 0.
EmitWordCompareZero(selector, opcode, value, cont);
}
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) {
FlagsContinuation cont(kNotEqual, tbranch, fbranch);
// If we can fall through to the true block, invert the branch.
if (IsNextInAssemblyOrder(tbranch)) {
cont.Negate();
cont.SwapBlocks();
}
VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
}
void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation cont(kEqual, node);
Int32BinopMatcher m(node);
if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
}
VisitWord32Compare(this, node, &cont);
}
void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node);
VisitWord32Compare(this, node, &cont);
}
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node);
VisitWord32Compare(this, node, &cont);
}
void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node);
VisitWord32Compare(this, node, &cont);
}
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
VisitWord32Compare(this, node, &cont);
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dadd, &cont);
}
FlagsContinuation cont;
VisitBinop(this, node, kMips64Dadd, &cont);
}
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMips64Dsub, &cont);
}
FlagsContinuation cont;
VisitBinop(this, node, kMips64Dsub, &cont);
}
void InstructionSelector::VisitWord64Equal(Node* const node) {
FlagsContinuation cont(kEqual, node);
Int64BinopMatcher m(node);
if (m.right().Is(0)) {
return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
}
VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitInt64LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node);
VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node);
VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitUint64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node);
VisitWord64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kUnorderedEqual, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnorderedLessThan, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont);
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
return MachineOperatorBuilder::kNoFlags;
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,67 @@
// 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/v8.h"
#include "src/assembler.h"
#include "src/code-stubs.h"
#include "src/compiler/linkage.h"
#include "src/compiler/linkage-impl.h"
#include "src/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
struct MipsLinkageHelperTraits {
static Register ReturnValueReg() { return v0; }
static Register ReturnValue2Reg() { return v1; }
static Register JSCallFunctionReg() { return a1; }
static Register ContextReg() { return cp; }
static Register RuntimeCallFunctionReg() { return a1; }
static Register RuntimeCallArgCountReg() { return a0; }
static RegList CCalleeSaveRegisters() {
return s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() |
s6.bit() | s7.bit();
}
static Register CRegisterParameter(int i) {
static Register register_parameters[] = {a0, a1, a2, a3, a4, a5, a6, a7};
return register_parameters[i];
}
static int CRegisterParametersLength() { return 8; }
};
typedef LinkageHelper<MipsLinkageHelperTraits> LH;
CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
CallDescriptor::Flags flags) {
return LH::GetJSCallDescriptor(zone, parameter_count, flags);
}
CallDescriptor* Linkage::GetRuntimeCallDescriptor(
Runtime::FunctionId function, int parameter_count,
Operator::Properties properties, Zone* zone) {
return LH::GetRuntimeCallDescriptor(zone, function, parameter_count,
properties);
}
CallDescriptor* Linkage::GetStubCallDescriptor(
const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
CallDescriptor::Flags flags, Zone* zone) {
return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
flags);
}
CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
MachineSignature* sig) {
return LH::GetSimplifiedCDescriptor(zone, sig);
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -27,7 +27,8 @@
#endif
#if V8_TARGET_ARCH_IA32 || (V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_32_BIT) || \
V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS
V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64
#define V8_TURBOFAN_BACKEND 1
#else
#define V8_TURBOFAN_BACKEND 0

View File

@ -207,6 +207,42 @@ class CallHelper {
Simulator::CallArgument::End()};
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
}
#elif USE_SIMULATOR && V8_TARGET_ARCH_MIPS64
uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
int64_t p3 = 0, int64_t p4 = 0) {
Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
}
template <typename R, typename F>
R DoCall(F* f) {
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
}
template <typename R, typename F, typename P1>
R DoCall(F* f, P1 p1) {
return ReturnValueTraits<R>::Cast(
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
}
template <typename R, typename F, typename P1, typename P2>
R DoCall(F* f, P1 p1, P2 p2) {
return ReturnValueTraits<R>::Cast(
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
ParameterTraits<P2>::Cast(p2)));
}
template <typename R, typename F, typename P1, typename P2, typename P3>
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
return ReturnValueTraits<R>::Cast(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
}
template <typename R, typename F, typename P1, typename P2, typename P3,
typename P4>
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
return ReturnValueTraits<R>::Cast(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
ParameterTraits<P4>::Cast(p4)));
}
#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS)
uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
int32_t p3 = 0, int32_t p4 = 0) {

View File

@ -0,0 +1,5 @@
paul.lind@imgtec.com
gergely.kis@imgtec.com
akos.palfi@imgtec.com
balazs.kilvady@imgtec.com
dusan.milosavljevic@imgtec.com

View File

@ -0,0 +1,807 @@
// 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 "test/unittests/compiler/instruction-selector-unittest.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
template <typename T>
struct MachInst {
T constructor;
const char* constructor_name;
ArchOpcode arch_opcode;
MachineType machine_type;
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
return os << mi.constructor_name;
}
typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
// To avoid duplicated code IntCmp helper structure
// is created. It contains MachInst2 with two nodes and expected_size
// because different cmp instructions have different size.
struct IntCmp {
MachInst2 mi;
uint32_t expected_size;
};
struct FPCmp {
MachInst2 mi;
FlagsCondition cond;
};
const FPCmp kFPCmpInstructions[] = {
{{&RawMachineAssembler::Float64Equal, "Float64Equal", kMips64CmpD,
kMachFloat64},
kUnorderedEqual},
{{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMips64CmpD,
kMachFloat64},
kUnorderedLessThan},
{{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
kMips64CmpD, kMachFloat64},
kUnorderedLessThanOrEqual},
{{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan",
kMips64CmpD, kMachFloat64},
kUnorderedLessThan},
{{&RawMachineAssembler::Float64GreaterThanOrEqual,
"Float64GreaterThanOrEqual", kMips64CmpD, kMachFloat64},
kUnorderedLessThanOrEqual}};
struct Conversion {
// The machine_type field in MachInst1 represents the destination type.
MachInst1 mi;
MachineType src_machine_type;
};
// ----------------------------------------------------------------------------
// Logical instructions.
// ----------------------------------------------------------------------------
const MachInst2 kLogicalInstructions[] = {
{&RawMachineAssembler::Word32And, "Word32And", kMips64And, kMachInt32},
{&RawMachineAssembler::Word64And, "Word64And", kMips64And, kMachInt64},
{&RawMachineAssembler::Word32Or, "Word32Or", kMips64Or, kMachInt32},
{&RawMachineAssembler::Word64Or, "Word64Or", kMips64Or, kMachInt64},
{&RawMachineAssembler::Word32Xor, "Word32Xor", kMips64Xor, kMachInt32},
{&RawMachineAssembler::Word64Xor, "Word64Xor", kMips64Xor, kMachInt64}};
// ----------------------------------------------------------------------------
// Shift instructions.
// ----------------------------------------------------------------------------
const MachInst2 kShiftInstructions[] = {
{&RawMachineAssembler::Word32Shl, "Word32Shl", kMips64Shl, kMachInt32},
{&RawMachineAssembler::Word64Shl, "Word64Shl", kMips64Dshl, kMachInt64},
{&RawMachineAssembler::Word32Shr, "Word32Shr", kMips64Shr, kMachInt32},
{&RawMachineAssembler::Word64Shr, "Word64Shr", kMips64Dshr, kMachInt64},
{&RawMachineAssembler::Word32Sar, "Word32Sar", kMips64Sar, kMachInt32},
{&RawMachineAssembler::Word64Sar, "Word64Sar", kMips64Dsar, kMachInt64},
{&RawMachineAssembler::Word32Ror, "Word32Ror", kMips64Ror, kMachInt32},
{&RawMachineAssembler::Word64Ror, "Word64Ror", kMips64Dror, kMachInt64}};
// ----------------------------------------------------------------------------
// MUL/DIV instructions.
// ----------------------------------------------------------------------------
const MachInst2 kMulDivInstructions[] = {
{&RawMachineAssembler::Int32Mul, "Int32Mul", kMips64Mul, kMachInt32},
{&RawMachineAssembler::Int32Div, "Int32Div", kMips64Div, kMachInt32},
{&RawMachineAssembler::Uint32Div, "Uint32Div", kMips64DivU, kMachUint32},
{&RawMachineAssembler::Int64Mul, "Int64Mul", kMips64Dmul, kMachInt64},
{&RawMachineAssembler::Int64Div, "Int64Div", kMips64Ddiv, kMachInt64},
{&RawMachineAssembler::Uint64Div, "Uint64Div", kMips64DdivU, kMachUint64},
{&RawMachineAssembler::Float64Mul, "Float64Mul", kMips64MulD, kMachFloat64},
{&RawMachineAssembler::Float64Div, "Float64Div", kMips64DivD,
kMachFloat64}};
// ----------------------------------------------------------------------------
// MOD instructions.
// ----------------------------------------------------------------------------
const MachInst2 kModInstructions[] = {
{&RawMachineAssembler::Int32Mod, "Int32Mod", kMips64Mod, kMachInt32},
{&RawMachineAssembler::Uint32Mod, "Uint32Mod", kMips64ModU, kMachInt32},
{&RawMachineAssembler::Float64Mod, "Float64Mod", kMips64ModD,
kMachFloat64}};
// ----------------------------------------------------------------------------
// Arithmetic FPU instructions.
// ----------------------------------------------------------------------------
const MachInst2 kFPArithInstructions[] = {
{&RawMachineAssembler::Float64Add, "Float64Add", kMips64AddD, kMachFloat64},
{&RawMachineAssembler::Float64Sub, "Float64Sub", kMips64SubD,
kMachFloat64}};
// ----------------------------------------------------------------------------
// IntArithTest instructions, two nodes.
// ----------------------------------------------------------------------------
const MachInst2 kAddSubInstructions[] = {
{&RawMachineAssembler::Int32Add, "Int32Add", kMips64Add, kMachInt32},
{&RawMachineAssembler::Int64Add, "Int64Add", kMips64Dadd, kMachInt64},
{&RawMachineAssembler::Int32Sub, "Int32Sub", kMips64Sub, kMachInt32},
{&RawMachineAssembler::Int64Sub, "Int64Sub", kMips64Dsub, kMachInt64}};
// ----------------------------------------------------------------------------
// IntArithTest instructions, one node.
// ----------------------------------------------------------------------------
const MachInst1 kAddSubOneInstructions[] = {
{&RawMachineAssembler::Int32Neg, "Int32Neg", kMips64Sub, kMachInt32},
{&RawMachineAssembler::Int64Neg, "Int64Neg", kMips64Dsub, kMachInt64}};
// ----------------------------------------------------------------------------
// Arithmetic compare instructions.
// ----------------------------------------------------------------------------
const IntCmp kCmpInstructions[] = {
{{&RawMachineAssembler::WordEqual, "WordEqual", kMips64Cmp, kMachInt64},
1U},
{{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp,
kMachInt64},
1U},
{{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp32,
kMachInt32},
1U},
{{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp32,
kMachInt32},
1U},
{{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp32,
kMachInt32},
1U},
{{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
kMips64Cmp32, kMachInt32},
1U},
{{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp32,
kMachInt32},
1U},
{{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
kMips64Cmp32, kMachInt32},
1U},
{{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp32,
kMachUint32},
1U},
{{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
kMips64Cmp32, kMachUint32},
1U}};
// ----------------------------------------------------------------------------
// Conversion instructions.
// ----------------------------------------------------------------------------
const Conversion kConversionInstructions[] = {
// Conversion instructions are related to machine_operator.h:
// FPU conversions:
// Convert representation of integers between float64 and int32/uint32.
// The precise rounding mode and handling of out of range inputs are *not*
// defined for these operators, since they are intended only for use with
// integers.
// mips instructions:
// mtc1, cvt.d.w
{{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
kMips64CvtDW, kMachFloat64},
kMachInt32},
// mips instructions:
// cvt.d.uw
{{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
kMips64CvtDUw, kMachFloat64},
kMachInt32},
// mips instructions:
// mfc1, trunc double to word, for more details look at mips macro
// asm and mips asm file
{{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
kMips64TruncWD, kMachFloat64},
kMachInt32},
// mips instructions:
// trunc double to unsigned word, for more details look at mips macro
// asm and mips asm file
{{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
kMips64TruncUwD, kMachFloat64},
kMachInt32}};
} // namespace
typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
TEST_P(InstructionSelectorFPCmpTest, Parameter) {
const FPCmp cmp = GetParam();
StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(cmp.cond, s[0]->flags_condition());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
::testing::ValuesIn(kFPCmpInstructions));
// ----------------------------------------------------------------------------
// Arithmetic compare instructions integers
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<IntCmp> InstructionSelectorCmpTest;
TEST_P(InstructionSelectorCmpTest, Parameter) {
const IntCmp cmp = GetParam();
const MachineType type = cmp.mi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(cmp.expected_size, s.size());
EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
::testing::ValuesIn(kCmpInstructions));
// ----------------------------------------------------------------------------
// Shift instructions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorShiftTest;
TEST_P(InstructionSelectorShiftTest, Immediate) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
StreamBuilder m(this, type, type);
m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
::testing::ValuesIn(kShiftInstructions));
// ----------------------------------------------------------------------------
// Logical instructions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorLogicalTest;
TEST_P(InstructionSelectorLogicalTest, Parameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
::testing::ValuesIn(kLogicalInstructions));
// ----------------------------------------------------------------------------
// MUL/DIV instructions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorMulDivTest;
TEST_P(InstructionSelectorMulDivTest, Parameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
::testing::ValuesIn(kMulDivInstructions));
// ----------------------------------------------------------------------------
// MOD instructions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2> InstructionSelectorModTest;
TEST_P(InstructionSelectorModTest, Parameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorModTest,
::testing::ValuesIn(kModInstructions));
// ----------------------------------------------------------------------------
// Floating point instructions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorFPArithTest;
TEST_P(InstructionSelectorFPArithTest, Parameter) {
const MachInst2 fpa = GetParam();
StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
::testing::ValuesIn(kFPArithInstructions));
// ----------------------------------------------------------------------------
// Integer arithmetic
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorIntArithTwoTest;
TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
const MachInst2 intpa = GetParam();
StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
intpa.machine_type);
m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorIntArithTwoTest,
::testing::ValuesIn(kAddSubInstructions));
// ----------------------------------------------------------------------------
// One node.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MachInst1>
InstructionSelectorIntArithOneTest;
TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
const MachInst1 intpa = GetParam();
StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
intpa.machine_type);
m.Return((m.*intpa.constructor)(m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorIntArithOneTest,
::testing::ValuesIn(kAddSubOneInstructions));
// ----------------------------------------------------------------------------
// Conversions.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<Conversion>
InstructionSelectorConversionTest;
TEST_P(InstructionSelectorConversionTest, Parameter) {
const Conversion conv = GetParam();
StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorConversionTest,
::testing::ValuesIn(kConversionInstructions));
// ----------------------------------------------------------------------------
// Loads and stores.
// ----------------------------------------------------------------------------
namespace {
struct MemoryAccess {
MachineType type;
ArchOpcode load_opcode;
ArchOpcode store_opcode;
};
static const MemoryAccess kMemoryAccesses[] = {
{kMachInt8, kMips64Lb, kMips64Sb},
{kMachUint8, kMips64Lbu, kMips64Sb},
{kMachInt16, kMips64Lh, kMips64Sh},
{kMachUint16, kMips64Lhu, kMips64Sh},
{kMachInt32, kMips64Lw, kMips64Sw},
{kRepFloat32, kMips64Lwc1, kMips64Swc1},
{kRepFloat64, kMips64Ldc1, kMips64Sdc1},
{kMachInt64, kMips64Ld, kMips64Sd}};
struct MemoryAccessImm {
MachineType type;
ArchOpcode load_opcode;
ArchOpcode store_opcode;
bool (InstructionSelectorTest::Stream::*val_predicate)(
const InstructionOperand*) const;
const int32_t immediates[40];
};
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
return os << acc.type;
}
struct MemoryAccessImm1 {
MachineType type;
ArchOpcode load_opcode;
ArchOpcode store_opcode;
bool (InstructionSelectorTest::Stream::*val_predicate)(
const InstructionOperand*) const;
const int32_t immediates[5];
};
std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
return os << acc.type;
}
// ----------------------------------------------------------------------------
// Loads and stores immediate values
// ----------------------------------------------------------------------------
const MemoryAccessImm kMemoryAccessesImm[] = {
{kMachInt8,
kMips64Lb,
kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachUint8,
kMips64Lbu,
kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachInt16,
kMips64Lh,
kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachUint16,
kMips64Lhu,
kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachInt32,
kMips64Lw,
kMips64Sw,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachFloat32,
kMips64Lwc1,
kMips64Swc1,
&InstructionSelectorTest::Stream::IsDouble,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachFloat64,
kMips64Ldc1,
kMips64Sdc1,
&InstructionSelectorTest::Stream::IsDouble,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
{kMachInt64,
kMips64Ld,
kMips64Sd,
&InstructionSelectorTest::Stream::IsInteger,
{-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
-87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
{kMachInt8,
kMips64Lb,
kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}},
{kMachInt8,
kMips64Lbu,
kMips64Sb,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}},
{kMachInt16,
kMips64Lh,
kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}},
{kMachInt16,
kMips64Lhu,
kMips64Sh,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}},
{kMachInt32,
kMips64Lw,
kMips64Sw,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}},
{kMachFloat32,
kMips64Lwc1,
kMips64Swc1,
&InstructionSelectorTest::Stream::IsDouble,
{-65000, -55000, 32777, 55000, 65000}},
{kMachFloat64,
kMips64Ldc1,
kMips64Sdc1,
&InstructionSelectorTest::Stream::IsDouble,
{-65000, -55000, 32777, 55000, 65000}},
{kMachInt64,
kMips64Ld,
kMips64Sd,
&InstructionSelectorTest::Stream::IsInteger,
{-65000, -55000, 32777, 55000, 65000}}};
} // namespace
typedef InstructionSelectorTestWithParam<MemoryAccess>
InstructionSelectorMemoryAccessTest;
TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
const MemoryAccess memacc = GetParam();
StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
m.Return(m.Load(memacc.type, m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
}
TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
const MemoryAccess memacc = GetParam();
StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
m.Store(memacc.type, m.Parameter(0), m.Parameter(1));
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessTest,
::testing::ValuesIn(kMemoryAccesses));
// ----------------------------------------------------------------------------
// Load immediate.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MemoryAccessImm>
InstructionSelectorMemoryAccessImmTest;
TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
const MemoryAccessImm memacc = GetParam();
TRACED_FOREACH(int32_t, index, memacc.immediates) {
StreamBuilder m(this, memacc.type, kMachPtr);
m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
}
}
// ----------------------------------------------------------------------------
// Store immediate.
// ----------------------------------------------------------------------------
TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
const MemoryAccessImm memacc = GetParam();
TRACED_FOREACH(int32_t, index, memacc.immediates) {
StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
m.Parameter(1));
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(0U, s[0]->OutputCount());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessImmTest,
::testing::ValuesIn(kMemoryAccessesImm));
// ----------------------------------------------------------------------------
// Load/store offsets more than 16 bits.
// ----------------------------------------------------------------------------
typedef InstructionSelectorTestWithParam<MemoryAccessImm1>
InstructionSelectorMemoryAccessImmMoreThan16bitTest;
TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
LoadWithImmediateIndex) {
const MemoryAccessImm1 memacc = GetParam();
TRACED_FOREACH(int32_t, index, memacc.immediates) {
StreamBuilder m(this, memacc.type, kMachPtr);
m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
// kMips64Dadd is expected opcode
// size more than 16 bits wide
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
StoreWithImmediateIndex) {
const MemoryAccessImm1 memacc = GetParam();
TRACED_FOREACH(int32_t, index, memacc.immediates) {
StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
m.Parameter(1));
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
// kMips64Add is expected opcode
// size more than 16 bits wide
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessImmMoreThan16bitTest,
::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
// ----------------------------------------------------------------------------
// kMips64Cmp with zero testing.
// ----------------------------------------------------------------------------
TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
{
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
}
{
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
{
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
}
{
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Word64Equal(m.Int32Constant(0), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -87,6 +87,11 @@
'compiler/mips/instruction-selector-mips-unittest.cc',
],
}],
['v8_target_arch=="mips64el"', {
'sources': [ ### gcmole(arch:mips64el) ###
'compiler/mips64/instruction-selector-mips64-unittest.cc',
],
}],
['v8_target_arch=="x64"', {
'sources': [ ### gcmole(arch:x64) ###
'compiler/x64/instruction-selector-x64-unittest.cc',

View File

@ -1116,6 +1116,10 @@
'../../src/mips64/regexp-macro-assembler-mips64.cc',
'../../src/mips64/regexp-macro-assembler-mips64.h',
'../../src/mips64/simulator-mips64.cc',
'../../src/compiler/mips64/code-generator-mips64.cc',
'../../src/compiler/mips64/instruction-codes-mips64.h',
'../../src/compiler/mips64/instruction-selector-mips64.cc',
'../../src/compiler/mips64/linkage-mips64.cc',
'../../src/ic/mips64/access-compiler-mips64.cc',
'../../src/ic/mips64/handler-compiler-mips64.cc',
'../../src/ic/mips64/ic-mips64.cc',