| Index: src/compiler/mips/instruction-selector-mips.cc
|
| diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc
|
| index 2519b9331db35ee20cd7ad2e584d1b560e47685d..f81b7e9e928a542b1c0dec6bbad431a421aeaf40 100644
|
| --- a/src/compiler/mips/instruction-selector-mips.cc
|
| +++ b/src/compiler/mips/instruction-selector-mips.cc
|
| @@ -307,6 +307,104 @@ void InstructionSelector::VisitWord32And(Node* node) {
|
|
|
|
|
| void InstructionSelector::VisitWord32Or(Node* node) {
|
| + Int32BinopMatcher orm(node);
|
| +
|
| + bool unalignedMatched = false;
|
| + bool loadSigned = false;
|
| +
|
| + int i = 0;
|
| + uintptr_t prevAddress = 0;
|
| + Node* smallestLoad = NULL;
|
| +
|
| + // Unligned access is simulated using combinations of
|
| + // load byte, shift and or operations, like this
|
| + // Result = 0
|
| + // Result = LoadByte (high) | Result << 8
|
| + // Result = LoadByte (high - 1) | Result << 8
|
| + // ...
|
| + // Result = LoadByte (low) | Result << 8
|
| + // We are trying to match the graph that corresponds
|
| + // to the above operations and reduce it to
|
| + // one simple Unaligned load
|
| + while (orm.left().IsWord32Shl() && orm.right().IsLoad()) {
|
| + Int32BinopMatcher shl(orm.left().node());
|
| + LoadMatcher<PtrMatcher> load(orm.right().node());
|
| +
|
| + // Verifying load address
|
| + if (load.object().HasValue()) {
|
| + // Assumption is that the first byte will
|
| + // always be the most significant
|
| + if (prevAddress == 0) {
|
| + prevAddress = load.object().Value();
|
| + smallestLoad = load.node();
|
| + } else {
|
| + // Verifying that load addresses are consecutive
|
| + if (prevAddress + 1 != load.object().Value()) {
|
| + unalignedMatched = false;
|
| + break;
|
| + }
|
| + prevAddress = load.object().Value();
|
| + loadSigned = LoadRepresentationOf(load.node()->op()).IsSigned();
|
| + }
|
| + } else {
|
| + unalignedMatched = false;
|
| + break;
|
| + }
|
| +
|
| + if (shl.left().IsWord32Or() && shl.right().Is(8)) {
|
| + orm = Int32BinopMatcher(shl.left().node());
|
| + } else if (shl.left().Is(0)) {
|
| + unalignedMatched = true;
|
| + break;
|
| + } else {
|
| + unalignedMatched = false;
|
| + break;
|
| + }
|
| +
|
| + i++;
|
| + // Something is not right, the graph is too deep, break
|
| + if (i > 8) {
|
| + unalignedMatched = false;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (unalignedMatched) {
|
| + MipsOperandGenerator g(this);
|
| + ArchOpcode opcode = kArchNop;
|
| +
|
| + if (i == 3) {
|
| + opcode = kMipsUlw;
|
| + } else if (i == 1) {
|
| + opcode = loadSigned ? kMipsUlh : kMipsUlhu;
|
| + } else {
|
| + unalignedMatched = false;
|
| + }
|
| +
|
| + if (unalignedMatched) {
|
| + MipsOperandGenerator g(this);
|
| +
|
| + DCHECK(smallestLoad != NULL);
|
| +
|
| + Node* base = smallestLoad->InputAt(0);
|
| + Node* index = smallestLoad->InputAt(1);
|
| +
|
| + 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(kMipsAdd | 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));
|
| + }
|
| + return;
|
| + }
|
| + }
|
| +
|
| VisitBinop(this, node, kMipsOr);
|
| }
|
|
|
| @@ -972,6 +1070,100 @@ bool InstructionSelector::IsTailCallAddressImmediate() { return false; }
|
|
|
| int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; }
|
|
|
| +void InstructionSelector::VisitUnalignedLoad(Node* node) {
|
| + UnalignedLoadRepresentation load_rep =
|
| + UnalignedLoadRepresentationOf(node->op());
|
| + MipsOperandGenerator g(this);
|
| + Node* base = node->InputAt(0);
|
| + Node* index = node->InputAt(1);
|
| +
|
| + ArchOpcode opcode = kArchNop;
|
| + switch (load_rep.representation()) {
|
| + case MachineRepresentation::kBit: // Fall through.
|
| + case MachineRepresentation::kWord8:
|
| + opcode = load_rep.IsUnsigned() ? kMipsLbu : kMipsLb;
|
| + break;
|
| + case MachineRepresentation::kWord16:
|
| + opcode = load_rep.IsUnsigned() ? kMipsUlhu : kMipsUlh;
|
| + break;
|
| + case MachineRepresentation::kTagged: // Fall through.
|
| + case MachineRepresentation::kWord32:
|
| + opcode = kMipsUlw;
|
| + break;
|
| + case MachineRepresentation::kFloat32:
|
| + opcode = kMipsUlwc1;
|
| + break;
|
| + case MachineRepresentation::kFloat64:
|
| + opcode = kMipsUldc1;
|
| + break;
|
| + case MachineRepresentation::kWord64: // Fall through.
|
| + case MachineRepresentation::kSimd128: // Fall through.
|
| + case MachineRepresentation::kNone:
|
| + 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(kMipsAdd | 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::VisitUnalignedStore(Node* node) {
|
| + MipsOperandGenerator g(this);
|
| + Node* base = node->InputAt(0);
|
| + Node* index = node->InputAt(1);
|
| + Node* value = node->InputAt(2);
|
| +
|
| + UnalignedStoreRepresentation rep = UnalignedStoreRepresentationOf(node->op());
|
| +
|
| + // TODO(mips): I guess this could be done in a better way.
|
| + ArchOpcode opcode = kArchNop;
|
| + switch (rep) {
|
| + case MachineRepresentation::kFloat32:
|
| + opcode = kMipsUswc1;
|
| + break;
|
| + case MachineRepresentation::kFloat64:
|
| + opcode = kMipsUsdc1;
|
| + break;
|
| + case MachineRepresentation::kBit: // Fall through.
|
| + case MachineRepresentation::kWord8:
|
| + opcode = kMipsSb;
|
| + break;
|
| + case MachineRepresentation::kWord16:
|
| + opcode = kMipsUsh;
|
| + break;
|
| + case MachineRepresentation::kTagged: // Fall through.
|
| + case MachineRepresentation::kWord32:
|
| + opcode = kMipsUsw;
|
| + break;
|
| + case MachineRepresentation::kWord64: // Fall through.
|
| + case MachineRepresentation::kSimd128: // Fall through.
|
| + case MachineRepresentation::kNone:
|
| + UNREACHABLE();
|
| + return;
|
| + }
|
| +
|
| + if (g.CanBeImmediate(index, opcode)) {
|
| + Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(),
|
| + g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
|
| + } else {
|
| + InstructionOperand addr_reg = g.TempRegister();
|
| + Emit(kMipsAdd | 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), g.NoOutput(),
|
| + addr_reg, g.TempImmediate(0), g.UseRegister(value));
|
| + }
|
| +}
|
| +
|
| void InstructionSelector::VisitCheckedLoad(Node* node) {
|
| CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
|
| MipsOperandGenerator g(this);
|
| @@ -1464,6 +1656,13 @@ InstructionSelector::SupportedMachineOperatorFlags() {
|
| MachineOperatorBuilder::kFloat64RoundTruncate |
|
| MachineOperatorBuilder::kFloat64RoundTiesEven;
|
| }
|
| +
|
| + if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1)) ||
|
| + IsMipsArchVariant(kLoongson)) {
|
| + flags |= MachineOperatorBuilder::kUnalignedLoad |
|
| + MachineOperatorBuilder::kUnalignedStore;
|
| + }
|
| +
|
| return flags | MachineOperatorBuilder::kWord32Ctz |
|
| MachineOperatorBuilder::kWord32Popcnt |
|
| MachineOperatorBuilder::kInt32DivIsSafe |
|
|
|