Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Unified Diff: src/compiler/arm/instruction-selector-arm.cc

Issue 1883133002: [turbofan] ARM: elide masks on loads and stores (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/unittests/compiler/arm/instruction-selector-arm-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/arm/instruction-selector-arm.cc
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
index ef0bb6800e4933ecf905a65f3ca03558760db289..16712addffbd26a94a0b612eb9bad6767455af2e 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -304,6 +304,78 @@ void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
}
}
+void EmitLoad(InstructionSelector* selector, ArchOpcode opcode, Node* node,
+ Node* const base, Node* const index) {
+ ArmOperandGenerator g(selector);
+ InstructionCode icode;
+ InstructionOperand index_operand;
+ if (g.CanBeImmediate(index, opcode)) {
+ icode = opcode | AddressingModeField::encode(kMode_Offset_RI);
+ index_operand = g.UseImmediate(index);
+ } else {
+ icode = opcode | AddressingModeField::encode(kMode_Offset_RR);
+ index_operand = g.UseRegister(index);
+ }
+ selector->Emit(icode, g.DefineAsRegister(node), g.UseRegister(base),
+ index_operand);
+}
+
+void EmitCheckedLoad(InstructionSelector* selector, ArchOpcode opcode,
+ Node* node, Node* const buffer, Node* const offset,
+ Node* const length) {
+ ArmOperandGenerator g(selector);
+ InstructionOperand offset_operand = g.UseRegister(offset);
+ InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
+ ? g.UseImmediate(length)
+ : g.UseRegister(length);
+ selector->Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
+ g.DefineAsRegister(node), offset_operand, length_operand,
+ g.UseRegister(buffer), offset_operand);
+}
+
+// Simplify or elide mask on 8-bit and 16-bit stores. Returns the input node of
+// the mask operation if it can be elided, otherwise the value node.
+Node* SimplifyAndForMaskedStore(InstructionSelector* selector, Node* node,
Benedikt Meurer 2016/04/14 18:39:58 This looks like something that should be done in t
martyn.capewell 2016/04/15 14:05:49 You're right, I should update MachineOperatorReduc
+ Node* value, ArchOpcode opcode) {
+ ArmOperandGenerator g(selector);
+ NodeMatcher nm(value);
+ if (nm.IsWord32And() && selector->CanCover(node, value)) {
+ Uint32BinopMatcher m(value);
+ if (m.right().HasValue()) {
+ uint32_t mask = m.right().Value();
+
+ // Rewrite the opcode to make the later if statement simpler.
+ opcode = (opcode == kCheckedStoreWord8) ? kArmStrb : opcode;
+ opcode = (opcode == kCheckedStoreWord16) ? kArmStrh : opcode;
+
+ if (((opcode == kArmStrb) && ((mask & 0xff) == 0xff)) ||
+ ((opcode == kArmStrh) && ((mask & 0xffff) == 0xffff))) {
+ // The masking operation can be elided, so return the left input to the
+ // mask.
+ return m.left().node();
+ } else if (opcode == kArmStrh) {
+ // Strh effectively applies a mask of 0xffff, so simplify the AND's mask
+ // using this, with the aim of making the new immediate encodable in the
+ // instruction.
+ mask &= 0xffff;
+ if (g.CanBeImmediate(mask)) {
+ selector->Emit(
+ kArmAnd | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(value), g.UseRegister(m.left().node()),
+ g.TempImmediate(mask));
+ } else if (g.CanBeImmediate(mask ^ 0xffff)) {
+ selector->Emit(
+ kArmBic | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(value), g.UseRegister(m.left().node()),
+ g.TempImmediate(mask ^ 0xffff));
+ }
+ }
+ // TODO(turbofan): Consider similar optimisation for strb/and 0xff.
+ }
+ }
+ return value;
+}
+
} // namespace
@@ -339,13 +411,7 @@ void InstructionSelector::VisitLoad(Node* node) {
return;
}
- if (g.CanBeImmediate(index, opcode)) {
- Emit(opcode | AddressingModeField::encode(kMode_Offset_RI),
- g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
- } else {
- Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
- g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
- }
+ EmitLoad(this, opcode, node, base, index);
}
@@ -423,6 +489,8 @@ void InstructionSelector::VisitStore(Node* node) {
return;
}
+ value = SimplifyAndForMaskedStore(this, node, value, opcode);
+
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(),
g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
@@ -465,13 +533,7 @@ void InstructionSelector::VisitCheckedLoad(Node* node) {
UNREACHABLE();
return;
}
- InstructionOperand offset_operand = g.UseRegister(offset);
- InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
- ? g.UseImmediate(length)
- : g.UseRegister(length);
- Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
- g.DefineAsRegister(node), offset_operand, length_operand,
- g.UseRegister(buffer), offset_operand);
+ EmitCheckedLoad(this, opcode, node, buffer, offset, length);
}
@@ -481,7 +543,7 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
Node* const buffer = node->InputAt(0);
Node* const offset = node->InputAt(1);
Node* const length = node->InputAt(2);
- Node* const value = node->InputAt(3);
+ Node* value = node->InputAt(3);
ArchOpcode opcode = kArchNop;
switch (rep) {
case MachineRepresentation::kWord8:
@@ -507,6 +569,9 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
UNREACHABLE();
return;
}
+
+ value = SimplifyAndForMaskedStore(this, node, value, opcode);
+
InstructionOperand offset_operand = g.UseRegister(offset);
InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
? g.UseImmediate(length)
@@ -545,6 +610,42 @@ void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
g.TempImmediate(lsb), g.TempImmediate(width));
}
+// Try to emit an AND or BIC instruction when the left input is an 8/16-bit
+// load. Returns true if an instruction was emitted, false otherwise.
+bool TryEmitAndForMaskedLoad(InstructionSelector* selector, Node* node,
+ MachineType type, uint32_t value) {
+ ArmOperandGenerator g(selector);
+ Int32BinopMatcher m(node);
+ if (type == MachineType::Uint16()) {
+ // The input load has already applied a 0xffff mask to the input, so
+ // simplify the value and test if it's an immediate that can be encoded in
+ // the instruction.
+ value &= 0xffff;
+ if (g.CanBeImmediate(value)) {
+ selector->Emit(kArmAnd | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(value));
+ return true;
+ }
+ // Test if an inverted value can be used with BIC.
+ if (g.CanBeImmediate(value ^ 0xffff)) {
+ selector->Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(value ^ 0xffff));
+ return true;
+ }
+ } else if (type == MachineType::Uint8()) {
+ // The input load has already applied a 0xff mask to the input.
+ value &= 0xff;
+ DCHECK(g.CanBeImmediate(value)); // All 8-bit values are encodable.
+ selector->Emit(kArmAnd | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(value));
+ return true;
+ }
+ return false;
+}
+
} // namespace
@@ -570,6 +671,46 @@ void InstructionSelector::VisitWord32And(Node* node) {
uint32_t width = base::bits::CountPopulation32(value);
uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
+ if (m.left().IsLoad()) {
+ LoadRepresentation load_rep = LoadRepresentationOf(m.left().node()->op());
+ if (CanCover(node, m.left().node()) &&
+ ((value == 0xff) || (value == 0xffff))) {
+ // Elide mask operation on load inputs by modifying the size of the
+ // load.
+ ArchOpcode opcode = kArmLdrb;
+ if ((value == 0xffff) &&
+ (load_rep.representation() != MachineRepresentation::kWord8)) {
+ opcode = kArmLdrh;
+ }
+ EmitLoad(this, opcode, node, m.left().InputAt(0), m.left().InputAt(1));
+ return;
+ }
+ if (!g.CanBeImmediate(value) &&
+ TryEmitAndForMaskedLoad(this, node, load_rep, value)) {
+ return;
+ }
+ } else if (m.left().IsCheckedLoad()) {
+ CheckedLoadRepresentation load_rep =
+ CheckedLoadRepresentationOf(m.left().node()->op());
+ if (CanCover(node, m.left().node()) &&
+ ((value == 0xff) || (value == 0xffff))) {
+ // Elide mask operation on load inputs by modifying the size of the
+ // load.
+ ArchOpcode opcode = kCheckedLoadUint8;
+ if ((value == 0xffff) &&
+ (load_rep.representation() != MachineRepresentation::kWord8)) {
+ opcode = kCheckedLoadUint16;
+ }
+ EmitCheckedLoad(this, opcode, node, m.left().InputAt(0),
+ m.left().InputAt(1), m.left().InputAt(2));
+ return;
+ }
+ if (!g.CanBeImmediate(value) &&
+ TryEmitAndForMaskedLoad(this, node, load_rep, value)) {
+ return;
+ }
+ }
+
// Try to merge SHR operations on the left hand input into this AND.
if (m.left().IsWord32Shr()) {
Int32BinopMatcher mshr(m.left().node());
« no previous file with comments | « no previous file | test/unittests/compiler/arm/instruction-selector-arm-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698