| 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());
|
|
|