ARM: Merge data-processing instructions and shifts/(un)signed extensions
This commit mirrors the work that has already been done for ARM64.
Test: m test-art-target-run-test-551-checker-shifter-operand
Change-Id: Iec8c1563b035f40f0e18dcffde28d91dc21922f8
diff --git a/compiler/Android.bp b/compiler/Android.bp
index f6a4db4..f5589cd 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -111,6 +111,7 @@
"optimizing/instruction_simplifier_shared.cc",
"optimizing/intrinsics_arm.cc",
"optimizing/intrinsics_arm_vixl.cc",
+ "optimizing/nodes_shared.cc",
"utils/arm/assembler_arm.cc",
"utils/arm/assembler_arm_vixl.cc",
"utils/arm/assembler_thumb2.cc",
@@ -127,7 +128,6 @@
"optimizing/scheduler_arm64.cc",
"optimizing/instruction_simplifier_arm64.cc",
"optimizing/intrinsics_arm64.cc",
- "optimizing/nodes_arm64.cc",
"utils/arm64/assembler_arm64.cc",
"utils/arm64/jni_macro_assembler_arm64.cc",
"utils/arm64/managed_register_arm64.cc",
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 759a951..7b84ef8 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -19,6 +19,7 @@
#include "arch/arm/instruction_set_features_arm.h"
#include "art_method.h"
#include "code_generator_utils.h"
+#include "common_arm.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "gc/accounting/card_table.h"
@@ -1132,10 +1133,6 @@
DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
};
-#undef __
-// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
-#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
-
inline Condition ARMCondition(IfCondition cond) {
switch (cond) {
case kCondEQ: return EQ;
@@ -1191,6 +1188,197 @@
}
}
+inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
+ switch (op_kind) {
+ case HDataProcWithShifterOp::kASR: return ASR;
+ case HDataProcWithShifterOp::kLSL: return LSL;
+ case HDataProcWithShifterOp::kLSR: return LSR;
+ default:
+ LOG(FATAL) << "Unexpected op kind " << op_kind;
+ UNREACHABLE();
+ }
+}
+
+static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
+ Register out,
+ Register first,
+ const ShifterOperand& second,
+ CodeGeneratorARM* codegen) {
+ if (second.IsImmediate() && second.GetImmediate() == 0) {
+ const ShifterOperand in = kind == HInstruction::kAnd
+ ? ShifterOperand(0)
+ : ShifterOperand(first);
+
+ __ mov(out, in);
+ } else {
+ switch (kind) {
+ case HInstruction::kAdd:
+ __ add(out, first, second);
+ break;
+ case HInstruction::kAnd:
+ __ and_(out, first, second);
+ break;
+ case HInstruction::kOr:
+ __ orr(out, first, second);
+ break;
+ case HInstruction::kSub:
+ __ sub(out, first, second);
+ break;
+ case HInstruction::kXor:
+ __ eor(out, first, second);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected instruction kind: " << kind;
+ UNREACHABLE();
+ }
+ }
+}
+
+static void GenerateDataProc(HInstruction::InstructionKind kind,
+ const Location& out,
+ const Location& first,
+ const ShifterOperand& second_lo,
+ const ShifterOperand& second_hi,
+ CodeGeneratorARM* codegen) {
+ const Register first_hi = first.AsRegisterPairHigh<Register>();
+ const Register first_lo = first.AsRegisterPairLow<Register>();
+ const Register out_hi = out.AsRegisterPairHigh<Register>();
+ const Register out_lo = out.AsRegisterPairLow<Register>();
+
+ if (kind == HInstruction::kAdd) {
+ __ adds(out_lo, first_lo, second_lo);
+ __ adc(out_hi, first_hi, second_hi);
+ } else if (kind == HInstruction::kSub) {
+ __ subs(out_lo, first_lo, second_lo);
+ __ sbc(out_hi, first_hi, second_hi);
+ } else {
+ GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
+ GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
+ }
+}
+
+static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
+ return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
+}
+
+static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+ DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
+
+ const LocationSummary* const locations = instruction->GetLocations();
+ const uint32_t shift_value = instruction->GetShiftAmount();
+ const HInstruction::InstructionKind kind = instruction->GetInstrKind();
+ const Location first = locations->InAt(0);
+ const Location second = locations->InAt(1);
+ const Location out = locations->Out();
+ const Register first_hi = first.AsRegisterPairHigh<Register>();
+ const Register first_lo = first.AsRegisterPairLow<Register>();
+ const Register out_hi = out.AsRegisterPairHigh<Register>();
+ const Register out_lo = out.AsRegisterPairLow<Register>();
+ const Register second_hi = second.AsRegisterPairHigh<Register>();
+ const Register second_lo = second.AsRegisterPairLow<Register>();
+ const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
+
+ if (shift_value >= 32) {
+ if (shift == LSL) {
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ ShifterOperand(second_lo, LSL, shift_value - 32),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ first_lo,
+ ShifterOperand(0),
+ codegen);
+ } else if (shift == ASR) {
+ GenerateDataProc(kind,
+ out,
+ first,
+ GetShifterOperand(second_hi, ASR, shift_value - 32),
+ ShifterOperand(second_hi, ASR, 31),
+ codegen);
+ } else {
+ DCHECK_EQ(shift, LSR);
+ GenerateDataProc(kind,
+ out,
+ first,
+ GetShifterOperand(second_hi, LSR, shift_value - 32),
+ ShifterOperand(0),
+ codegen);
+ }
+ } else {
+ DCHECK_GT(shift_value, 1U);
+ DCHECK_LT(shift_value, 32U);
+
+ if (shift == LSL) {
+ // We are not doing this for HInstruction::kAdd because the output will require
+ // Location::kOutputOverlap; not applicable to other cases.
+ if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ ShifterOperand(second_hi, LSL, shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ out_hi,
+ ShifterOperand(second_lo, LSR, 32 - shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ first_lo,
+ ShifterOperand(second_lo, LSL, shift_value),
+ codegen);
+ } else {
+ __ Lsl(IP, second_hi, shift_value);
+ __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
+ GenerateDataProc(kind,
+ out,
+ first,
+ ShifterOperand(second_lo, LSL, shift_value),
+ ShifterOperand(IP),
+ codegen);
+ }
+ } else {
+ DCHECK(shift == ASR || shift == LSR);
+
+ // We are not doing this for HInstruction::kAdd because the output will require
+ // Location::kOutputOverlap; not applicable to other cases.
+ if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ first_lo,
+ ShifterOperand(second_lo, LSR, shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ out_lo,
+ ShifterOperand(second_hi, LSL, 32 - shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ ShifterOperand(second_hi, shift, shift_value),
+ codegen);
+ } else {
+ __ Lsr(IP, second_lo, shift_value);
+ __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
+ GenerateDataProc(kind,
+ out,
+ first,
+ ShifterOperand(IP),
+ ShifterOperand(second_hi, shift, shift_value),
+ codegen);
+ }
+ }
+ }
+}
+
+#undef __
+// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
+#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
+
void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
stream << Register(reg);
}
@@ -6709,6 +6897,63 @@
}
}
+void LocationsBuilderARM::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
+ DCHECK(instruction->GetType() == Primitive::kPrimInt ||
+ instruction->GetType() == Primitive::kPrimLong);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
+ HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(),
+ overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
+ const LocationSummary* const locations = instruction->GetLocations();
+ const HInstruction::InstructionKind kind = instruction->GetInstrKind();
+ const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
+ const Location left = locations->InAt(0);
+ const Location right = locations->InAt(1);
+ const Location out = locations->Out();
+
+ if (instruction->GetType() == Primitive::kPrimInt) {
+ DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
+
+ const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
+ ? right.AsRegisterPairLow<Register>()
+ : right.AsRegister<Register>();
+
+ GenerateDataProcInstruction(kind,
+ out.AsRegister<Register>(),
+ left.AsRegister<Register>(),
+ ShifterOperand(second,
+ ShiftFromOpKind(op_kind),
+ instruction->GetShiftAmount()),
+ codegen_);
+ } else {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+
+ if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
+ const Register second = right.AsRegister<Register>();
+
+ DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
+ GenerateDataProc(kind,
+ out,
+ left,
+ ShifterOperand(second),
+ ShifterOperand(second, ASR, 31),
+ codegen_);
+ } else {
+ GenerateLongDataProc(instruction, codegen_);
+ }
+ }
+}
+
void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
// Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
if (value == 0xffffffffu) {
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index e6032d2..edccbd4 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2277,8 +2277,8 @@
}
}
-void LocationsBuilderARM64::VisitArm64DataProcWithShifterOp(
- HArm64DataProcWithShifterOp* instruction) {
+void LocationsBuilderARM64::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
DCHECK(instruction->GetType() == Primitive::kPrimInt ||
instruction->GetType() == Primitive::kPrimLong);
LocationSummary* locations =
@@ -2292,8 +2292,8 @@
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
}
-void InstructionCodeGeneratorARM64::VisitArm64DataProcWithShifterOp(
- HArm64DataProcWithShifterOp* instruction) {
+void InstructionCodeGeneratorARM64::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
Primitive::Type type = instruction->GetType();
HInstruction::InstructionKind kind = instruction->GetInstrKind();
DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
@@ -2302,21 +2302,20 @@
if (kind != HInstruction::kNeg) {
left = InputRegisterAt(instruction, 0);
}
- // If this `HArm64DataProcWithShifterOp` was created by merging a type conversion as the
+ // If this `HDataProcWithShifterOp` was created by merging a type conversion as the
// shifter operand operation, the IR generating `right_reg` (input to the type
// conversion) can have a different type from the current instruction's type,
// so we manually indicate the type.
Register right_reg = RegisterFrom(instruction->GetLocations()->InAt(1), type);
- int64_t shift_amount = instruction->GetShiftAmount() &
- (type == Primitive::kPrimInt ? kMaxIntShiftDistance : kMaxLongShiftDistance);
-
Operand right_operand(0);
- HArm64DataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
- if (HArm64DataProcWithShifterOp::IsExtensionOp(op_kind)) {
+ HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
+ if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
right_operand = Operand(right_reg, helpers::ExtendFromOpKind(op_kind));
} else {
- right_operand = Operand(right_reg, helpers::ShiftFromOpKind(op_kind), shift_amount);
+ right_operand = Operand(right_reg,
+ helpers::ShiftFromOpKind(op_kind),
+ instruction->GetShiftAmount());
}
// Logical binary operations do not support extension operations in the
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 5c4ca5b..6bfbe4a 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -1216,6 +1216,17 @@
}
}
+inline ShiftType ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
+ switch (op_kind) {
+ case HDataProcWithShifterOp::kASR: return ShiftType::ASR;
+ case HDataProcWithShifterOp::kLSL: return ShiftType::LSL;
+ case HDataProcWithShifterOp::kLSR: return ShiftType::LSR;
+ default:
+ LOG(FATAL) << "Unexpected op kind " << op_kind;
+ UNREACHABLE();
+ }
+}
+
void CodeGeneratorARMVIXL::DumpCoreRegister(std::ostream& stream, int reg) const {
stream << vixl32::Register(reg);
}
@@ -1260,6 +1271,185 @@
return 0;
}
+static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
+ vixl32::Register out,
+ vixl32::Register first,
+ const Operand& second,
+ CodeGeneratorARMVIXL* codegen) {
+ if (second.IsImmediate() && second.GetImmediate() == 0) {
+ const Operand in = kind == HInstruction::kAnd
+ ? Operand(0)
+ : Operand(first);
+
+ __ Mov(out, in);
+ } else {
+ switch (kind) {
+ case HInstruction::kAdd:
+ __ Add(out, first, second);
+ break;
+ case HInstruction::kAnd:
+ __ And(out, first, second);
+ break;
+ case HInstruction::kOr:
+ __ Orr(out, first, second);
+ break;
+ case HInstruction::kSub:
+ __ Sub(out, first, second);
+ break;
+ case HInstruction::kXor:
+ __ Eor(out, first, second);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected instruction kind: " << kind;
+ UNREACHABLE();
+ }
+ }
+}
+
+static void GenerateDataProc(HInstruction::InstructionKind kind,
+ const Location& out,
+ const Location& first,
+ const Operand& second_lo,
+ const Operand& second_hi,
+ CodeGeneratorARMVIXL* codegen) {
+ const vixl32::Register first_hi = HighRegisterFrom(first);
+ const vixl32::Register first_lo = LowRegisterFrom(first);
+ const vixl32::Register out_hi = HighRegisterFrom(out);
+ const vixl32::Register out_lo = LowRegisterFrom(out);
+
+ if (kind == HInstruction::kAdd) {
+ __ Adds(out_lo, first_lo, second_lo);
+ __ Adc(out_hi, first_hi, second_hi);
+ } else if (kind == HInstruction::kSub) {
+ __ Subs(out_lo, first_lo, second_lo);
+ __ Sbc(out_hi, first_hi, second_hi);
+ } else {
+ GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
+ GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
+ }
+}
+
+static Operand GetShifterOperand(vixl32::Register rm, ShiftType shift, uint32_t shift_imm) {
+ return shift_imm == 0 ? Operand(rm) : Operand(rm, shift, shift_imm);
+}
+
+static void GenerateLongDataProc(HDataProcWithShifterOp* instruction,
+ CodeGeneratorARMVIXL* codegen) {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+ DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
+
+ const LocationSummary* const locations = instruction->GetLocations();
+ const uint32_t shift_value = instruction->GetShiftAmount();
+ const HInstruction::InstructionKind kind = instruction->GetInstrKind();
+ const Location first = locations->InAt(0);
+ const Location second = locations->InAt(1);
+ const Location out = locations->Out();
+ const vixl32::Register first_hi = HighRegisterFrom(first);
+ const vixl32::Register first_lo = LowRegisterFrom(first);
+ const vixl32::Register out_hi = HighRegisterFrom(out);
+ const vixl32::Register out_lo = LowRegisterFrom(out);
+ const vixl32::Register second_hi = HighRegisterFrom(second);
+ const vixl32::Register second_lo = LowRegisterFrom(second);
+ const ShiftType shift = ShiftFromOpKind(instruction->GetOpKind());
+
+ if (shift_value >= 32) {
+ if (shift == ShiftType::LSL) {
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ Operand(second_lo, ShiftType::LSL, shift_value - 32),
+ codegen);
+ GenerateDataProcInstruction(kind, out_lo, first_lo, 0, codegen);
+ } else if (shift == ShiftType::ASR) {
+ GenerateDataProc(kind,
+ out,
+ first,
+ GetShifterOperand(second_hi, ShiftType::ASR, shift_value - 32),
+ Operand(second_hi, ShiftType::ASR, 31),
+ codegen);
+ } else {
+ DCHECK_EQ(shift, ShiftType::LSR);
+ GenerateDataProc(kind,
+ out,
+ first,
+ GetShifterOperand(second_hi, ShiftType::LSR, shift_value - 32),
+ 0,
+ codegen);
+ }
+ } else {
+ DCHECK_GT(shift_value, 1U);
+ DCHECK_LT(shift_value, 32U);
+
+ UseScratchRegisterScope temps(codegen->GetVIXLAssembler());
+
+ if (shift == ShiftType::LSL) {
+ // We are not doing this for HInstruction::kAdd because the output will require
+ // Location::kOutputOverlap; not applicable to other cases.
+ if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ Operand(second_hi, ShiftType::LSL, shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ out_hi,
+ Operand(second_lo, ShiftType::LSR, 32 - shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ first_lo,
+ Operand(second_lo, ShiftType::LSL, shift_value),
+ codegen);
+ } else {
+ const vixl32::Register temp = temps.Acquire();
+
+ __ Lsl(temp, second_hi, shift_value);
+ __ Orr(temp, temp, Operand(second_lo, ShiftType::LSR, 32 - shift_value));
+ GenerateDataProc(kind,
+ out,
+ first,
+ Operand(second_lo, ShiftType::LSL, shift_value),
+ temp,
+ codegen);
+ }
+ } else {
+ DCHECK(shift == ShiftType::ASR || shift == ShiftType::LSR);
+
+ // We are not doing this for HInstruction::kAdd because the output will require
+ // Location::kOutputOverlap; not applicable to other cases.
+ if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ first_lo,
+ Operand(second_lo, ShiftType::LSR, shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_lo,
+ out_lo,
+ Operand(second_hi, ShiftType::LSL, 32 - shift_value),
+ codegen);
+ GenerateDataProcInstruction(kind,
+ out_hi,
+ first_hi,
+ Operand(second_hi, shift, shift_value),
+ codegen);
+ } else {
+ const vixl32::Register temp = temps.Acquire();
+
+ __ Lsr(temp, second_lo, shift_value);
+ __ Orr(temp, temp, Operand(second_hi, ShiftType::LSL, 32 - shift_value));
+ GenerateDataProc(kind,
+ out,
+ first,
+ temp,
+ Operand(second_hi, shift, shift_value),
+ codegen);
+ }
+ }
+ }
+}
+
#undef __
CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph,
@@ -6781,6 +6971,60 @@
}
}
+void LocationsBuilderARMVIXL::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
+ DCHECK(instruction->GetType() == Primitive::kPrimInt ||
+ instruction->GetType() == Primitive::kPrimLong);
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
+ HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(),
+ overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* instruction) {
+ const LocationSummary* const locations = instruction->GetLocations();
+ const HInstruction::InstructionKind kind = instruction->GetInstrKind();
+ const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
+
+ if (instruction->GetType() == Primitive::kPrimInt) {
+ DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
+
+ const vixl32::Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
+ ? LowRegisterFrom(locations->InAt(1))
+ : InputRegisterAt(instruction, 1);
+
+ GenerateDataProcInstruction(kind,
+ OutputRegister(instruction),
+ InputRegisterAt(instruction, 0),
+ Operand(second,
+ ShiftFromOpKind(op_kind),
+ instruction->GetShiftAmount()),
+ codegen_);
+ } else {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
+
+ if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
+ const vixl32::Register second = InputRegisterAt(instruction, 1);
+
+ DCHECK(!LowRegisterFrom(locations->Out()).Is(second));
+ GenerateDataProc(kind,
+ locations->Out(),
+ locations->InAt(0),
+ second,
+ Operand(second, ShiftType::ASR, 31),
+ codegen_);
+ } else {
+ GenerateLongDataProc(instruction, codegen_);
+ }
+ }
+}
+
// TODO(VIXL): Remove optimizations in the helper when they are implemented in vixl.
void InstructionCodeGeneratorARMVIXL::GenerateAndConst(vixl32::Register out,
vixl32::Register first,
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index ecb8687..e184745 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_COMMON_ARM_H_
#define ART_COMPILER_OPTIMIZING_COMMON_ARM_H_
+#include "instruction_simplifier_shared.h"
#include "debug/dwarf/register.h"
#include "locations.h"
#include "nodes.h"
@@ -29,6 +30,9 @@
#pragma GCC diagnostic pop
namespace art {
+
+using helpers::HasShifterOperand;
+
namespace arm {
namespace helpers {
@@ -218,6 +222,14 @@
return Location::FpuRegisterPairLocation(low.GetCode(), high.GetCode());
}
+inline bool ShifterOperandSupportsExtension(HInstruction* instruction) {
+ DCHECK(HasShifterOperand(instruction, kArm));
+ // TODO: HAdd applied to the other integral types could make use of
+ // the SXTAB, SXTAH, UXTAB and UXTAH instructions.
+ return instruction->GetType() == Primitive::kPrimLong &&
+ (instruction->IsAdd() || instruction->IsSub());
+}
+
} // namespace helpers
} // namespace arm
} // namespace art
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 93ea090..d3f431e 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_COMMON_ARM64_H_
#include "code_generator.h"
+#include "instruction_simplifier_shared.h"
#include "locations.h"
#include "nodes.h"
#include "utils/arm64/assembler_arm64.h"
@@ -31,6 +32,10 @@
#pragma GCC diagnostic pop
namespace art {
+
+using helpers::CanFitInShifterOperand;
+using helpers::HasShifterOperand;
+
namespace arm64 {
namespace helpers {
@@ -290,11 +295,11 @@
return true;
}
-inline vixl::aarch64::Shift ShiftFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
+inline vixl::aarch64::Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
switch (op_kind) {
- case HArm64DataProcWithShifterOp::kASR: return vixl::aarch64::ASR;
- case HArm64DataProcWithShifterOp::kLSL: return vixl::aarch64::LSL;
- case HArm64DataProcWithShifterOp::kLSR: return vixl::aarch64::LSR;
+ case HDataProcWithShifterOp::kASR: return vixl::aarch64::ASR;
+ case HDataProcWithShifterOp::kLSL: return vixl::aarch64::LSL;
+ case HDataProcWithShifterOp::kLSR: return vixl::aarch64::LSR;
default:
LOG(FATAL) << "Unexpected op kind " << op_kind;
UNREACHABLE();
@@ -302,14 +307,14 @@
}
}
-inline vixl::aarch64::Extend ExtendFromOpKind(HArm64DataProcWithShifterOp::OpKind op_kind) {
+inline vixl::aarch64::Extend ExtendFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
switch (op_kind) {
- case HArm64DataProcWithShifterOp::kUXTB: return vixl::aarch64::UXTB;
- case HArm64DataProcWithShifterOp::kUXTH: return vixl::aarch64::UXTH;
- case HArm64DataProcWithShifterOp::kUXTW: return vixl::aarch64::UXTW;
- case HArm64DataProcWithShifterOp::kSXTB: return vixl::aarch64::SXTB;
- case HArm64DataProcWithShifterOp::kSXTH: return vixl::aarch64::SXTH;
- case HArm64DataProcWithShifterOp::kSXTW: return vixl::aarch64::SXTW;
+ case HDataProcWithShifterOp::kUXTB: return vixl::aarch64::UXTB;
+ case HDataProcWithShifterOp::kUXTH: return vixl::aarch64::UXTH;
+ case HDataProcWithShifterOp::kUXTW: return vixl::aarch64::UXTW;
+ case HDataProcWithShifterOp::kSXTB: return vixl::aarch64::SXTB;
+ case HDataProcWithShifterOp::kSXTH: return vixl::aarch64::SXTH;
+ case HDataProcWithShifterOp::kSXTW: return vixl::aarch64::SXTW;
default:
LOG(FATAL) << "Unexpected op kind " << op_kind;
UNREACHABLE();
@@ -317,31 +322,8 @@
}
}
-inline bool CanFitInShifterOperand(HInstruction* instruction) {
- if (instruction->IsTypeConversion()) {
- HTypeConversion* conversion = instruction->AsTypeConversion();
- Primitive::Type result_type = conversion->GetResultType();
- Primitive::Type input_type = conversion->GetInputType();
- // We don't expect to see the same type as input and result.
- return Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type) &&
- (result_type != input_type);
- } else {
- return (instruction->IsShl() && instruction->AsShl()->InputAt(1)->IsIntConstant()) ||
- (instruction->IsShr() && instruction->AsShr()->InputAt(1)->IsIntConstant()) ||
- (instruction->IsUShr() && instruction->AsUShr()->InputAt(1)->IsIntConstant());
- }
-}
-
-inline bool HasShifterOperand(HInstruction* instr) {
- // `neg` instructions are an alias of `sub` using the zero register as the
- // first register input.
- bool res = instr->IsAdd() || instr->IsAnd() || instr->IsNeg() ||
- instr->IsOr() || instr->IsSub() || instr->IsXor();
- return res;
-}
-
inline bool ShifterOperandSupportsExtension(HInstruction* instruction) {
- DCHECK(HasShifterOperand(instruction));
+ DCHECK(HasShifterOperand(instruction, kArm64));
// Although the `neg` instruction is an alias of the `sub` instruction, `HNeg`
// does *not* support extension. This is because the `extended register` form
// of the `sub` instruction interprets the left register with code 31 as the
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index f6fba88..2bf5c53 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -511,12 +511,10 @@
void VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) OVERRIDE {
StartAttributeStream("kind") << instruction->GetOpKind();
}
-#endif
-#ifdef ART_ENABLE_CODEGEN_arm64
- void VisitArm64DataProcWithShifterOp(HArm64DataProcWithShifterOp* instruction) OVERRIDE {
+ void VisitDataProcWithShifterOp(HDataProcWithShifterOp* instruction) OVERRIDE {
StartAttributeStream("kind") << instruction->GetInstrKind() << "+" << instruction->GetOpKind();
- if (HArm64DataProcWithShifterOp::IsShiftOp(instruction->GetOpKind())) {
+ if (HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind())) {
StartAttributeStream("shift") << instruction->GetShiftAmount();
}
}
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 56e4c7a..5f5e29b 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -15,23 +15,124 @@
*/
#include "code_generator.h"
+#include "common_arm.h"
#include "instruction_simplifier_arm.h"
#include "instruction_simplifier_shared.h"
#include "mirror/array-inl.h"
+#include "nodes.h"
namespace art {
+
+using helpers::CanFitInShifterOperand;
+using helpers::HasShifterOperand;
+
namespace arm {
-void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) {
- if (TryCombineMultiplyAccumulate(instruction, kArm)) {
+using helpers::ShifterOperandSupportsExtension;
+
+bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use,
+ HInstruction* bitfield_op,
+ bool do_merge) {
+ DCHECK(HasShifterOperand(use, kArm));
+ DCHECK(use->IsBinaryOperation());
+ DCHECK(CanFitInShifterOperand(bitfield_op));
+ DCHECK(!bitfield_op->HasEnvironmentUses());
+
+ Primitive::Type type = use->GetType();
+ if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
+ return false;
+ }
+
+ HInstruction* left = use->InputAt(0);
+ HInstruction* right = use->InputAt(1);
+ DCHECK(left == bitfield_op || right == bitfield_op);
+
+ if (left == right) {
+ // TODO: Handle special transformations in this situation?
+ // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
+ // Or should this be part of a separate transformation logic?
+ return false;
+ }
+
+ bool is_commutative = use->AsBinaryOperation()->IsCommutative();
+ HInstruction* other_input;
+ if (bitfield_op == right) {
+ other_input = left;
+ } else {
+ if (is_commutative) {
+ other_input = right;
+ } else {
+ return false;
+ }
+ }
+
+ HDataProcWithShifterOp::OpKind op_kind;
+ int shift_amount = 0;
+
+ HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
+ shift_amount &= use->GetType() == Primitive::kPrimInt
+ ? kMaxIntShiftDistance
+ : kMaxLongShiftDistance;
+
+ if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
+ if (!ShifterOperandSupportsExtension(use)) {
+ return false;
+ }
+ // Shift by 1 is a special case that results in the same number and type of instructions
+ // as this simplification, but potentially shorter code.
+ } else if (type == Primitive::kPrimLong && shift_amount == 1) {
+ return false;
+ }
+
+ if (do_merge) {
+ HDataProcWithShifterOp* alu_with_op =
+ new (GetGraph()->GetArena()) HDataProcWithShifterOp(use,
+ other_input,
+ bitfield_op->InputAt(0),
+ op_kind,
+ shift_amount,
+ use->GetDexPc());
+ use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
+ if (bitfield_op->GetUses().empty()) {
+ bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
+ }
RecordSimplification();
}
+
+ return true;
}
-void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) {
- if (TryMergeNegatedInput(instruction)) {
- RecordSimplification();
+// Merge a bitfield move instruction into its uses if it can be merged in all of them.
+bool InstructionSimplifierArmVisitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
+ DCHECK(CanFitInShifterOperand(bitfield_op));
+
+ if (bitfield_op->HasEnvironmentUses()) {
+ return false;
}
+
+ const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
+
+ // Check whether we can merge the instruction in all its users' shifter operand.
+ for (const HUseListNode<HInstruction*>& use : uses) {
+ HInstruction* user = use.GetUser();
+ if (!HasShifterOperand(user, kArm)) {
+ return false;
+ }
+ if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
+ return false;
+ }
+ }
+
+ // Merge the instruction into its uses.
+ for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
+ HInstruction* user = it->GetUser();
+ // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
+ ++it;
+ bool merged = MergeIntoShifterOperand(user, bitfield_op);
+ DCHECK(merged);
+ }
+
+ return true;
}
void InstructionSimplifierArmVisitor::VisitAnd(HAnd* instruction) {
@@ -89,5 +190,49 @@
}
}
+void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) {
+ if (TryCombineMultiplyAccumulate(instruction, kArm)) {
+ RecordSimplification();
+ }
+}
+
+void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) {
+ if (TryMergeNegatedInput(instruction)) {
+ RecordSimplification();
+ }
+}
+
+void InstructionSimplifierArmVisitor::VisitShl(HShl* instruction) {
+ if (instruction->InputAt(1)->IsConstant()) {
+ TryMergeIntoUsersShifterOperand(instruction);
+ }
+}
+
+void InstructionSimplifierArmVisitor::VisitShr(HShr* instruction) {
+ if (instruction->InputAt(1)->IsConstant()) {
+ TryMergeIntoUsersShifterOperand(instruction);
+ }
+}
+
+void InstructionSimplifierArmVisitor::VisitTypeConversion(HTypeConversion* instruction) {
+ Primitive::Type result_type = instruction->GetResultType();
+ Primitive::Type input_type = instruction->GetInputType();
+
+ if (input_type == result_type) {
+ // We let the arch-independent code handle this.
+ return;
+ }
+
+ if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
+ TryMergeIntoUsersShifterOperand(instruction);
+ }
+}
+
+void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) {
+ if (instruction->InputAt(1)->IsConstant()) {
+ TryMergeIntoUsersShifterOperand(instruction);
+ }
+}
+
} // namespace arm
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_arm.h b/compiler/optimizing/instruction_simplifier_arm.h
index 9b54511..e2ed257 100644
--- a/compiler/optimizing/instruction_simplifier_arm.h
+++ b/compiler/optimizing/instruction_simplifier_arm.h
@@ -35,11 +35,41 @@
}
}
- void VisitMul(HMul* instruction) OVERRIDE;
- void VisitOr(HOr* instruction) OVERRIDE;
+ bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
+ bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge);
+ bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
+ }
+ bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
+ }
+
+ /**
+ * This simplifier uses a special-purpose BB visitor.
+ * (1) No need to visit Phi nodes.
+ * (2) Since statements can be removed in a "forward" fashion,
+ * the visitor should test if each statement is still there.
+ */
+ void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
+ // TODO: fragile iteration, provide more robust iterators?
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ if (instruction->IsInBlock()) {
+ instruction->Accept(this);
+ }
+ }
+ }
+
void VisitAnd(HAnd* instruction) OVERRIDE;
void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
void VisitArraySet(HArraySet* instruction) OVERRIDE;
+ void VisitMul(HMul* instruction) OVERRIDE;
+ void VisitOr(HOr* instruction) OVERRIDE;
+ void VisitShl(HShl* instruction) OVERRIDE;
+ void VisitShr(HShr* instruction) OVERRIDE;
+ void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
+ void VisitUShr(HUShr* instruction) OVERRIDE;
OptimizingCompilerStats* stats_;
};
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 6d107d5..73b7b2b 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -22,16 +22,18 @@
#include "mirror/string.h"
namespace art {
-namespace arm64 {
using helpers::CanFitInShifterOperand;
using helpers::HasShifterOperand;
+
+namespace arm64 {
+
using helpers::ShifterOperandSupportsExtension;
bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
HInstruction* bitfield_op,
bool do_merge) {
- DCHECK(HasShifterOperand(use));
+ DCHECK(HasShifterOperand(use, kArm64));
DCHECK(use->IsBinaryOperation() || use->IsNeg());
DCHECK(CanFitInShifterOperand(bitfield_op));
DCHECK(!bitfield_op->HasEnvironmentUses());
@@ -72,23 +74,22 @@
}
}
- HArm64DataProcWithShifterOp::OpKind op_kind;
+ HDataProcWithShifterOp::OpKind op_kind;
int shift_amount = 0;
- HArm64DataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
+ HDataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
- if (HArm64DataProcWithShifterOp::IsExtensionOp(op_kind) &&
- !ShifterOperandSupportsExtension(use)) {
+ if (HDataProcWithShifterOp::IsExtensionOp(op_kind) && !ShifterOperandSupportsExtension(use)) {
return false;
}
if (do_merge) {
- HArm64DataProcWithShifterOp* alu_with_op =
- new (GetGraph()->GetArena()) HArm64DataProcWithShifterOp(use,
- other_input,
- bitfield_op->InputAt(0),
- op_kind,
- shift_amount,
- use->GetDexPc());
+ HDataProcWithShifterOp* alu_with_op =
+ new (GetGraph()->GetArena()) HDataProcWithShifterOp(use,
+ other_input,
+ bitfield_op->InputAt(0),
+ op_kind,
+ shift_amount,
+ use->GetDexPc());
use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
if (bitfield_op->GetUses().empty()) {
bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
@@ -112,7 +113,7 @@
// Check whether we can merge the instruction in all its users' shifter operand.
for (const HUseListNode<HInstruction*>& use : uses) {
HInstruction* user = use.GetUser();
- if (!HasShifterOperand(user)) {
+ if (!HasShifterOperand(user, kArm64)) {
return false;
}
if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
diff --git a/compiler/optimizing/instruction_simplifier_arm64.h b/compiler/optimizing/instruction_simplifier_arm64.h
index d4cb1f1..65654f5 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.h
+++ b/compiler/optimizing/instruction_simplifier_arm64.h
@@ -40,11 +40,11 @@
HInstruction* bitfield_op,
bool do_merge);
bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
- return TryMergeIntoShifterOperand(use, bitfield_op, false);
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
}
bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
- return TryMergeIntoShifterOperand(use, bitfield_op, true);
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
}
/**
diff --git a/compiler/optimizing/instruction_simplifier_shared.h b/compiler/optimizing/instruction_simplifier_shared.h
index 56804f5..83e3ffc 100644
--- a/compiler/optimizing/instruction_simplifier_shared.h
+++ b/compiler/optimizing/instruction_simplifier_shared.h
@@ -21,6 +21,33 @@
namespace art {
+namespace helpers {
+
+inline bool CanFitInShifterOperand(HInstruction* instruction) {
+ if (instruction->IsTypeConversion()) {
+ HTypeConversion* conversion = instruction->AsTypeConversion();
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ // We don't expect to see the same type as input and result.
+ return Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type) &&
+ (result_type != input_type);
+ } else {
+ return (instruction->IsShl() && instruction->AsShl()->InputAt(1)->IsIntConstant()) ||
+ (instruction->IsShr() && instruction->AsShr()->InputAt(1)->IsIntConstant()) ||
+ (instruction->IsUShr() && instruction->AsUShr()->InputAt(1)->IsIntConstant());
+ }
+}
+
+inline bool HasShifterOperand(HInstruction* instr, InstructionSet isa) {
+ // On ARM64 `neg` instructions are an alias of `sub` using the zero register
+ // as the first register input.
+ bool res = instr->IsAdd() || instr->IsAnd() || (isa == kArm64 && instr->IsNeg()) ||
+ instr->IsOr() || instr->IsSub() || instr->IsXor();
+ return res;
+}
+
+} // namespace helpers
+
bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa);
// For bitwise operations (And/Or/Xor) with a negated input, try to use
// a negated bitwise instruction.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 96f9aba..56ca84a 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1346,6 +1346,7 @@
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \
M(BitwiseNegatedRight, Instruction) \
+ M(DataProcWithShifterOp, Instruction) \
M(MultiplyAccumulate, Instruction) \
M(IntermediateAddress, Instruction)
#endif
@@ -1357,12 +1358,7 @@
M(ArmDexCacheArraysBase, Instruction)
#endif
-#ifndef ART_ENABLE_CODEGEN_arm64
#define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)
-#else
-#define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \
- M(Arm64DataProcWithShifterOp, Instruction)
-#endif
#ifndef ART_ENABLE_CODEGEN_mips
#define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M)
@@ -6603,9 +6599,6 @@
#ifdef ART_ENABLE_CODEGEN_arm
#include "nodes_arm.h"
#endif
-#ifdef ART_ENABLE_CODEGEN_arm64
-#include "nodes_arm64.h"
-#endif
#ifdef ART_ENABLE_CODEGEN_mips
#include "nodes_mips.h"
#endif
diff --git a/compiler/optimizing/nodes_arm64.h b/compiler/optimizing/nodes_arm64.h
deleted file mode 100644
index 3f88717..0000000
--- a/compiler/optimizing/nodes_arm64.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_NODES_ARM64_H_
-#define ART_COMPILER_OPTIMIZING_NODES_ARM64_H_
-
-#include "nodes.h"
-
-namespace art {
-
-class HArm64DataProcWithShifterOp FINAL : public HExpression<2> {
- public:
- enum OpKind {
- kLSL, // Logical shift left.
- kLSR, // Logical shift right.
- kASR, // Arithmetic shift right.
- kUXTB, // Unsigned extend byte.
- kUXTH, // Unsigned extend half-word.
- kUXTW, // Unsigned extend word.
- kSXTB, // Signed extend byte.
- kSXTH, // Signed extend half-word.
- kSXTW, // Signed extend word.
-
- // Aliases.
- kFirstShiftOp = kLSL,
- kLastShiftOp = kASR,
- kFirstExtensionOp = kUXTB,
- kLastExtensionOp = kSXTW
- };
- HArm64DataProcWithShifterOp(HInstruction* instr,
- HInstruction* left,
- HInstruction* right,
- OpKind op,
- // The shift argument is unused if the operation
- // is an extension.
- int shift = 0,
- uint32_t dex_pc = kNoDexPc)
- : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
- instr_kind_(instr->GetKind()), op_kind_(op), shift_amount_(shift) {
- DCHECK(!instr->HasSideEffects());
- SetRawInputAt(0, left);
- SetRawInputAt(1, right);
- }
-
- bool CanBeMoved() const OVERRIDE { return true; }
- bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
- const HArm64DataProcWithShifterOp* other = other_instr->AsArm64DataProcWithShifterOp();
- return instr_kind_ == other->instr_kind_ &&
- op_kind_ == other->op_kind_ &&
- shift_amount_ == other->shift_amount_;
- }
-
- static bool IsShiftOp(OpKind op_kind) {
- return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
- }
-
- static bool IsExtensionOp(OpKind op_kind) {
- return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
- }
-
- // Find the operation kind and shift amount from a bitfield move instruction.
- static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
- /*out*/OpKind* op_kind,
- /*out*/int* shift_amount);
-
- InstructionKind GetInstrKind() const { return instr_kind_; }
- OpKind GetOpKind() const { return op_kind_; }
- int GetShiftAmount() const { return shift_amount_; }
-
- DECLARE_INSTRUCTION(Arm64DataProcWithShifterOp);
-
- private:
- InstructionKind instr_kind_;
- OpKind op_kind_;
- int shift_amount_;
-
- friend std::ostream& operator<<(std::ostream& os, OpKind op);
-
- DISALLOW_COPY_AND_ASSIGN(HArm64DataProcWithShifterOp);
-};
-
-std::ostream& operator<<(std::ostream& os, const HArm64DataProcWithShifterOp::OpKind op);
-
-} // namespace art
-
-#endif // ART_COMPILER_OPTIMIZING_NODES_ARM64_H_
diff --git a/compiler/optimizing/nodes_arm64.cc b/compiler/optimizing/nodes_shared.cc
similarity index 63%
rename from compiler/optimizing/nodes_arm64.cc
rename to compiler/optimizing/nodes_shared.cc
index ac2f093..f145bf9 100644
--- a/compiler/optimizing/nodes_arm64.cc
+++ b/compiler/optimizing/nodes_shared.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,15 @@
*/
#include "common_arm64.h"
-#include "nodes.h"
+#include "nodes_shared.h"
namespace art {
-using arm64::helpers::CanFitInShifterOperand;
+using helpers::CanFitInShifterOperand;
-void HArm64DataProcWithShifterOp::GetOpInfoFromInstruction(HInstruction* instruction,
- /*out*/OpKind* op_kind,
- /*out*/int* shift_amount) {
+void HDataProcWithShifterOp::GetOpInfoFromInstruction(HInstruction* instruction,
+ /*out*/OpKind* op_kind,
+ /*out*/int* shift_amount) {
DCHECK(CanFitInShifterOperand(instruction));
if (instruction->IsShl()) {
*op_kind = kLSL;
@@ -41,12 +41,11 @@
int result_size = Primitive::ComponentSize(result_type);
int input_size = Primitive::ComponentSize(input_type);
int min_size = std::min(result_size, input_size);
- // This follows the logic in
- // `InstructionCodeGeneratorARM64::VisitTypeConversion()`.
if (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimLong) {
- // There is actually nothing to do. The register will be used as a W
- // register, discarding the top bits. This is represented by the default
- // encoding 'LSL 0'.
+ // There is actually nothing to do. On ARM the high register from the
+ // pair will be ignored. On ARM64 the register will be used as a W
+ // register, discarding the top bits. This is represented by the
+ // default encoding 'LSL 0'.
*op_kind = kLSL;
*shift_amount = 0;
} else if (result_type == Primitive::kPrimChar ||
@@ -64,17 +63,17 @@
}
}
-std::ostream& operator<<(std::ostream& os, const HArm64DataProcWithShifterOp::OpKind op) {
+std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op) {
switch (op) {
- case HArm64DataProcWithShifterOp::kLSL: return os << "LSL";
- case HArm64DataProcWithShifterOp::kLSR: return os << "LSR";
- case HArm64DataProcWithShifterOp::kASR: return os << "ASR";
- case HArm64DataProcWithShifterOp::kUXTB: return os << "UXTB";
- case HArm64DataProcWithShifterOp::kUXTH: return os << "UXTH";
- case HArm64DataProcWithShifterOp::kUXTW: return os << "UXTW";
- case HArm64DataProcWithShifterOp::kSXTB: return os << "SXTB";
- case HArm64DataProcWithShifterOp::kSXTH: return os << "SXTH";
- case HArm64DataProcWithShifterOp::kSXTW: return os << "SXTW";
+ case HDataProcWithShifterOp::kLSL: return os << "LSL";
+ case HDataProcWithShifterOp::kLSR: return os << "LSR";
+ case HDataProcWithShifterOp::kASR: return os << "ASR";
+ case HDataProcWithShifterOp::kUXTB: return os << "UXTB";
+ case HDataProcWithShifterOp::kUXTH: return os << "UXTH";
+ case HDataProcWithShifterOp::kUXTW: return os << "UXTW";
+ case HDataProcWithShifterOp::kSXTB: return os << "SXTB";
+ case HDataProcWithShifterOp::kSXTH: return os << "SXTH";
+ case HDataProcWithShifterOp::kSXTW: return os << "SXTW";
default:
LOG(FATAL) << "Invalid OpKind " << static_cast<int>(op);
UNREACHABLE();
diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h
index 814202e..c6bfbcc 100644
--- a/compiler/optimizing/nodes_shared.h
+++ b/compiler/optimizing/nodes_shared.h
@@ -150,6 +150,81 @@
DISALLOW_COPY_AND_ASSIGN(HIntermediateAddress);
};
+class HDataProcWithShifterOp FINAL : public HExpression<2> {
+ public:
+ enum OpKind {
+ kLSL, // Logical shift left.
+ kLSR, // Logical shift right.
+ kASR, // Arithmetic shift right.
+ kUXTB, // Unsigned extend byte.
+ kUXTH, // Unsigned extend half-word.
+ kUXTW, // Unsigned extend word.
+ kSXTB, // Signed extend byte.
+ kSXTH, // Signed extend half-word.
+ kSXTW, // Signed extend word.
+
+ // Aliases.
+ kFirstShiftOp = kLSL,
+ kLastShiftOp = kASR,
+ kFirstExtensionOp = kUXTB,
+ kLastExtensionOp = kSXTW
+ };
+ HDataProcWithShifterOp(HInstruction* instr,
+ HInstruction* left,
+ HInstruction* right,
+ OpKind op,
+ // The shift argument is unused if the operation
+ // is an extension.
+ int shift = 0,
+ uint32_t dex_pc = kNoDexPc)
+ : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
+ instr_kind_(instr->GetKind()), op_kind_(op),
+ shift_amount_(shift & (instr->GetType() == Primitive::kPrimInt
+ ? kMaxIntShiftDistance
+ : kMaxLongShiftDistance)) {
+ DCHECK(!instr->HasSideEffects());
+ SetRawInputAt(0, left);
+ SetRawInputAt(1, right);
+ }
+
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
+ const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
+ return instr_kind_ == other->instr_kind_ &&
+ op_kind_ == other->op_kind_ &&
+ shift_amount_ == other->shift_amount_;
+ }
+
+ static bool IsShiftOp(OpKind op_kind) {
+ return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
+ }
+
+ static bool IsExtensionOp(OpKind op_kind) {
+ return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
+ }
+
+ // Find the operation kind and shift amount from a bitfield move instruction.
+ static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
+ /*out*/OpKind* op_kind,
+ /*out*/int* shift_amount);
+
+ InstructionKind GetInstrKind() const { return instr_kind_; }
+ OpKind GetOpKind() const { return op_kind_; }
+ int GetShiftAmount() const { return shift_amount_; }
+
+ DECLARE_INSTRUCTION(DataProcWithShifterOp);
+
+ private:
+ InstructionKind instr_kind_;
+ OpKind op_kind_;
+ int shift_amount_;
+
+ friend std::ostream& operator<<(std::ostream& os, OpKind op);
+
+ DISALLOW_COPY_AND_ASSIGN(HDataProcWithShifterOp);
+};
+
+std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
} // namespace art
diff --git a/compiler/optimizing/scheduler_arm64.cc b/compiler/optimizing/scheduler_arm64.cc
index e3701fb..558dcc4 100644
--- a/compiler/optimizing/scheduler_arm64.cc
+++ b/compiler/optimizing/scheduler_arm64.cc
@@ -31,8 +31,8 @@
last_visited_latency_ = kArm64IntegerOpLatency;
}
-void SchedulingLatencyVisitorARM64::VisitArm64DataProcWithShifterOp(
- HArm64DataProcWithShifterOp* ATTRIBUTE_UNUSED) {
+void SchedulingLatencyVisitorARM64::VisitDataProcWithShifterOp(
+ HDataProcWithShifterOp* ATTRIBUTE_UNUSED) {
last_visited_latency_ = kArm64DataProcWithShifterOpLatency;
}
diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h
index 702027c..7a33720 100644
--- a/compiler/optimizing/scheduler_arm64.h
+++ b/compiler/optimizing/scheduler_arm64.h
@@ -74,7 +74,8 @@
#define FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(M) \
M(BitwiseNegatedRight, unused) \
M(MultiplyAccumulate, unused) \
- M(IntermediateAddress, unused)
+ M(IntermediateAddress, unused) \
+ M(DataProcWithShifterOp, unused)
#define DECLARE_VISIT_INSTRUCTION(type, unused) \
void Visit##type(H##type* instruction) OVERRIDE;
diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java
index a4561b8..e967398 100644
--- a/test/551-checker-shifter-operand/src/Main.java
+++ b/test/551-checker-shifter-operand/src/Main.java
@@ -76,6 +76,25 @@
* the shifter operand.
*/
+ /// CHECK-START-ARM: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm (before)
+ /// CHECK-DAG: <<l:j\d+>> ParameterValue
+ /// CHECK-DAG: <<b:b\d+>> ParameterValue
+ /// CHECK: <<tmp:j\d+>> TypeConversion [<<b>>]
+ /// CHECK: Sub [<<l>>,<<tmp>>]
+
+ /// CHECK-START-ARM: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<l:j\d+>> ParameterValue
+ /// CHECK-DAG: <<b:b\d+>> ParameterValue
+ /// CHECK: DataProcWithShifterOp [<<l>>,<<b>>] kind:Sub+SXTB
+
+ /// CHECK-START-ARM: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Sub
+
+ /// CHECK-START-ARM: long Main.$opt$noinline$translate(long, byte) disassembly (after)
+ /// CHECK: subs r{{\d+}}, r{{\d+}}, r{{\d+}}
+ /// CHECK: sbc r{{\d+}}, r{{\d+}}, r{{\d+}}, asr #31
+
/// CHECK-START-ARM64: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm64 (before)
/// CHECK-DAG: <<l:j\d+>> ParameterValue
/// CHECK-DAG: <<b:b\d+>> ParameterValue
@@ -85,7 +104,7 @@
/// CHECK-START-ARM64: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm64 (after)
/// CHECK-DAG: <<l:j\d+>> ParameterValue
/// CHECK-DAG: <<b:b\d+>> ParameterValue
- /// CHECK: Arm64DataProcWithShifterOp [<<l>>,<<b>>] kind:Sub+SXTB
+ /// CHECK: DataProcWithShifterOp [<<l>>,<<b>>] kind:Sub+SXTB
/// CHECK-START-ARM64: long Main.$opt$noinline$translate(long, byte) instruction_simplifier_arm64 (after)
/// CHECK-NOT: TypeConversion
@@ -106,6 +125,21 @@
* inputs are the the IR.
*/
+ /// CHECK-START-ARM: int Main.$opt$noinline$sameInput(int) instruction_simplifier_arm (before)
+ /// CHECK: <<a:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<tmp:i\d+>> Shl [<<a>>,<<Const2>>]
+ /// CHECK: Add [<<tmp>>,<<tmp>>]
+
+ /// CHECK-START-ARM: int Main.$opt$noinline$sameInput(int) instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<a:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Shl:i\d+>> Shl [<<a>>,<<Const2>>]
+ /// CHECK: Add [<<Shl>>,<<Shl>>]
+
+ /// CHECK-START-ARM: int Main.$opt$noinline$sameInput(int) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: int Main.$opt$noinline$sameInput(int) instruction_simplifier_arm64 (before)
/// CHECK: <<a:i\d+>> ParameterValue
/// CHECK: <<Const2:i\d+>> IntConstant 2
@@ -119,7 +153,7 @@
/// CHECK: Add [<<Shl>>,<<Shl>>]
/// CHECK-START-ARM64: int Main.$opt$noinline$sameInput(int) instruction_simplifier_arm64 (after)
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
public static int $opt$noinline$sameInput(int a) {
if (doThrow) throw new Error();
@@ -131,6 +165,28 @@
* Check that we perform the merge for multiple uses.
*/
+ /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm (before)
+ /// CHECK: <<arg:i\d+>> ParameterValue
+ /// CHECK: <<Const23:i\d+>> IntConstant 23
+ /// CHECK: <<tmp:i\d+>> Shl [<<arg>>,<<Const23>>]
+ /// CHECK: Add [<<tmp>>,{{i\d+}}]
+ /// CHECK: Add [<<tmp>>,{{i\d+}}]
+ /// CHECK: Add [<<tmp>>,{{i\d+}}]
+ /// CHECK: Add [<<tmp>>,{{i\d+}}]
+ /// CHECK: Add [<<tmp>>,{{i\d+}}]
+
+ /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm (after)
+ /// CHECK: <<arg:i\d+>> ParameterValue
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+
+ /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm (after)
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Add
+
/// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm64 (before)
/// CHECK: <<arg:i\d+>> ParameterValue
/// CHECK: <<Const23:i\d+>> IntConstant 23
@@ -143,11 +199,11 @@
/// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm64 (after)
/// CHECK: <<arg:i\d+>> ParameterValue
- /// CHECK: Arm64DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
- /// CHECK: Arm64DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
- /// CHECK: Arm64DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
- /// CHECK: Arm64DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
- /// CHECK: Arm64DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
+ /// CHECK: DataProcWithShifterOp [{{i\d+}},<<arg>>] kind:Add+LSL shift:23
/// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses(int) instruction_simplifier_arm64 (after)
/// CHECK-NOT: Shl
@@ -171,9 +227,19 @@
* operand, so test that only the shifts are merged.
*/
+ /// CHECK-START-ARM: void Main.$opt$noinline$testAnd(long, long) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$noinline$testAnd(long, long) disassembly (after)
+ /// CHECK: and lsl
+ /// CHECK: sbfx
+ /// CHECK: asr
+ /// CHECK: and
+
/// CHECK-START-ARM64: void Main.$opt$noinline$testAnd(long, long) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$noinline$testAnd(long, long) disassembly (after)
/// CHECK: and lsl
@@ -186,9 +252,18 @@
(a & (b << 5)) | (a & (byte)b));
}
+ /// CHECK-START-ARM: void Main.$opt$noinline$testOr(int, int) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$noinline$testOr(int, int) disassembly (after)
+ /// CHECK: orr asr
+ /// CHECK: ubfx
+ /// CHECK: orr
+
/// CHECK-START-ARM64: void Main.$opt$noinline$testOr(int, int) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$noinline$testOr(int, int) disassembly (after)
/// CHECK: orr asr
@@ -201,9 +276,19 @@
(a | (b >> 6)) | (a | (char)b));
}
+ /// CHECK-START-ARM: void Main.$opt$noinline$testXor(long, long) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$noinline$testXor(long, long) disassembly (after)
+ /// CHECK: eor lsr
+ /// CHECK: mov
+ /// CHECK: asr
+ /// CHECK: eor
+
/// CHECK-START-ARM64: void Main.$opt$noinline$testXor(long, long) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$noinline$testXor(long, long) disassembly (after)
/// CHECK: eor lsr
@@ -216,9 +301,12 @@
(a ^ (b >>> 7)) | (a ^ (int)b));
}
+ /// CHECK-START-ARM: void Main.$opt$noinline$testNeg(int) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$noinline$testNeg(int) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$noinline$testNeg(int) disassembly (after)
/// CHECK: neg lsl
@@ -239,9 +327,12 @@
* does occur on the right-hand.
*/
+ /// CHECK-START-ARM: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm64 (after)
/// CHECK-NOT: TypeConversion
@@ -252,9 +343,11 @@
assertIntEquals(a + $noinline$byteToShort(b), a + (short)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendByteInt2(int, byte) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt2(int, byte) instruction_simplifier_arm64 (after)
- /// CHECK-NOT: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
public static void $opt$validateExtendByteInt2(int a, byte b) {
// The conversion to `int` has been optimized away, so there is nothing to merge.
@@ -263,13 +356,25 @@
assertLongEquals(a + $noinline$byteToLong(b), a + (long)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendByteLong(long, byte) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$validateExtendByteLong(long, byte) instruction_simplifier_arm (after)
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendByteLong(long, byte) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendByteLong(long, byte) instruction_simplifier_arm64 (after)
/// CHECK: TypeConversion
@@ -294,9 +399,12 @@
$opt$validateExtendByteLong(a, b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendCharInt1(int, char) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendCharInt1(int, char) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendCharInt1(int, char) instruction_simplifier_arm64 (after)
/// CHECK-NOT: TypeConversion
@@ -306,22 +414,41 @@
assertIntEquals(a + $noinline$charToShort(b), a + (short)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendCharInt2(int, char) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendCharInt2(int, char) instruction_simplifier_arm64 (after)
- /// CHECK-NOT: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
public static void $opt$validateExtendCharInt2(int a, char b) {
// The conversion to `int` has been optimized away, so there is nothing to merge.
assertIntEquals (a + $noinline$charToInt (b), a + (int)b);
- // There is an environment use for `(long)b`, preventing the merge.
+ // There is an environment use for `(long)b` and the implicit `(long)a`, preventing the merge.
assertLongEquals(a + $noinline$charToLong(b), a + (long)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendCharLong(long, char) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$validateExtendCharLong(long, char) instruction_simplifier_arm (after)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendCharLong(long, char) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendCharLong(long, char) instruction_simplifier_arm64 (after)
/// CHECK: TypeConversion
@@ -332,7 +459,7 @@
// The first two tests have a type conversion.
assertLongEquals(a + $noinline$charToByte (b), a + (byte)b);
assertLongEquals(a + $noinline$charToShort(b), a + (short)b);
- // This test does not because the conversion to `int` is optimized away.
+ // On ARM64 this test does not because the conversion to `int` is optimized away.
assertLongEquals(a + $noinline$charToInt (b), a + (int)b);
}
@@ -342,9 +469,12 @@
$opt$validateExtendCharLong(a, b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendShortInt1(int, short) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendShortInt1(int, short) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendShortInt1(int, short) instruction_simplifier_arm64 (after)
/// CHECK-NOT: TypeConversion
@@ -354,21 +484,41 @@
assertIntEquals(a + $noinline$shortToChar (b), a + (char)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendShortInt2(int, short) instruction_simplifier_arm (after)
+ /// CHECK-NOT: DataProcWithShifterOp
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendShortInt2(int, short) instruction_simplifier_arm64 (after)
- /// CHECK-NOT: Arm64DataProcWithShifterOp
- /// CHECK-NOT: Arm64DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
public static void $opt$validateExtendShortInt2(int a, short b) {
// The conversion to `int` has been optimized away, so there is nothing to merge.
assertIntEquals (a + $noinline$shortToInt (b), a + (int)b);
- // There is an environment use for `(long)b`, preventing the merge.
+ // There is an environment use for `(long)b` and the implicit `(long)a`, preventing the merge.
assertLongEquals(a + $noinline$shortToLong (b), a + (long)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendShortLong(long, short) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$validateExtendShortLong(long, short) instruction_simplifier_arm (after)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendShortLong(long, short) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendShortLong(long, short) instruction_simplifier_arm64 (after)
/// CHECK: TypeConversion
@@ -379,7 +529,7 @@
// The first two tests have a type conversion.
assertLongEquals(a + $noinline$shortToByte(b), a + (byte)b);
assertLongEquals(a + $noinline$shortToChar(b), a + (char)b);
- // This test does not because the conversion to `int` is optimized away.
+ // On ARM64 this test does not because the conversion to `int` is optimized away.
assertLongEquals(a + $noinline$shortToInt (b), a + (int)b);
}
@@ -389,11 +539,31 @@
$opt$validateExtendShortLong(a, b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendInt(long, int) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$validateExtendInt(long, int) instruction_simplifier_arm (after)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendInt(long, int) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendInt(long, int) instruction_simplifier_arm64 (after)
/// CHECK: TypeConversion
@@ -411,11 +581,34 @@
assertLongEquals(a + $noinline$intToLong (b), a + (long)b);
}
+ /// CHECK-START-ARM: void Main.$opt$validateExtendLong(long, long) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ /// CHECK-START-ARM: void Main.$opt$validateExtendLong(long, long) instruction_simplifier_arm (after)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
+
/// CHECK-START-ARM64: void Main.$opt$validateExtendLong(long, long) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateExtendLong(long, long) instruction_simplifier_arm64 (after)
/// CHECK: TypeConversion
@@ -449,40 +642,83 @@
// Each test line below should see one merge.
+ /// CHECK-START-ARM: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+ // Note: `b << 32`, `b >> 32` and `b >>> 32` are optimized away by generic simplifier.
+
+ /// CHECK-START-ARM: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm (after)
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Shr
+ /// CHECK-NOT: UShr
+
/// CHECK-START-ARM64: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
// Note: `b << 32`, `b >> 32` and `b >>> 32` are optimized away by generic simplifier.
/// CHECK-START-ARM64: void Main.$opt$validateShiftInt(int, int) instruction_simplifier_arm64 (after)
@@ -552,43 +788,89 @@
}
// Each test line below should see one merge.
+ /// CHECK-START-ARM: void Main.$opt$validateShiftLong(long, long) instruction_simplifier_arm (after)
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
+
+ // On ARM shifts by 1 are not merged.
+ /// CHECK-START-ARM: void Main.$opt$validateShiftLong(long, long) instruction_simplifier_arm (after)
+ /// CHECK: Shl
+ /// CHECK-NOT: Shl
+ /// CHECK: Shr
+ /// CHECK-NOT: Shr
+ /// CHECK: UShr
+ /// CHECK-NOT: UShr
+
/// CHECK-START-ARM64: void Main.$opt$validateShiftLong(long, long) instruction_simplifier_arm64 (after)
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
- /// CHECK: Arm64DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK: DataProcWithShifterOp
+ /// CHECK-NOT: DataProcWithShifterOp
/// CHECK-START-ARM64: void Main.$opt$validateShiftLong(long, long) instruction_simplifier_arm64 (after)
/// CHECK-NOT: Shl
diff --git a/test/593-checker-shift-and-simplifier/src/Main.java b/test/593-checker-shift-and-simplifier/src/Main.java
index 65e809a..c9826bc 100644
--- a/test/593-checker-shift-and-simplifier/src/Main.java
+++ b/test/593-checker-shift-and-simplifier/src/Main.java
@@ -21,6 +21,17 @@
// A very particular set of operations that caused a double removal by the
// ARM64 simplifier doing "forward" removals (b/27851582).
+ /// CHECK-START-ARM: int Main.operations() instruction_simplifier_arm (before)
+ /// CHECK-DAG: <<Get:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Not:i\d+>> Not [<<Get>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<Get>>,i{{\d+}}]
+ /// CHECK-DAG: And [<<Not>>,<<Shl>>]
+ //
+ /// CHECK-START-ARM: int Main.operations() instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Get:i\d+>> ArrayGet
+ /// CHECK-DAG: <<Not:i\d+>> Not [<<Get>>]
+ /// CHECK-DAG: DataProcWithShifterOp [<<Not>>,<<Get>>] kind:And+LSL shift:2
+
/// CHECK-START-ARM64: int Main.operations() instruction_simplifier_arm64 (before)
/// CHECK-DAG: <<Get:i\d+>> ArrayGet
/// CHECK-DAG: <<Not:i\d+>> Not [<<Get>>]
@@ -30,7 +41,7 @@
/// CHECK-START-ARM64: int Main.operations() instruction_simplifier_arm64 (after)
/// CHECK-DAG: <<Get:i\d+>> ArrayGet
/// CHECK-DAG: <<Not:i\d+>> Not [<<Get>>]
- /// CHECK-DAG: Arm64DataProcWithShifterOp [<<Not>>,<<Get>>] kind:And+LSL shift:2
+ /// CHECK-DAG: DataProcWithShifterOp [<<Not>>,<<Get>>] kind:And+LSL shift:2
private static int operations() {
int r = a[0];
int n = ~r;