Index: src/compiler/mips64/instruction-selector-mips64.cc |
diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc |
index 1b3b6a6d62ccfc598253072bb32c7c83934f145a..6f72c6451d1fb920c0aae444f7cf1dbeb3ff6182 100644 |
--- a/src/compiler/mips64/instruction-selector-mips64.cc |
+++ b/src/compiler/mips64/instruction-selector-mips64.cc |
@@ -31,14 +31,25 @@ class Mips64OperandGenerator final : public OperandGenerator { |
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; |
+ bool IsIntegerConstant(Node* node) { |
+ return (node->opcode() == IrOpcode::kInt32Constant) || |
+ (node->opcode() == IrOpcode::kInt64Constant); |
+ } |
+ |
+ int64_t GetIntegerConstantValue(Node* node) { |
+ if (node->opcode() == IrOpcode::kInt32Constant) { |
+ return OpParameter<int32_t>(node); |
+ } |
+ DCHECK(node->opcode() == IrOpcode::kInt64Constant); |
+ return OpParameter<int64_t>(node); |
+ } |
+ |
+ bool CanBeImmediate(Node* node, InstructionCode mode) { |
+ return IsIntegerConstant(node) && |
+ CanBeImmediate(GetIntegerConstantValue(node), mode); |
+ } |
+ |
+ bool CanBeImmediate(int64_t value, InstructionCode opcode) { |
switch (ArchOpcodeField::decode(opcode)) { |
case kMips64Shl: |
case kMips64Sar: |
@@ -91,6 +102,76 @@ static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, |
g.UseOperand(node->InputAt(1), opcode)); |
} |
+struct ExtendingLoadMatcher { |
+ ExtendingLoadMatcher(Node* node, InstructionSelector* selector) |
+ : matches_(false), selector_(selector), base_(nullptr), immediate_(0) { |
+ Initialize(node); |
+ } |
+ |
+ bool Matches() const { return matches_; } |
+ |
+ Node* base() const { |
+ DCHECK(Matches()); |
+ return base_; |
+ } |
+ int64_t immediate() const { |
+ DCHECK(Matches()); |
+ return immediate_; |
+ } |
+ ArchOpcode opcode() const { |
+ DCHECK(Matches()); |
+ return opcode_; |
+ } |
+ |
+ private: |
+ bool matches_; |
+ InstructionSelector* selector_; |
+ Node* base_; |
+ int64_t immediate_; |
+ ArchOpcode opcode_; |
+ |
+ void Initialize(Node* node) { |
+ Int64BinopMatcher m(node); |
+ // When loading a 64-bit value and shifting by 32, we should |
+ // just load and sign-extend the interesting 4 bytes instead. |
+ // This happens, for example, when we're loading and untagging SMIs. |
+ DCHECK(m.IsWord64Sar()); |
+ if (m.left().IsLoad() && m.right().Is(32) && |
+ selector_->CanCover(m.node(), m.left().node())) { |
+ Mips64OperandGenerator g(selector_); |
+ Node* load = m.left().node(); |
+ Node* offset = load->InputAt(1); |
+ base_ = load->InputAt(0); |
+ opcode_ = kMips64Lw; |
+ if (g.CanBeImmediate(offset, opcode_)) { |
+#if defined(V8_TARGET_LITTLE_ENDIAN) |
+ immediate_ = g.GetIntegerConstantValue(offset) + 4; |
+#elif defined(V8_TARGET_BIG_ENDIAN) |
+ immediate_ = g.GetIntegerConstantValue(offset); |
+#endif |
+ matches_ = g.CanBeImmediate(immediate_, kMips64Lw); |
+ } |
+ } |
+ } |
+}; |
+ |
+bool TryEmitExtendingLoad(InstructionSelector* selector, Node* node) { |
+ ExtendingLoadMatcher m(node, selector); |
+ Mips64OperandGenerator g(selector); |
+ if (m.Matches()) { |
+ InstructionOperand inputs[2]; |
+ inputs[0] = g.UseRegister(m.base()); |
+ InstructionCode opcode = |
+ m.opcode() | AddressingModeField::encode(kMode_MRI); |
+ DCHECK(is_int32(m.immediate())); |
+ inputs[1] = g.TempImmediate(static_cast<int32_t>(m.immediate())); |
+ InstructionOperand outputs[] = {g.DefineAsRegister(node)}; |
+ selector->Emit(opcode, arraysize(outputs), outputs, arraysize(inputs), |
+ inputs); |
+ return true; |
+ } |
+ return false; |
+} |
static void VisitBinop(InstructionSelector* selector, Node* node, |
InstructionCode opcode, FlagsContinuation* cont) { |
@@ -597,6 +678,7 @@ void InstructionSelector::VisitWord64Shr(Node* node) { |
void InstructionSelector::VisitWord64Sar(Node* node) { |
+ if (TryEmitExtendingLoad(this, node)) return; |
VisitRRO(this, kMips64Dsar, node); |
} |