Chromium Code Reviews| Index: src/arm64/lithium-arm64.cc |
| diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc |
| index 34c98241a5cb4093271853028656cf551d3fdb27..8a541d56299fe53f09ed26b852f85ff7e2071d18 100644 |
| --- a/src/arm64/lithium-arm64.cc |
| +++ b/src/arm64/lithium-arm64.cc |
| @@ -825,6 +825,12 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { |
| if (instr->representation().IsSmiOrInteger32()) { |
| ASSERT(instr->left()->representation().Equals(instr->representation())); |
| ASSERT(instr->right()->representation().Equals(instr->representation())); |
| + |
| + LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| + if (shifted_operation != NULL) { |
| + return shifted_operation; |
| + } |
| + |
| LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); |
| LOperand* right = |
| UseRegisterOrConstantAtStart(instr->BetterRightOperand()); |
| @@ -905,6 +911,11 @@ LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { |
| ASSERT(instr->right()->representation().Equals(instr->representation())); |
| ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32)); |
| + LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| + if (shifted_operation != NULL) { |
| + return shifted_operation; |
| + } |
| + |
| LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); |
| LOperand* right = |
| UseRegisterOrConstantAtStart(instr->BetterRightOperand()); |
| @@ -2030,6 +2041,120 @@ LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { |
| } |
| +HBitwiseBinaryOperation* LChunkBuilder::CanTransformToShiftedOp(HValue* val, |
| + HValue** left) { |
| + if (!val->representation().IsInteger32()) return NULL; |
| + if (!val->IsBitwise() && !(val->IsAdd() || val->IsSub())) return NULL; |
|
ulan
2014/05/02 10:01:18
Simpler condition: !(val->IsBitwise() || val->IsAd
Alexandre Rames
2014/05/02 13:51:44
Done.
|
| + |
| + HBinaryOperation* hinstr = HBinaryOperation::cast(val); |
| + HValue* hleft = hinstr->left(); |
| + HValue* hright = hinstr->right(); |
| + ASSERT(hleft->representation().Equals(hinstr->representation())); |
| + ASSERT(hright->representation().Equals(hinstr->representation())); |
| + |
| + if ((hright->IsConstant() && |
| + LikelyFitsImmField(hinstr, HConstant::cast(hright)->Integer32Value())) || |
| + (hinstr->IsCommutative() && hleft->IsConstant() && |
| + LikelyFitsImmField(hinstr, HConstant::cast(hleft)->Integer32Value()))) { |
| + // The constant operand will likely fit in the immediate field. We are |
| + // better off with |
| + // lsl x8, x9, #imm |
| + // add x0, x8, #imm2 |
| + // than with |
| + // mov x16, #imm2 |
| + // add x0, x16, x9 LSL #imm |
| + return NULL; |
| + } |
| + |
| + HBitwiseBinaryOperation* shift = NULL; |
| + // TODO(aleram): We will miss situations where a shift operation is used by |
| + // different instructions both as a left and right operands. |
| + if (hright->IsBitwiseBinaryShift() && |
| + HBitwiseBinaryOperation::cast(hright)->right()->IsConstant()) { |
| + shift = HBitwiseBinaryOperation::cast(hright); |
| + if (left != NULL) { |
| + *left = hleft; |
| + } |
| + } else if (hinstr->IsCommutative() && |
| + hleft->IsBitwiseBinaryShift() && |
| + HBitwiseBinaryOperation::cast(hleft)->right()->IsConstant()) { |
| + shift = HBitwiseBinaryOperation::cast(hleft); |
| + if (left != NULL) { |
| + *left = hright; |
| + } |
| + } else { |
| + return NULL; |
| + } |
| + |
| + if ((ShiftAmountFromHConstant(shift->right()) == 0) && shift->IsShr()) { |
| + // Shifts right by zero can deoptimize. |
| + return NULL; |
| + } |
| + |
| + return shift; |
| +} |
| + |
| + |
| +bool LChunkBuilder::ShiftCanBeOptimizedAway(HBitwiseBinaryOperation* shift) { |
| + if (!shift->representation().IsInteger32()) { |
| + return false; |
| + } |
| + for (HUseIterator it(shift->uses()); !it.Done(); it.Advance()) { |
| + if (shift != CanTransformToShiftedOp(it.value())) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| + |
| +LInstruction* LChunkBuilder::TryDoOpWithShiftedRightOperand( |
| + HBinaryOperation* instr) { |
| + HValue* left; |
| + HBitwiseBinaryOperation* shift = CanTransformToShiftedOp(instr, &left); |
| + |
| + if ((shift != NULL) && ShiftCanBeOptimizedAway(shift)) { |
| + return DoShiftedBinaryOp(instr, left, shift); |
| + } |
| + return NULL; |
| +} |
| + |
| + |
| +LInstruction* LChunkBuilder::DoShiftedBinaryOp( |
| + HBinaryOperation* hinstr, HValue* hleft, HBitwiseBinaryOperation* hshift) { |
| + ASSERT(hshift->IsBitwiseBinaryShift()); |
| + ASSERT(!hshift->IsShr() || (ShiftAmountFromHConstant(hshift->right()) > 0)); |
| + |
| + LTemplateResultInstruction<1>* res; |
| + LOperand* left = UseRegisterAtStart(hleft); |
| + LOperand* right = UseRegisterAtStart(hshift->left()); |
| + LOperand* shift_amount = UseConstant(hshift->right()); |
| + Shift shift_op; |
| + switch (hshift->opcode()) { |
| + case HValue::kShl: shift_op = LSL; break; |
| + case HValue::kShr: shift_op = LSR; break; |
| + case HValue::kSar: shift_op = ASR; break; |
| + default: UNREACHABLE(); shift_op = NO_SHIFT; |
| + } |
| + bool can_overflow = hinstr->CheckFlag(HValue::kCanOverflow); |
|
ulan
2014/05/02 10:01:18
You can inline hinstr->CheckFlag(HValue::kCanOverf
Alexandre Rames
2014/05/02 13:51:44
Done.
|
| + |
| + if (hinstr->IsBitwise()) { |
| + res = new(zone()) LBitI(left, right, shift_op, shift_amount); |
| + } else if (hinstr->IsAdd()) { |
| + res = new(zone()) LAddI(left, right, shift_op, shift_amount); |
| + } else if (hinstr->IsSub()) { |
| + res = new(zone()) LSubI(left, right, shift_op, shift_amount); |
| + } else { |
| + UNREACHABLE(); |
|
ulan
2014/05/02 10:01:18
nit: I'd ASSERT(hinstr->IsSub()) above.
Alexandre Rames
2014/05/02 13:51:44
Done.
|
| + res = NULL; |
| + } |
| + if (can_overflow) { |
| + AssignEnvironment(res); |
| + } |
| + return DefineAsRegister(res); |
| +} |
| + |
| + |
| LInstruction* LChunkBuilder::DoShift(Token::Value op, |
| HBitwiseBinaryOperation* instr) { |
| if (instr->representation().IsTagged()) { |
| @@ -2041,6 +2166,10 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, |
| ASSERT(instr->left()->representation().Equals(instr->representation())); |
| ASSERT(instr->right()->representation().Equals(instr->representation())); |
| + if (ShiftCanBeOptimizedAway(instr)) { |
| + return NULL; |
| + } |
| + |
| LOperand* left = instr->representation().IsSmi() |
| ? UseRegister(instr->left()) |
| : UseRegisterAtStart(instr->left()); |
| @@ -2314,6 +2443,12 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { |
| if (instr->representation().IsSmiOrInteger32()) { |
| ASSERT(instr->left()->representation().Equals(instr->representation())); |
| ASSERT(instr->right()->representation().Equals(instr->representation())); |
| + |
| + LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr); |
| + if (shifted_operation != NULL) { |
| + return shifted_operation; |
| + } |
| + |
| LOperand *left; |
| if (instr->left()->IsConstant() && |
| (HConstant::cast(instr->left())->Integer32Value() == 0)) { |