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

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: Rebase on master's machine-operator-reducer changes 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 b8d2d905e45681b9933250f3a27e78e35593f82c..536b0fcd18ec49ef3f927ac332adeef59c7191b2 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -304,6 +304,64 @@ 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);
+}
+
+void SimplifyAndForMaskedStore(InstructionSelector* selector, Node* node,
+ Node* value, ArchOpcode opcode) {
+ ArmOperandGenerator g(selector);
+ NodeMatcher nm(value);
+ if (nm.IsWord32And() && selector->CanCover(node, value)) {
+ Uint32BinopMatcher m(value);
+ if (m.right().HasValue() &&
+ ((opcode == kCheckedStoreWord16) || (opcode == kArmStrh))) {
+ uint32_t mask = m.right().Value();
+
+ // Halfword stores effectively apply 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.
+ }
+ }
+}
+
} // namespace
@@ -339,13 +397,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 +475,8 @@ void InstructionSelector::VisitStore(Node* node) {
return;
}
+ 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 +519,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);
}
@@ -507,6 +555,9 @@ void InstructionSelector::VisitCheckedStore(Node* node) {
UNREACHABLE();
return;
}
+
+ SimplifyAndForMaskedStore(this, node, value, opcode);
+
InstructionOperand offset_operand = g.UseRegister(offset);
InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp)
? g.UseImmediate(length)
@@ -545,6 +596,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 +657,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