Merge "Use isolated namespaces for app native libs"
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index eaf2408..f48947d 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -50,6 +50,23 @@
true, // kIntrinsicMinMaxLong
true, // kIntrinsicMinMaxFloat
true, // kIntrinsicMinMaxDouble
+ true, // kIntrinsicCos
+ true, // kIntrinsicSin
+ true, // kIntrinsicAcos
+ true, // kIntrinsicAsin
+ true, // kIntrinsicAtan
+ true, // kIntrinsicAtan2
+ true, // kIntrinsicCbrt
+ true, // kIntrinsicCosh
+ true, // kIntrinsicExp
+ true, // kIntrinsicExpm1
+ true, // kIntrinsicHypot
+ true, // kIntrinsicLog
+ true, // kIntrinsicLog10
+ true, // kIntrinsicNextAfter
+ true, // kIntrinsicSinh
+ true, // kIntrinsicTan
+ true, // kIntrinsicTanh
true, // kIntrinsicSqrt
true, // kIntrinsicCeil
true, // kIntrinsicFloor
@@ -95,6 +112,23 @@
static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong_must_be_static");
static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat_must_be_static");
static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble_must_be_static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCos], "Cos must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicSin], "Sin must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAcos], "Acos must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAsin], "Asin must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAtan], "Atan must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicAtan2], "Atan2 must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCbrt], "Cbrt must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicCosh], "Cosh must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicExp], "Exp must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicExpm1], "Expm1 must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicHypot], "Hypot must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicLog], "Log must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicLog10], "Log10 must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicNextAfter], "NextAfter must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicSinh], "Sinh must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicTan], "Tan must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicTanh], "Tanh must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static");
@@ -196,6 +230,23 @@
"abs", // kNameCacheAbs
"max", // kNameCacheMax
"min", // kNameCacheMin
+ "cos", // kNameCacheCos
+ "sin", // kNameCacheSin
+ "acos", // kNameCacheAcos
+ "asin", // kNameCacheAsin
+ "atan", // kNameCacheAtan
+ "atan2", // kNameCacheAtan2
+ "cbrt", // kNameCacheCbrt
+ "cosh", // kNameCacheCosh
+ "exp", // kNameCacheExp
+ "expm1", // kNameCacheExpm1
+ "hypot", // kNameCacheHypot
+ "log", // kNameCacheLog
+ "log10", // kNameCacheLog10
+ "nextAfter", // kNameCacheNextAfter
+ "sinh", // kNameCacheSinh
+ "tan", // kNameCacheTan
+ "tanh", // kNameCacheTanh
"sqrt", // kNameCacheSqrt
"ceil", // kNameCacheCeil
"floor", // kNameCacheFloor
@@ -425,6 +476,23 @@
INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Cos, D_D, kIntrinsicCos, 0),
+ INTRINSIC(JavaLangMath, Sin, D_D, kIntrinsicSin, 0),
+ INTRINSIC(JavaLangMath, Acos, D_D, kIntrinsicAcos, 0),
+ INTRINSIC(JavaLangMath, Asin, D_D, kIntrinsicAsin, 0),
+ INTRINSIC(JavaLangMath, Atan, D_D, kIntrinsicAtan, 0),
+ INTRINSIC(JavaLangMath, Atan2, DD_D, kIntrinsicAtan2, 0),
+ INTRINSIC(JavaLangMath, Cbrt, D_D, kIntrinsicCbrt, 0),
+ INTRINSIC(JavaLangMath, Cosh, D_D, kIntrinsicCosh, 0),
+ INTRINSIC(JavaLangMath, Exp, D_D, kIntrinsicExp, 0),
+ INTRINSIC(JavaLangMath, Expm1, D_D, kIntrinsicExpm1, 0),
+ INTRINSIC(JavaLangMath, Hypot, DD_D, kIntrinsicHypot, 0),
+ INTRINSIC(JavaLangMath, Log, D_D, kIntrinsicLog, 0),
+ INTRINSIC(JavaLangMath, Log10, D_D, kIntrinsicLog10, 0),
+ INTRINSIC(JavaLangMath, NextAfter, DD_D, kIntrinsicNextAfter, 0),
+ INTRINSIC(JavaLangMath, Sinh, D_D, kIntrinsicSinh, 0),
+ INTRINSIC(JavaLangMath, Tan, D_D, kIntrinsicTan, 0),
+ INTRINSIC(JavaLangMath, Tanh, D_D, kIntrinsicTanh, 0),
INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
@@ -603,6 +671,25 @@
return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */);
case kIntrinsicMinMaxDouble:
return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */);
+ case kIntrinsicCos:
+ case kIntrinsicSin:
+ case kIntrinsicAcos:
+ case kIntrinsicAsin:
+ case kIntrinsicAtan:
+ case kIntrinsicAtan2:
+ case kIntrinsicCbrt:
+ case kIntrinsicCosh:
+ case kIntrinsicExp:
+ case kIntrinsicExpm1:
+ case kIntrinsicHypot:
+ case kIntrinsicLog:
+ case kIntrinsicLog10:
+ case kIntrinsicNextAfter:
+ case kIntrinsicSinh:
+ case kIntrinsicTan:
+ case kIntrinsicTanh:
+ // Not implemented in Quick.
+ return false;
case kIntrinsicSqrt:
return backend->GenInlinedSqrt(info);
case kIntrinsicCeil:
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 5ce110c..ac70577 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -162,6 +162,23 @@
kNameCacheAbs,
kNameCacheMax,
kNameCacheMin,
+ kNameCacheCos,
+ kNameCacheSin,
+ kNameCacheAcos,
+ kNameCacheAsin,
+ kNameCacheAtan,
+ kNameCacheAtan2,
+ kNameCacheCbrt,
+ kNameCacheCosh,
+ kNameCacheExp,
+ kNameCacheExpm1,
+ kNameCacheHypot,
+ kNameCacheLog,
+ kNameCacheLog10,
+ kNameCacheNextAfter,
+ kNameCacheSinh,
+ kNameCacheTan,
+ kNameCacheTanh,
kNameCacheSqrt,
kNameCacheCeil,
kNameCacheFloor,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 82af541..76b57dd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1134,15 +1134,21 @@
// See also Compiler::ResolveDexFile
bool result = false;
- if (IsBootImage()) {
- // We resolve all const-string strings when building for the image.
+ if (IsBootImage() || Runtime::Current()->UseJit()) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
soa.Self(), dex_file, false)));
- class_linker->ResolveString(dex_file, string_idx, dex_cache);
- result = true;
+ if (IsBootImage()) {
+ // We resolve all const-string strings when building for the image.
+ class_linker->ResolveString(dex_file, string_idx, dex_cache);
+ result = true;
+ } else {
+ // Just check whether the dex cache already has the string.
+ DCHECK(Runtime::Current()->UseJit());
+ result = (dex_cache->GetResolvedString(string_idx) != nullptr);
+ }
}
if (result) {
stats_->StringInDexCache();
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index c5c0f13..e806acf 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -446,6 +446,7 @@
info_.StartTag(DW_TAG_compile_unit);
info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
info_.WriteData1(DW_AT_language, DW_LANG_Java);
+ info_.WriteStrp(DW_AT_comp_dir, owner_->WriteString("$JAVA_SRC_ROOT"));
info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_);
info_.WriteUdata(DW_AT_high_pc, compilation_unit.high_pc_ - compilation_unit.low_pc_);
info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index f995cd7..a2b29a3 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -255,7 +255,7 @@
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(28U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(114 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
+ EXPECT_EQ(131 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
}
TEST_F(OatTest, OatHeaderIsValid) {
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index e1404ce..1178d0f 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -2841,15 +2841,21 @@
}
case Instruction::CONST_STRING: {
+ uint32_t string_index = instruction.VRegB_21c();
+ bool in_dex_cache = compiler_driver_->CanAssumeStringIsPresentInDexCache(
+ *dex_file_, string_index);
current_block_->AddInstruction(
- new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_21c(), dex_pc));
+ new (arena_) HLoadString(graph_->GetCurrentMethod(), string_index, dex_pc, in_dex_cache));
UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
case Instruction::CONST_STRING_JUMBO: {
+ uint32_t string_index = instruction.VRegB_31c();
+ bool in_dex_cache = compiler_driver_->CanAssumeStringIsPresentInDexCache(
+ *dex_file_, string_index);
current_block_->AddInstruction(
- new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_31c(), dex_pc));
+ new (arena_) HLoadString(graph_->GetCurrentMethod(), string_index, dex_pc, in_dex_cache));
UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 0a26786..a941935 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3234,6 +3234,146 @@
}
}
+void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
+ Register in = locations->InAt(0).AsRegister<Register>();
+ Location rhs = locations->InAt(1);
+ Register out = locations->Out().AsRegister<Register>();
+
+ if (rhs.IsConstant()) {
+ // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
+ // so map all rotations to a +ve. equivalent in that range.
+ // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
+ uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
+ if (rot) {
+ // Rotate, mapping left rotations to right equivalents if necessary.
+ // (e.g. left by 2 bits == right by 30.)
+ __ Ror(out, in, rot);
+ } else if (out != in) {
+ __ Mov(out, in);
+ }
+ } else {
+ __ Ror(out, in, rhs.AsRegister<Register>());
+ }
+}
+
+// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
+// rotates by swapping input regs (effectively rotating by the first 32-bits of
+// a larger rotation) or flipping direction (thus treating larger right/left
+// rotations as sub-word sized rotations in the other direction) as appropriate.
+void InstructionCodeGeneratorARM::HandleLongRotate(LocationSummary* locations) {
+ Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
+ Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
+ Location rhs = locations->InAt(1);
+ Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
+ Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
+
+ if (rhs.IsConstant()) {
+ uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
+ // Map all rotations to +ve. equivalents on the interval [0,63].
+ rot &= kMaxLongShiftValue;
+ // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
+ // logic below to a simple pair of binary orr.
+ // (e.g. 34 bits == in_reg swap + 2 bits right.)
+ if (rot >= kArmBitsPerWord) {
+ rot -= kArmBitsPerWord;
+ std::swap(in_reg_hi, in_reg_lo);
+ }
+ // Rotate, or mov to out for zero or word size rotations.
+ if (rot != 0u) {
+ __ Lsr(out_reg_hi, in_reg_hi, rot);
+ __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
+ __ Lsr(out_reg_lo, in_reg_lo, rot);
+ __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
+ } else {
+ __ Mov(out_reg_lo, in_reg_lo);
+ __ Mov(out_reg_hi, in_reg_hi);
+ }
+ } else {
+ Register shift_right = locations->GetTemp(0).AsRegister<Register>();
+ Register shift_left = locations->GetTemp(1).AsRegister<Register>();
+ Label end;
+ Label shift_by_32_plus_shift_right;
+
+ __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
+ __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
+ __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
+ __ b(&shift_by_32_plus_shift_right, CC);
+
+ // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
+ // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
+ __ Lsl(out_reg_hi, in_reg_hi, shift_left);
+ __ Lsr(out_reg_lo, in_reg_lo, shift_right);
+ __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
+ __ Lsl(out_reg_lo, in_reg_lo, shift_left);
+ __ Lsr(shift_left, in_reg_hi, shift_right);
+ __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
+ __ b(&end);
+
+ __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
+ // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
+ // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
+ __ Lsr(out_reg_hi, in_reg_hi, shift_right);
+ __ Lsl(out_reg_lo, in_reg_lo, shift_left);
+ __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
+ __ Lsr(out_reg_lo, in_reg_lo, shift_right);
+ __ Lsl(shift_right, in_reg_hi, shift_left);
+ __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
+
+ __ Bind(&end);
+ }
+}
+void LocationsBuilderARM::HandleRotate(HRor* ror) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
+ switch (ror->GetResultType()) {
+ case Primitive::kPrimInt: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+ }
+ case Primitive::kPrimLong: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ if (ror->InputAt(1)->IsConstant()) {
+ locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
+ } else {
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
+ }
+}
+
+void InstructionCodeGeneratorARM::HandleRotate(HRor* ror) {
+ LocationSummary* locations = ror->GetLocations();
+ Primitive::Type type = ror->GetResultType();
+ switch (type) {
+ case Primitive::kPrimInt: {
+ HandleIntegerRotate(locations);
+ break;
+ }
+ case Primitive::kPrimLong: {
+ HandleLongRotate(locations);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected operation type " << type;
+ }
+}
+
+void LocationsBuilderARM::VisitRor(HRor* op) {
+ HandleRotate(op);
+}
+
+void InstructionCodeGeneratorARM::VisitRor(HRor* op) {
+ HandleRotate(op);
+}
+
void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
@@ -5067,16 +5207,15 @@
}
void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
- codegen_->AddSlowPath(slow_path);
-
LocationSummary* locations = load->GetLocations();
Location out_loc = locations->Out();
Register out = out_loc.AsRegister<Register>();
@@ -5107,8 +5246,12 @@
__ LoadFromOffset(kLoadWord, out, out, cache_offset);
}
- __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ if (!load->IsInDexCache()) {
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
+ codegen_->AddSlowPath(slow_path);
+ __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
static int32_t GetExceptionTlsOffset() {
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 193add2..8193c28 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -170,6 +170,9 @@
private:
void HandleInvoke(HInvoke* invoke);
void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
+ void HandleIntegerRotate(LocationSummary* locations);
+ void HandleLongRotate(LocationSummary* locations);
+ void HandleRotate(HRor* ror);
void HandleShift(HBinaryOperation* operation);
void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
@@ -213,6 +216,9 @@
void GenerateOrrConst(Register out, Register first, uint32_t value);
void GenerateEorConst(Register out, Register first, uint32_t value);
void HandleBitwiseOperation(HBinaryOperation* operation);
+ void HandleIntegerRotate(LocationSummary* locations);
+ void HandleLongRotate(LocationSummary* locations);
+ void HandleRotate(HRor* ror);
void HandleShift(HBinaryOperation* operation);
void GenerateMemoryBarrier(MemBarrierKind kind);
void GenerateWideAtomicStore(Register addr, uint32_t offset,
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 227f4be..b7efbe3 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1791,6 +1791,17 @@
__ Orr(dst, lhs, rhs);
} else if (instr->IsSub()) {
__ Sub(dst, lhs, rhs);
+ } else if (instr->IsRor()) {
+ if (rhs.IsImmediate()) {
+ uint32_t shift = rhs.immediate() & (lhs.SizeInBits() - 1);
+ __ Ror(dst, lhs, shift);
+ } else {
+ // Ensure shift distance is in the same size register as the result. If
+ // we are rotating a long and the shift comes in a w register originally,
+ // we don't need to sxtw for use as an x since the shift distances are
+ // all & reg_bits - 1.
+ __ Ror(dst, lhs, RegisterFrom(instr->GetLocations()->InAt(1), type));
+ }
} else {
DCHECK(instr->IsXor());
__ Eor(dst, lhs, rhs);
@@ -3850,16 +3861,15 @@
}
void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
- SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
- codegen_->AddSlowPath(slow_path);
-
Location out_loc = load->GetLocations()->Out();
Register out = OutputRegister(load);
Register current_method = InputRegisterAt(load, 0);
@@ -3889,8 +3899,12 @@
__ Ldr(out, MemOperand(out.X(), cache_offset));
}
- __ Cbz(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ if (!load->IsInDexCache()) {
+ SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
+ codegen_->AddSlowPath(slow_path);
+ __ Cbz(out, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
void LocationsBuilderARM64::VisitLocal(HLocal* local) {
@@ -4258,6 +4272,14 @@
codegen_->GenerateFrameExit();
}
+void LocationsBuilderARM64::VisitRor(HRor* ror) {
+ HandleBinaryOp(ror);
+}
+
+void InstructionCodeGeneratorARM64::VisitRor(HRor* ror) {
+ HandleBinaryOp(ror);
+}
+
void LocationsBuilderARM64::VisitShl(HShl* shl) {
HandleShift(shl);
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index d092de9..ce7cbcd 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -3413,24 +3413,28 @@
}
void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
- SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
- codegen_->AddSlowPath(slow_path);
-
LocationSummary* locations = load->GetLocations();
Register out = locations->Out().AsRegister<Register>();
Register current_method = locations->InAt(0).AsRegister<Register>();
__ LoadFromOffset(kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
__ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
__ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
- __ Beqz(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+
+ if (!load->IsInDexCache()) {
+ SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
+ codegen_->AddSlowPath(slow_path);
+ __ Beqz(out, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
void LocationsBuilderMIPS::VisitLocal(HLocal* local) {
@@ -3913,6 +3917,16 @@
codegen_->GenerateFrameExit();
}
+void LocationsBuilderMIPS::VisitRor(HRor* ror ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+}
+
+void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+}
+
void LocationsBuilderMIPS::VisitShl(HShl* shl) {
HandleShift(shl);
}
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 78f5644..1a9de15 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3105,16 +3105,15 @@
}
void LocationsBuilderMIPS64::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorMIPS64::VisitLoadString(HLoadString* load) {
- SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
- codegen_->AddSlowPath(slow_path);
-
LocationSummary* locations = load->GetLocations();
GpuRegister out = locations->Out().AsRegister<GpuRegister>();
GpuRegister current_method = locations->InAt(0).AsRegister<GpuRegister>();
@@ -3123,8 +3122,13 @@
__ LoadFromOffset(kLoadDoubleword, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
__ LoadFromOffset(kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
// TODO: We will need a read barrier here.
- __ Beqzc(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+
+ if (!load->IsInDexCache()) {
+ SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
+ codegen_->AddSlowPath(slow_path);
+ __ Beqzc(out, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
void LocationsBuilderMIPS64::VisitLocal(HLocal* local) {
@@ -3519,6 +3523,16 @@
codegen_->GenerateFrameExit();
}
+void LocationsBuilderMIPS64::VisitRor(HRor* ror ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+}
+
+void InstructionCodeGeneratorMIPS64::VisitRor(HRor* ror ATTRIBUTE_UNUSED) {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+}
+
void LocationsBuilderMIPS64::VisitShl(HShl* shl) {
HandleShift(shl);
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 19f03df..0fb552a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3759,6 +3759,92 @@
__ Bind(&done);
}
+void LocationsBuilderX86::VisitRor(HRor* ror) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
+
+ switch (ror->GetResultType()) {
+ case Primitive::kPrimLong:
+ // Add the temporary needed.
+ locations->AddTemp(Location::RequiresRegister());
+ FALLTHROUGH_INTENDED;
+ case Primitive::kPrimInt:
+ locations->SetInAt(0, Location::RequiresRegister());
+ // The shift count needs to be in CL (unless it is a constant).
+ locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, ror->InputAt(1)));
+ locations->SetOut(Location::SameAsFirstInput());
+ break;
+ default:
+ LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
+ UNREACHABLE();
+ }
+}
+
+void InstructionCodeGeneratorX86::VisitRor(HRor* ror) {
+ LocationSummary* locations = ror->GetLocations();
+ Location first = locations->InAt(0);
+ Location second = locations->InAt(1);
+
+ if (ror->GetResultType() == Primitive::kPrimInt) {
+ Register first_reg = first.AsRegister<Register>();
+ if (second.IsRegister()) {
+ Register second_reg = second.AsRegister<Register>();
+ __ rorl(first_reg, second_reg);
+ } else {
+ Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
+ __ rorl(first_reg, imm);
+ }
+ return;
+ }
+
+ DCHECK_EQ(ror->GetResultType(), Primitive::kPrimLong);
+ Register first_reg_lo = first.AsRegisterPairLow<Register>();
+ Register first_reg_hi = first.AsRegisterPairHigh<Register>();
+ Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
+ if (second.IsRegister()) {
+ Register second_reg = second.AsRegister<Register>();
+ DCHECK_EQ(second_reg, ECX);
+ __ movl(temp_reg, first_reg_hi);
+ __ shrd(first_reg_hi, first_reg_lo, second_reg);
+ __ shrd(first_reg_lo, temp_reg, second_reg);
+ __ movl(temp_reg, first_reg_hi);
+ __ testl(second_reg, Immediate(32));
+ __ cmovl(kNotEqual, first_reg_hi, first_reg_lo);
+ __ cmovl(kNotEqual, first_reg_lo, temp_reg);
+ } else {
+ int32_t shift_amt =
+ CodeGenerator::GetInt64ValueOf(second.GetConstant()) & kMaxLongShiftValue;
+ if (shift_amt == 0) {
+ // Already fine.
+ return;
+ }
+ if (shift_amt == 32) {
+ // Just swap.
+ __ movl(temp_reg, first_reg_lo);
+ __ movl(first_reg_lo, first_reg_hi);
+ __ movl(first_reg_hi, temp_reg);
+ return;
+ }
+
+ Immediate imm(shift_amt);
+ // Save the constents of the low value.
+ __ movl(temp_reg, first_reg_lo);
+
+ // Shift right into low, feeding bits from high.
+ __ shrd(first_reg_lo, first_reg_hi, imm);
+
+ // Shift right into high, feeding bits from the original low.
+ __ shrd(first_reg_hi, temp_reg, imm);
+
+ // Swap if needed.
+ if (shift_amt > 32) {
+ __ movl(temp_reg, first_reg_lo);
+ __ movl(first_reg_lo, first_reg_hi);
+ __ movl(first_reg_hi, temp_reg);
+ }
+ }
+}
+
void LocationsBuilderX86::VisitShl(HShl* shl) {
HandleShift(shl);
}
@@ -5611,16 +5697,15 @@
}
void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
- codegen_->AddSlowPath(slow_path);
-
LocationSummary* locations = load->GetLocations();
Location out_loc = locations->Out();
Register out = out_loc.AsRegister<Register>();
@@ -5651,9 +5736,13 @@
__ movl(out, Address(out, cache_offset));
}
- __ testl(out, out);
- __ j(kEqual, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ if (!load->IsInDexCache()) {
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
+ codegen_->AddSlowPath(slow_path);
+ __ testl(out, out);
+ __ j(kEqual, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
static Address GetExceptionTlsAddress() {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 44a51ea..610ce67 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3758,6 +3758,55 @@
}
}
+void LocationsBuilderX86_64::VisitRor(HRor* ror) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
+
+ switch (ror->GetResultType()) {
+ case Primitive::kPrimInt:
+ case Primitive::kPrimLong: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ // The shift count needs to be in CL (unless it is a constant).
+ locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, ror->InputAt(1)));
+ locations->SetOut(Location::SameAsFirstInput());
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
+ UNREACHABLE();
+ }
+}
+
+void InstructionCodeGeneratorX86_64::VisitRor(HRor* ror) {
+ LocationSummary* locations = ror->GetLocations();
+ CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
+ Location second = locations->InAt(1);
+
+ switch (ror->GetResultType()) {
+ case Primitive::kPrimInt:
+ if (second.IsRegister()) {
+ CpuRegister second_reg = second.AsRegister<CpuRegister>();
+ __ rorl(first_reg, second_reg);
+ } else {
+ Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
+ __ rorl(first_reg, imm);
+ }
+ break;
+ case Primitive::kPrimLong:
+ if (second.IsRegister()) {
+ CpuRegister second_reg = second.AsRegister<CpuRegister>();
+ __ rorq(first_reg, second_reg);
+ } else {
+ Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
+ __ rorq(first_reg, imm);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
+ UNREACHABLE();
+ }
+}
+
void LocationsBuilderX86_64::VisitShl(HShl* shl) {
HandleShift(shl);
}
@@ -5220,16 +5269,15 @@
}
void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
- LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ LocationSummary::CallKind call_kind = (!load->IsInDexCache() || kEmitCompilerReadBarrier)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister());
}
void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
- codegen_->AddSlowPath(slow_path);
-
LocationSummary* locations = load->GetLocations();
Location out_loc = locations->Out();
CpuRegister out = out_loc.AsRegister<CpuRegister>();
@@ -5260,9 +5308,13 @@
__ movl(out, Address(out, cache_offset));
}
- __ testl(out, out);
- __ j(kEqual, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
+ if (!load->IsInDexCache()) {
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
+ codegen_->AddSlowPath(slow_path);
+ __ testl(out, out);
+ __ j(kEqual, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ }
}
static Address GetExceptionTlsAddress() {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 145b1f3..7351fed 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -47,6 +47,12 @@
static constexpr size_t kRuntimeParameterFpuRegistersLength =
arraysize(kRuntimeParameterFpuRegisters);
+// These XMM registers are non-volatile in ART ABI, but volatile in native ABI.
+// If the ART ABI changes, this list must be updated. It is used to ensure that
+// these are not clobbered by any direct call to native code (such as math intrinsics).
+static constexpr FloatRegister non_volatile_xmm_regs[] = { XMM12, XMM13, XMM14, XMM15 };
+
+
class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> {
public:
InvokeRuntimeCallingConvention()
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index af8b8b5..10d8343 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -202,6 +202,11 @@
return true;
}
+ // Our code generator ensures shift distances are within an encodable range.
+ if (instr->IsRor()) {
+ return true;
+ }
+
int64_t value = CodeGenerator::GetInt64ValueOf(constant);
if (instr->IsAnd() || instr->IsOr() || instr->IsXor()) {
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index c16b872..dfc363f 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -850,7 +850,7 @@
void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
VisitInstruction(op);
- if (op->IsUShr() || op->IsShr() || op->IsShl()) {
+ if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
AddError(StringPrintf(
"Shift operation %s %d has a non-int kind second input: "
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2f3df7f..6946265 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -39,6 +39,12 @@
}
}
+ bool ReplaceRotateWithRor(HBinaryOperation* op, HUShr* ushr, HShl* shl);
+ bool TryReplaceWithRotate(HBinaryOperation* instruction);
+ bool TryReplaceWithRotateConstantPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
+ bool TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
+ bool TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op, HUShr* ushr, HShl* shl);
+
bool TryMoveNegOnInputsAfterBinop(HBinaryOperation* binop);
void VisitShift(HBinaryOperation* shift);
@@ -77,6 +83,7 @@
bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const;
+ void SimplifyRotate(HInvoke* invoke, bool is_left);
void SimplifySystemArrayCopy(HInvoke* invoke);
void SimplifyStringEquals(HInvoke* invoke);
@@ -173,6 +180,161 @@
}
}
+static bool IsSubRegBitsMinusOther(HSub* sub, size_t reg_bits, HInstruction* other) {
+ return (sub->GetRight() == other &&
+ sub->GetLeft()->IsConstant() &&
+ (Int64FromConstant(sub->GetLeft()->AsConstant()) & (reg_bits - 1)) == 0);
+}
+
+bool InstructionSimplifierVisitor::ReplaceRotateWithRor(HBinaryOperation* op,
+ HUShr* ushr,
+ HShl* shl) {
+ DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
+ HRor* ror = new (GetGraph()->GetArena()) HRor(ushr->GetType(),
+ ushr->GetLeft(),
+ ushr->GetRight());
+ op->GetBlock()->ReplaceAndRemoveInstructionWith(op, ror);
+ if (!ushr->HasUses()) {
+ ushr->GetBlock()->RemoveInstruction(ushr);
+ }
+ if (!ushr->GetRight()->HasUses()) {
+ ushr->GetRight()->GetBlock()->RemoveInstruction(ushr->GetRight());
+ }
+ if (!shl->HasUses()) {
+ shl->GetBlock()->RemoveInstruction(shl);
+ }
+ if (!shl->GetRight()->HasUses()) {
+ shl->GetRight()->GetBlock()->RemoveInstruction(shl->GetRight());
+ }
+ return true;
+}
+
+// Try to replace a binary operation flanked by one UShr and one Shl with a bitfield rotation.
+bool InstructionSimplifierVisitor::TryReplaceWithRotate(HBinaryOperation* op) {
+ // This simplification is currently supported on ARM and ARM64.
+ // TODO: Implement it for MIPS/64.
+ const InstructionSet instruction_set = GetGraph()->GetInstructionSet();
+ switch (instruction_set) {
+ case kArm:
+ case kArm64:
+ case kThumb2:
+ case kX86:
+ case kX86_64:
+ break;
+ default:
+ return false;
+ }
+ DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
+ HInstruction* left = op->GetLeft();
+ HInstruction* right = op->GetRight();
+ // If we have an UShr and a Shl (in either order).
+ if ((left->IsUShr() && right->IsShl()) || (left->IsShl() && right->IsUShr())) {
+ HUShr* ushr = left->IsUShr() ? left->AsUShr() : right->AsUShr();
+ HShl* shl = left->IsShl() ? left->AsShl() : right->AsShl();
+ DCHECK(Primitive::IsIntOrLongType(ushr->GetType()));
+ if (ushr->GetType() == shl->GetType() &&
+ ushr->GetLeft() == shl->GetLeft()) {
+ if (ushr->GetRight()->IsConstant() && shl->GetRight()->IsConstant()) {
+ // Shift distances are both constant, try replacing with Ror if they
+ // add up to the register size.
+ return TryReplaceWithRotateConstantPattern(op, ushr, shl);
+ } else if (ushr->GetRight()->IsSub() || shl->GetRight()->IsSub()) {
+ // Shift distances are potentially of the form x and (reg_size - x).
+ return TryReplaceWithRotateRegisterSubPattern(op, ushr, shl);
+ } else if (ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg()) {
+ // Shift distances are potentially of the form d and -d.
+ return TryReplaceWithRotateRegisterNegPattern(op, ushr, shl);
+ }
+ }
+ }
+ return false;
+}
+
+// Try replacing code looking like (x >>> #rdist OP x << #ldist):
+// UShr dst, x, #rdist
+// Shl tmp, x, #ldist
+// OP dst, dst, tmp
+// or like (x >>> #rdist OP x << #-ldist):
+// UShr dst, x, #rdist
+// Shl tmp, x, #-ldist
+// OP dst, dst, tmp
+// with
+// Ror dst, x, #rdist
+bool InstructionSimplifierVisitor::TryReplaceWithRotateConstantPattern(HBinaryOperation* op,
+ HUShr* ushr,
+ HShl* shl) {
+ DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
+ size_t reg_bits = Primitive::ComponentSize(ushr->GetType()) * kBitsPerByte;
+ size_t rdist = Int64FromConstant(ushr->GetRight()->AsConstant());
+ size_t ldist = Int64FromConstant(shl->GetRight()->AsConstant());
+ if (((ldist + rdist) & (reg_bits - 1)) == 0) {
+ ReplaceRotateWithRor(op, ushr, shl);
+ return true;
+ }
+ return false;
+}
+
+// Replace code looking like (x >>> -d OP x << d):
+// Neg neg, d
+// UShr dst, x, neg
+// Shl tmp, x, d
+// OP dst, dst, tmp
+// with
+// Neg neg, d
+// Ror dst, x, neg
+// *** OR ***
+// Replace code looking like (x >>> d OP x << -d):
+// UShr dst, x, d
+// Neg neg, d
+// Shl tmp, x, neg
+// OP dst, dst, tmp
+// with
+// Ror dst, x, d
+bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterNegPattern(HBinaryOperation* op,
+ HUShr* ushr,
+ HShl* shl) {
+ DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
+ DCHECK(ushr->GetRight()->IsNeg() || shl->GetRight()->IsNeg());
+ bool neg_is_left = shl->GetRight()->IsNeg();
+ HNeg* neg = neg_is_left ? shl->GetRight()->AsNeg() : ushr->GetRight()->AsNeg();
+ // And the shift distance being negated is the distance being shifted the other way.
+ if (neg->InputAt(0) == (neg_is_left ? ushr->GetRight() : shl->GetRight())) {
+ ReplaceRotateWithRor(op, ushr, shl);
+ }
+ return false;
+}
+
+// Try replacing code looking like (x >>> d OP x << (#bits - d)):
+// UShr dst, x, d
+// Sub ld, #bits, d
+// Shl tmp, x, ld
+// OP dst, dst, tmp
+// with
+// Ror dst, x, d
+// *** OR ***
+// Replace code looking like (x >>> (#bits - d) OP x << d):
+// Sub rd, #bits, d
+// UShr dst, x, rd
+// Shl tmp, x, d
+// OP dst, dst, tmp
+// with
+// Neg neg, d
+// Ror dst, x, neg
+bool InstructionSimplifierVisitor::TryReplaceWithRotateRegisterSubPattern(HBinaryOperation* op,
+ HUShr* ushr,
+ HShl* shl) {
+ DCHECK(op->IsAdd() || op->IsXor() || op->IsOr());
+ DCHECK(ushr->GetRight()->IsSub() || shl->GetRight()->IsSub());
+ size_t reg_bits = Primitive::ComponentSize(ushr->GetType()) * kBitsPerByte;
+ HInstruction* shl_shift = shl->GetRight();
+ HInstruction* ushr_shift = ushr->GetRight();
+ if ((shl_shift->IsSub() && IsSubRegBitsMinusOther(shl_shift->AsSub(), reg_bits, ushr_shift)) ||
+ (ushr_shift->IsSub() && IsSubRegBitsMinusOther(ushr_shift->AsSub(), reg_bits, shl_shift))) {
+ return ReplaceRotateWithRor(op, ushr, shl);
+ }
+ return false;
+}
+
void InstructionSimplifierVisitor::VisitNullCheck(HNullCheck* null_check) {
HInstruction* obj = null_check->InputAt(0);
if (!obj->CanBeNull()) {
@@ -530,7 +692,10 @@
instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, sub);
RecordSimplification();
neg->GetBlock()->RemoveInstruction(neg);
+ return;
}
+
+ TryReplaceWithRotate(instruction);
}
void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
@@ -906,7 +1071,10 @@
// src
instruction->ReplaceWith(instruction->GetLeft());
instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
}
+
+ TryReplaceWithRotate(instruction);
}
void InstructionSimplifierVisitor::VisitShl(HShl* instruction) {
@@ -1027,6 +1195,8 @@
RecordSimplification();
return;
}
+
+ TryReplaceWithRotate(instruction);
}
void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
@@ -1095,6 +1265,42 @@
}
}
+void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, bool is_left) {
+ DCHECK(invoke->IsInvokeStaticOrDirect());
+ DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic);
+ // This simplification is currently supported on ARM and ARM64.
+ // TODO: Implement it for MIPS/64.
+ const InstructionSet instruction_set = GetGraph()->GetInstructionSet();
+ switch (instruction_set) {
+ case kArm:
+ case kArm64:
+ case kThumb2:
+ case kX86:
+ case kX86_64:
+ break;
+ default:
+ return;
+ }
+ HInstruction* value = invoke->InputAt(0);
+ HInstruction* distance = invoke->InputAt(1);
+ // Replace the invoke with an HRor.
+ if (is_left) {
+ distance = new (GetGraph()->GetArena()) HNeg(distance->GetType(), distance);
+ invoke->GetBlock()->InsertInstructionBefore(distance, invoke);
+ }
+ HRor* ror = new (GetGraph()->GetArena()) HRor(value->GetType(), value, distance);
+ invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, ror);
+ // Remove ClinitCheck and LoadClass, if possible.
+ HInstruction* clinit = invoke->InputAt(invoke->InputCount() - 1);
+ if (clinit->IsClinitCheck() && !clinit->HasUses()) {
+ clinit->GetBlock()->RemoveInstruction(clinit);
+ HInstruction* ldclass = clinit->InputAt(0);
+ if (ldclass->IsLoadClass() && !ldclass->HasUses()) {
+ ldclass->GetBlock()->RemoveInstruction(ldclass);
+ }
+ }
+}
+
static bool IsArrayLengthOf(HInstruction* potential_length, HInstruction* potential_array) {
if (potential_length->IsArrayLength()) {
return potential_length->InputAt(0) == potential_array;
@@ -1165,6 +1371,12 @@
SimplifyStringEquals(instruction);
} else if (instruction->GetIntrinsic() == Intrinsics::kSystemArrayCopy) {
SimplifySystemArrayCopy(instruction);
+ } else if (instruction->GetIntrinsic() == Intrinsics::kIntegerRotateRight ||
+ instruction->GetIntrinsic() == Intrinsics::kLongRotateRight) {
+ SimplifyRotate(instruction, false);
+ } else if (instruction->GetIntrinsic() == Intrinsics::kIntegerRotateLeft ||
+ instruction->GetIntrinsic() == Intrinsics::kLongRotateLeft) {
+ SimplifyRotate(instruction, true);
}
}
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 8340811..7127215 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -189,6 +189,42 @@
return ((method.d.data & kIntrinsicFlagMin) == 0) ?
Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
+ // More math builtins.
+ case kIntrinsicCos:
+ return Intrinsics::kMathCos;
+ case kIntrinsicSin:
+ return Intrinsics::kMathSin;
+ case kIntrinsicAcos:
+ return Intrinsics::kMathAcos;
+ case kIntrinsicAsin:
+ return Intrinsics::kMathAsin;
+ case kIntrinsicAtan:
+ return Intrinsics::kMathAtan;
+ case kIntrinsicAtan2:
+ return Intrinsics::kMathAtan2;
+ case kIntrinsicCbrt:
+ return Intrinsics::kMathCbrt;
+ case kIntrinsicCosh:
+ return Intrinsics::kMathCosh;
+ case kIntrinsicExp:
+ return Intrinsics::kMathExp;
+ case kIntrinsicExpm1:
+ return Intrinsics::kMathExpm1;
+ case kIntrinsicHypot:
+ return Intrinsics::kMathHypot;
+ case kIntrinsicLog:
+ return Intrinsics::kMathLog;
+ case kIntrinsicLog10:
+ return Intrinsics::kMathLog10;
+ case kIntrinsicNextAfter:
+ return Intrinsics::kMathNextAfter;
+ case kIntrinsicSinh:
+ return Intrinsics::kMathSinh;
+ case kIntrinsicTan:
+ return Intrinsics::kMathTan;
+ case kIntrinsicTanh:
+ return Intrinsics::kMathTanh;
+
// Misc math.
case kIntrinsicSqrt:
return Intrinsics::kMathSqrt;
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 5329b5c..e8181bb 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -240,178 +240,6 @@
GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
}
-static void GenIntegerRotate(LocationSummary* locations,
- ArmAssembler* assembler,
- bool is_left) {
- Register in = locations->InAt(0).AsRegister<Register>();
- Location rhs = locations->InAt(1);
- Register out = locations->Out().AsRegister<Register>();
-
- if (rhs.IsConstant()) {
- // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
- // so map all rotations to a +ve. equivalent in that range.
- // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
- uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue() & 0x1F;
- if (rot) {
- // Rotate, mapping left rotations to right equivalents if necessary.
- // (e.g. left by 2 bits == right by 30.)
- __ Ror(out, in, is_left ? (0x20 - rot) : rot);
- } else if (out != in) {
- __ Mov(out, in);
- }
- } else {
- if (is_left) {
- __ rsb(out, rhs.AsRegister<Register>(), ShifterOperand(0));
- __ Ror(out, in, out);
- } else {
- __ Ror(out, in, rhs.AsRegister<Register>());
- }
- }
-}
-
-// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
-// rotates by swapping input regs (effectively rotating by the first 32-bits of
-// a larger rotation) or flipping direction (thus treating larger right/left
-// rotations as sub-word sized rotations in the other direction) as appropriate.
-static void GenLongRotate(LocationSummary* locations,
- ArmAssembler* assembler,
- bool is_left) {
- Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
- Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
- Location rhs = locations->InAt(1);
- Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
- Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
-
- if (rhs.IsConstant()) {
- uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue();
- // Map all left rotations to right equivalents.
- if (is_left) {
- rot = 0x40 - rot;
- }
- // Map all rotations to +ve. equivalents on the interval [0,63].
- rot &= 0x3F;
- // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
- // logic below to a simple pair of binary orr.
- // (e.g. 34 bits == in_reg swap + 2 bits right.)
- if (rot >= 0x20) {
- rot -= 0x20;
- std::swap(in_reg_hi, in_reg_lo);
- }
- // Rotate, or mov to out for zero or word size rotations.
- if (rot) {
- __ Lsr(out_reg_hi, in_reg_hi, rot);
- __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, 0x20 - rot));
- __ Lsr(out_reg_lo, in_reg_lo, rot);
- __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, 0x20 - rot));
- } else {
- __ Mov(out_reg_lo, in_reg_lo);
- __ Mov(out_reg_hi, in_reg_hi);
- }
- } else {
- Register shift_left = locations->GetTemp(0).AsRegister<Register>();
- Register shift_right = locations->GetTemp(1).AsRegister<Register>();
- Label end;
- Label right;
-
- __ and_(shift_left, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
- __ Lsrs(shift_right, rhs.AsRegister<Register>(), 6);
- __ rsb(shift_right, shift_left, ShifterOperand(0x20), AL, kCcKeep);
-
- if (is_left) {
- __ b(&right, CS);
- } else {
- __ b(&right, CC);
- std::swap(shift_left, shift_right);
- }
-
- // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
- // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
- __ Lsl(out_reg_hi, in_reg_hi, shift_left);
- __ Lsr(out_reg_lo, in_reg_lo, shift_right);
- __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
- __ Lsl(out_reg_lo, in_reg_lo, shift_left);
- __ Lsr(shift_left, in_reg_hi, shift_right);
- __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
- __ b(&end);
-
- // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
- // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
- __ Bind(&right);
- __ Lsr(out_reg_hi, in_reg_hi, shift_right);
- __ Lsl(out_reg_lo, in_reg_lo, shift_left);
- __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
- __ Lsr(out_reg_lo, in_reg_lo, shift_right);
- __ Lsl(shift_right, in_reg_hi, shift_left);
- __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
-
- __ Bind(&end);
- }
-}
-
-void IntrinsicLocationsBuilderARM::VisitIntegerRotateRight(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM::VisitIntegerRotateRight(HInvoke* invoke) {
- GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false);
-}
-
-void IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- if (invoke->InputAt(1)->IsConstant()) {
- locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant()));
- } else {
- locations->SetInAt(1, Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- }
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM::VisitLongRotateRight(HInvoke* invoke) {
- GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false);
-}
-
-void IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM::VisitIntegerRotateLeft(HInvoke* invoke) {
- GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true);
-}
-
-void IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- if (invoke->InputAt(1)->IsConstant()) {
- locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant()));
- } else {
- locations->SetInAt(1, Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- locations->AddTemp(Location::RequiresRegister());
- }
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM::VisitLongRotateLeft(HInvoke* invoke) {
- GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true);
-}
-
static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
Location in = locations->InAt(0);
Location out = locations->Out();
@@ -1700,8 +1528,12 @@
UNIMPLEMENTED_INTRINSIC(IntegerReverse)
UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
UNIMPLEMENTED_INTRINSIC(LongReverse)
UNIMPLEMENTED_INTRINSIC(LongReverseBytes)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
UNIMPLEMENTED_INTRINSIC(ShortReverseBytes)
UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble)
UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat)
@@ -1718,6 +1550,23 @@
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
+UNIMPLEMENTED_INTRINSIC(MathCos)
+UNIMPLEMENTED_INTRINSIC(MathSin)
+UNIMPLEMENTED_INTRINSIC(MathAcos)
+UNIMPLEMENTED_INTRINSIC(MathAsin)
+UNIMPLEMENTED_INTRINSIC(MathAtan)
+UNIMPLEMENTED_INTRINSIC(MathAtan2)
+UNIMPLEMENTED_INTRINSIC(MathCbrt)
+UNIMPLEMENTED_INTRINSIC(MathCosh)
+UNIMPLEMENTED_INTRINSIC(MathExp)
+UNIMPLEMENTED_INTRINSIC(MathExpm1)
+UNIMPLEMENTED_INTRINSIC(MathHypot)
+UNIMPLEMENTED_INTRINSIC(MathLog)
+UNIMPLEMENTED_INTRINSIC(MathLog10)
+UNIMPLEMENTED_INTRINSIC(MathNextAfter)
+UNIMPLEMENTED_INTRINSIC(MathSinh)
+UNIMPLEMENTED_INTRINSIC(MathTan)
+UNIMPLEMENTED_INTRINSIC(MathTanh)
#undef UNIMPLEMENTED_INTRINSIC
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 962c4d5..6b34daa 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -330,103 +330,6 @@
GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
}
-static void GenRotateRight(LocationSummary* locations,
- Primitive::Type type,
- vixl::MacroAssembler* masm) {
- DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
-
- Location in = locations->InAt(0);
- Location out = locations->Out();
- Operand rhs = OperandFrom(locations->InAt(1), type);
-
- if (rhs.IsImmediate()) {
- uint32_t shift = rhs.immediate() & (RegisterFrom(in, type).SizeInBits() - 1);
- __ Ror(RegisterFrom(out, type),
- RegisterFrom(in, type),
- shift);
- } else {
- DCHECK(rhs.shift() == vixl::LSL && rhs.shift_amount() == 0);
- __ Ror(RegisterFrom(out, type),
- RegisterFrom(in, type),
- rhs.reg());
- }
-}
-
-void IntrinsicLocationsBuilderARM64::VisitIntegerRotateRight(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitIntegerRotateRight(HInvoke* invoke) {
- GenRotateRight(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
-}
-
-void IntrinsicLocationsBuilderARM64::VisitLongRotateRight(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitLongRotateRight(HInvoke* invoke) {
- GenRotateRight(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
-}
-
-static void GenRotateLeft(LocationSummary* locations,
- Primitive::Type type,
- vixl::MacroAssembler* masm) {
- DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
-
- Location in = locations->InAt(0);
- Location out = locations->Out();
- Operand rhs = OperandFrom(locations->InAt(1), type);
-
- if (rhs.IsImmediate()) {
- uint32_t regsize = RegisterFrom(in, type).SizeInBits();
- uint32_t shift = (regsize - rhs.immediate()) & (regsize - 1);
- __ Ror(RegisterFrom(out, type), RegisterFrom(in, type), shift);
- } else {
- DCHECK(rhs.shift() == vixl::LSL && rhs.shift_amount() == 0);
- __ Neg(RegisterFrom(out, type),
- Operand(RegisterFrom(locations->InAt(1), type)));
- __ Ror(RegisterFrom(out, type),
- RegisterFrom(in, type),
- RegisterFrom(out, type));
- }
-}
-
-void IntrinsicLocationsBuilderARM64::VisitIntegerRotateLeft(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitIntegerRotateLeft(HInvoke* invoke) {
- GenRotateLeft(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
-}
-
-void IntrinsicLocationsBuilderARM64::VisitLongRotateLeft(HInvoke* invoke) {
- LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
- locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitLongRotateLeft(HInvoke* invoke) {
- GenRotateLeft(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
-}
-
static void GenReverse(LocationSummary* locations,
Primitive::Type type,
vixl::MacroAssembler* masm) {
@@ -1527,11 +1430,33 @@
void IntrinsicCodeGeneratorARM64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
}
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
+UNIMPLEMENTED_INTRINSIC(MathCos)
+UNIMPLEMENTED_INTRINSIC(MathSin)
+UNIMPLEMENTED_INTRINSIC(MathAcos)
+UNIMPLEMENTED_INTRINSIC(MathAsin)
+UNIMPLEMENTED_INTRINSIC(MathAtan)
+UNIMPLEMENTED_INTRINSIC(MathAtan2)
+UNIMPLEMENTED_INTRINSIC(MathCbrt)
+UNIMPLEMENTED_INTRINSIC(MathCosh)
+UNIMPLEMENTED_INTRINSIC(MathExp)
+UNIMPLEMENTED_INTRINSIC(MathExpm1)
+UNIMPLEMENTED_INTRINSIC(MathHypot)
+UNIMPLEMENTED_INTRINSIC(MathLog)
+UNIMPLEMENTED_INTRINSIC(MathLog10)
+UNIMPLEMENTED_INTRINSIC(MathNextAfter)
+UNIMPLEMENTED_INTRINSIC(MathSinh)
+UNIMPLEMENTED_INTRINSIC(MathTan)
+UNIMPLEMENTED_INTRINSIC(MathTanh)
+
#undef UNIMPLEMENTED_INTRINSIC
#undef __
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
index 8f1d5e1..96f43a0 100644
--- a/compiler/optimizing/intrinsics_list.h
+++ b/compiler/optimizing/intrinsics_list.h
@@ -51,6 +51,23 @@
V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache) \
V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache) \
V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathCos, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathSin, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathAcos, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathAsin, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathAtan, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathAtan2, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathCbrt, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathCosh, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathExp, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathExpm1, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathHypot, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathLog, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathLog10, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathSinh, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathTan, kStatic, kNeedsEnvironmentOrCache) \
+ V(MathTanh, kStatic, kNeedsEnvironmentOrCache) \
V(MathSqrt, kStatic, kNeedsEnvironmentOrCache) \
V(MathCeil, kStatic, kNeedsEnvironmentOrCache) \
V(MathFloor, kStatic, kNeedsEnvironmentOrCache) \
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 9ecce0e..06fab61 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -989,6 +989,23 @@
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
+UNIMPLEMENTED_INTRINSIC(MathCos)
+UNIMPLEMENTED_INTRINSIC(MathSin)
+UNIMPLEMENTED_INTRINSIC(MathAcos)
+UNIMPLEMENTED_INTRINSIC(MathAsin)
+UNIMPLEMENTED_INTRINSIC(MathAtan)
+UNIMPLEMENTED_INTRINSIC(MathAtan2)
+UNIMPLEMENTED_INTRINSIC(MathCbrt)
+UNIMPLEMENTED_INTRINSIC(MathCosh)
+UNIMPLEMENTED_INTRINSIC(MathExp)
+UNIMPLEMENTED_INTRINSIC(MathExpm1)
+UNIMPLEMENTED_INTRINSIC(MathHypot)
+UNIMPLEMENTED_INTRINSIC(MathLog)
+UNIMPLEMENTED_INTRINSIC(MathLog10)
+UNIMPLEMENTED_INTRINSIC(MathNextAfter)
+UNIMPLEMENTED_INTRINSIC(MathSinh)
+UNIMPLEMENTED_INTRINSIC(MathTan)
+UNIMPLEMENTED_INTRINSIC(MathTanh)
#undef UNIMPLEMENTED_INTRINSIC
#undef __
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 36e1b20..8aa7d9f 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1730,6 +1730,24 @@
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
+UNIMPLEMENTED_INTRINSIC(MathCos)
+UNIMPLEMENTED_INTRINSIC(MathSin)
+UNIMPLEMENTED_INTRINSIC(MathAcos)
+UNIMPLEMENTED_INTRINSIC(MathAsin)
+UNIMPLEMENTED_INTRINSIC(MathAtan)
+UNIMPLEMENTED_INTRINSIC(MathAtan2)
+UNIMPLEMENTED_INTRINSIC(MathCbrt)
+UNIMPLEMENTED_INTRINSIC(MathCosh)
+UNIMPLEMENTED_INTRINSIC(MathExp)
+UNIMPLEMENTED_INTRINSIC(MathExpm1)
+UNIMPLEMENTED_INTRINSIC(MathHypot)
+UNIMPLEMENTED_INTRINSIC(MathLog)
+UNIMPLEMENTED_INTRINSIC(MathLog10)
+UNIMPLEMENTED_INTRINSIC(MathNextAfter)
+UNIMPLEMENTED_INTRINSIC(MathSinh)
+UNIMPLEMENTED_INTRINSIC(MathTan)
+UNIMPLEMENTED_INTRINSIC(MathTanh)
+
#undef UNIMPLEMENTED_INTRINSIC
#undef __
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 5b67cde..422bb89 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -788,6 +788,195 @@
__ Bind(&done);
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena,
+ HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
+}
+
+static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86* codegen, QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ DCHECK(locations->WillCall());
+ DCHECK(invoke->IsInvokeStaticOrDirect());
+ X86Assembler* assembler = codegen->GetAssembler();
+
+ // We need some place to pass the parameters.
+ __ subl(ESP, Immediate(16));
+ __ cfi().AdjustCFAOffset(16);
+
+ // Pass the parameters at the bottom of the stack.
+ __ movsd(Address(ESP, 0), XMM0);
+
+ // If we have a second parameter, pass it next.
+ if (invoke->GetNumberOfArguments() == 2) {
+ __ movsd(Address(ESP, 8), XMM1);
+ }
+
+ // Now do the actual call.
+ __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(entry)));
+
+ // Extract the return value from the FP stack.
+ __ fstpl(Address(ESP, 0));
+ __ movsd(XMM0, Address(ESP, 0));
+
+ // And clean up the stack.
+ __ addl(ESP, Immediate(16));
+ __ cfi().AdjustCFAOffset(-16);
+
+ codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCos);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSin);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAcos);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAsin);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCbrt);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCosh);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExp);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExpm1);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog10);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSinh);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTan);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTanh);
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
+ HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathAtan2(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan2);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathHypot(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickHypot);
+}
+
+void IntrinsicLocationsBuilderX86::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
+}
+
void IntrinsicLocationsBuilderX86::VisitStringCharAt(HInvoke* invoke) {
// The inputs plus one temp.
LocationSummary* locations = new (arena_) LocationSummary(invoke,
@@ -2277,56 +2466,6 @@
GenTrailingZeros(assembler, invoke, /* is_long */ true);
}
-static void CreateRotateLocations(ArenaAllocator* arena, HInvoke* invoke) {
- LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- // The shift count needs to be in CL or a constant.
- locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, invoke->InputAt(1)));
- locations->SetOut(Location::SameAsFirstInput());
-}
-
-static void GenRotate(X86Assembler* assembler, HInvoke* invoke, bool is_left) {
- LocationSummary* locations = invoke->GetLocations();
- Register first_reg = locations->InAt(0).AsRegister<Register>();
- Location second = locations->InAt(1);
-
- if (second.IsRegister()) {
- Register second_reg = second.AsRegister<Register>();
- if (is_left) {
- __ roll(first_reg, second_reg);
- } else {
- __ rorl(first_reg, second_reg);
- }
- } else {
- Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
- if (is_left) {
- __ roll(first_reg, imm);
- } else {
- __ rorl(first_reg, imm);
- }
- }
-}
-
-void IntrinsicLocationsBuilderX86::VisitIntegerRotateLeft(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86::VisitIntegerRotateLeft(HInvoke* invoke) {
- X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_left */ true);
-}
-
-void IntrinsicLocationsBuilderX86::VisitIntegerRotateRight(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86::VisitIntegerRotateRight(HInvoke* invoke) {
- X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_left */ false);
-}
-
// Unimplemented intrinsics.
#define UNIMPLEMENTED_INTRINSIC(Name) \
@@ -2337,6 +2476,8 @@
UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
UNIMPLEMENTED_INTRINSIC(LongRotateRight)
UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopy)
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index ecd129f..ac9b245 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -703,6 +703,188 @@
__ Bind(&done);
}
+static void CreateFPToFPCallLocations(ArenaAllocator* arena,
+ HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
+
+ // We have to ensure that the native code doesn't clobber the XMM registers which are
+ // non-volatile for ART, but volatile for Native calls. This will ensure that they are
+ // saved in the prologue and properly restored.
+ for (auto fp_reg : non_volatile_xmm_regs) {
+ locations->AddTemp(Location::FpuRegisterLocation(fp_reg));
+ }
+}
+
+static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86_64* codegen,
+ QuickEntrypointEnum entry) {
+ LocationSummary* locations = invoke->GetLocations();
+ DCHECK(locations->WillCall());
+ DCHECK(invoke->IsInvokeStaticOrDirect());
+ X86_64Assembler* assembler = codegen->GetAssembler();
+
+ __ gs()->call(Address::Absolute(GetThreadOffset<kX86_64WordSize>(entry), true));
+ codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathCos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathCos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCos);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathSin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathSin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSin);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAcos(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAcos(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAcos);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAsin(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAsin(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAsin);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAtan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAtan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathCbrt(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathCbrt(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCbrt);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathCosh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathCosh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickCosh);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathExp(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathExp(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExp);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathExpm1(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathExpm1(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickExpm1);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathLog(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathLog(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathLog10(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathLog10(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickLog10);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathSinh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathSinh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickSinh);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathTan(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathTan(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTan);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathTanh(HInvoke* invoke) {
+ CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathTanh(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickTanh);
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
+ HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kCall,
+ kIntrinsified);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
+ locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(Location::FpuRegisterLocation(XMM0));
+
+ // We have to ensure that the native code doesn't clobber the XMM registers which are
+ // non-volatile for ART, but volatile for Native calls. This will ensure that they are
+ // saved in the prologue and properly restored.
+ for (auto fp_reg : non_volatile_xmm_regs) {
+ locations->AddTemp(Location::FpuRegisterLocation(fp_reg));
+ }
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathAtan2(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathAtan2(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickAtan2);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathHypot(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathHypot(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickHypot);
+}
+
+void IntrinsicLocationsBuilderX86_64::VisitMathNextAfter(HInvoke* invoke) {
+ CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorX86_64::VisitMathNextAfter(HInvoke* invoke) {
+ GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
+}
+
void IntrinsicLocationsBuilderX86_64::VisitStringCharAt(HInvoke* invoke) {
// The inputs plus one temp.
LocationSummary* locations = new (arena_) LocationSummary(invoke,
@@ -2295,92 +2477,6 @@
GenTrailingZeros(assembler, invoke, /* is_long */ true);
}
-static void CreateRotateLocations(ArenaAllocator* arena, HInvoke* invoke) {
- LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kNoCall,
- kIntrinsified);
- locations->SetInAt(0, Location::RequiresRegister());
- // The shift count needs to be in CL or a constant.
- locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, invoke->InputAt(1)));
- locations->SetOut(Location::SameAsFirstInput());
-}
-
-static void GenRotate(X86_64Assembler* assembler, HInvoke* invoke, bool is_long, bool is_left) {
- LocationSummary* locations = invoke->GetLocations();
- CpuRegister first_reg = locations->InAt(0).AsRegister<CpuRegister>();
- Location second = locations->InAt(1);
-
- if (is_long) {
- if (second.IsRegister()) {
- CpuRegister second_reg = second.AsRegister<CpuRegister>();
- if (is_left) {
- __ rolq(first_reg, second_reg);
- } else {
- __ rorq(first_reg, second_reg);
- }
- } else {
- Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue);
- if (is_left) {
- __ rolq(first_reg, imm);
- } else {
- __ rorq(first_reg, imm);
- }
- }
- } else {
- if (second.IsRegister()) {
- CpuRegister second_reg = second.AsRegister<CpuRegister>();
- if (is_left) {
- __ roll(first_reg, second_reg);
- } else {
- __ rorl(first_reg, second_reg);
- }
- } else {
- Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
- if (is_left) {
- __ roll(first_reg, imm);
- } else {
- __ rorl(first_reg, imm);
- }
- }
- }
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitIntegerRotateLeft(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitIntegerRotateLeft(HInvoke* invoke) {
- X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_long */ false, /* is_left */ true);
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitIntegerRotateRight(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitIntegerRotateRight(HInvoke* invoke) {
- X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_long */ false, /* is_left */ false);
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitLongRotateLeft(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitLongRotateLeft(HInvoke* invoke) {
- X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_long */ true, /* is_left */ true);
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitLongRotateRight(HInvoke* invoke) {
- CreateRotateLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitLongRotateRight(HInvoke* invoke) {
- X86_64Assembler* assembler = down_cast<X86_64Assembler*>(codegen_->GetAssembler());
- GenRotate(assembler, invoke, /* is_long */ true, /* is_left */ false);
-}
-
// Unimplemented intrinsics.
#define UNIMPLEMENTED_INTRINSIC(Name) \
@@ -2390,6 +2486,10 @@
}
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
#undef UNIMPLEMENTED_INTRINSIC
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 389ada7..adde004 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -335,16 +335,24 @@
return true;
}
- ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* ref) {
- ReferenceInfo* ref_info = FindReferenceInfoOf(ref);
+ ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* instruction) {
+ ReferenceInfo* ref_info = FindReferenceInfoOf(instruction);
if (ref_info == nullptr) {
size_t pos = ref_info_array_.size();
- ref_info = new (GetGraph()->GetArena()) ReferenceInfo(ref, pos);
+ ref_info = new (GetGraph()->GetArena()) ReferenceInfo(instruction, pos);
ref_info_array_.push_back(ref_info);
}
return ref_info;
}
+ void CreateReferenceInfoForReferenceType(HInstruction* instruction) {
+ if (instruction->GetType() != Primitive::kPrimNot) {
+ return;
+ }
+ DCHECK(FindReferenceInfoOf(instruction) == nullptr);
+ GetOrCreateReferenceInfo(instruction);
+ }
+
HeapLocation* GetOrCreateHeapLocation(HInstruction* ref,
size_t offset,
HInstruction* index,
@@ -378,6 +386,7 @@
void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE {
VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
+ CreateReferenceInfoForReferenceType(instruction);
}
void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
@@ -387,6 +396,7 @@
void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
+ CreateReferenceInfoForReferenceType(instruction);
}
void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE {
@@ -399,6 +409,7 @@
void VisitArrayGet(HArrayGet* instruction) OVERRIDE {
VisitArrayAccess(instruction->InputAt(0), instruction->InputAt(1));
+ CreateReferenceInfoForReferenceType(instruction);
}
void VisitArraySet(HArraySet* instruction) OVERRIDE {
@@ -408,7 +419,23 @@
void VisitNewInstance(HNewInstance* new_instance) OVERRIDE {
// Any references appearing in the ref_info_array_ so far cannot alias with new_instance.
- GetOrCreateReferenceInfo(new_instance);
+ CreateReferenceInfoForReferenceType(new_instance);
+ }
+
+ void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitInvokeVirtual(HInvokeVirtual* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitInvokeInterface(HInvokeInterface* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitParameterValue(HParameterValue* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
}
void VisitDeoptimize(HDeoptimize* instruction ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3e38e9f..1f8ef47 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1082,6 +1082,7 @@
M(Rem, BinaryOperation) \
M(Return, Instruction) \
M(ReturnVoid, Instruction) \
+ M(Ror, BinaryOperation) \
M(Shl, BinaryOperation) \
M(Shr, BinaryOperation) \
M(StaticFieldGet, Instruction) \
@@ -4198,6 +4199,44 @@
DISALLOW_COPY_AND_ASSIGN(HXor);
};
+class HRor : public HBinaryOperation {
+ public:
+ HRor(Primitive::Type result_type, HInstruction* value, HInstruction* distance)
+ : HBinaryOperation(result_type, value, distance) {}
+
+ template <typename T, typename U, typename V>
+ T Compute(T x, U y, V max_shift_value) const {
+ static_assert(std::is_same<V, typename std::make_unsigned<T>::type>::value,
+ "V is not the unsigned integer type corresponding to T");
+ V ux = static_cast<V>(x);
+ if ((y & max_shift_value) == 0) {
+ return static_cast<T>(ux);
+ } else {
+ const V reg_bits = sizeof(T) * 8;
+ return static_cast<T>(ux >> (y & max_shift_value)) |
+ (x << (reg_bits - (y & max_shift_value)));
+ }
+ }
+
+ HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
+ }
+ HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
+ }
+ HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
+ }
+
+ DECLARE_INSTRUCTION(Ror);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HRor);
+};
+
// The value of a parameter in this method. Its location depends on
// the calling convention.
class HParameterValue : public HExpression<0> {
@@ -4925,9 +4964,13 @@
class HLoadString : public HExpression<1> {
public:
- HLoadString(HCurrentMethod* current_method, uint32_t string_index, uint32_t dex_pc)
+ HLoadString(HCurrentMethod* current_method,
+ uint32_t string_index,
+ uint32_t dex_pc,
+ bool is_in_dex_cache)
: HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
- string_index_(string_index) {
+ string_index_(string_index),
+ is_in_dex_cache_(is_in_dex_cache) {
SetRawInputAt(0, current_method);
}
@@ -4945,6 +4988,7 @@
bool NeedsEnvironment() const OVERRIDE { return false; }
bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { return true; }
bool CanBeNull() const OVERRIDE { return false; }
+ bool IsInDexCache() const { return is_in_dex_cache_; }
static SideEffects SideEffectsForArchRuntimeCalls() {
return SideEffects::CanTriggerGC();
@@ -4954,6 +4998,7 @@
private:
const uint32_t string_index_;
+ const bool is_in_dex_cache_;
DISALLOW_COPY_AND_ASSIGN(HLoadString);
};
diff --git a/compiler/optimizing/nodes_arm64.h b/compiler/optimizing/nodes_arm64.h
index e843935..18405f2 100644
--- a/compiler/optimizing/nodes_arm64.h
+++ b/compiler/optimizing/nodes_arm64.h
@@ -17,6 +17,8 @@
#ifndef ART_COMPILER_OPTIMIZING_NODES_ARM64_H_
#define ART_COMPILER_OPTIMIZING_NODES_ARM64_H_
+#include "nodes.h"
+
namespace art {
class HArm64DataProcWithShifterOp : public HExpression<2> {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index d387726..9a18635 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1319,6 +1319,8 @@
fprintf(gOutFile, " extends=\"%s\"\n", tmp);
free(tmp);
}
+ fprintf(gOutFile, " interface=%s\n",
+ quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 68433c1..993f37f 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -229,6 +229,16 @@
LIBART_TARGET_LDFLAGS :=
LIBART_HOST_LDFLAGS :=
+# Keep the __jit_debug_register_code symbol as a unique symbol during ICF for architectures where
+# we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when
+# new jit code is generated. We don't want it to be called when a different function with the same
+# (empty) body is called.
+JIT_DEBUG_REGISTER_CODE_LDFLAGS := -Wl,--keep-unique,__jit_debug_register_code
+LIBART_TARGET_LDFLAGS_arm := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
+LIBART_TARGET_LDFLAGS_x86 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
+LIBART_TARGET_LDFLAGS_x86_64 := $(JIT_DEBUG_REGISTER_CODE_LDFLAGS)
+JIT_DEBUG_REGISTER_CODE_LDFLAGS :=
+
LIBART_TARGET_SRC_FILES := \
$(LIBART_COMMON_SRC_FILES) \
jdwp/jdwp_adb.cc \
@@ -450,6 +460,8 @@
ifeq ($$(art_target_or_host),target)
LOCAL_CFLAGS += $$(LIBART_TARGET_CFLAGS)
LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS)
+ $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
+ $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch))))
else #host
LOCAL_CFLAGS += $$(LIBART_HOST_CFLAGS)
LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS)
@@ -457,8 +469,6 @@
LOCAL_LDFLAGS += -static
endif
endif
- $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
- $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch))))
# Clang usage
ifeq ($$(art_target_or_host),target)
@@ -587,8 +597,14 @@
LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES :=
LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
-LIBART_TARGET_LDFLAGS :=
LIBART_HOST_LDFLAGS :=
+LIBART_TARGET_LDFLAGS :=
+LIBART_TARGET_LDFLAGS_arm :=
+LIBART_TARGET_LDFLAGS_arm64 :=
+LIBART_TARGET_LDFLAGS_x86 :=
+LIBART_TARGET_LDFLAGS_x86_64 :=
+LIBART_TARGET_LDFLAGS_mips :=
+LIBART_TARGET_LDFLAGS_mips64 :=
LIBART_TARGET_SRC_FILES :=
LIBART_TARGET_SRC_FILES_arm :=
LIBART_TARGET_SRC_FILES_arm64 :=
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index e200018..aca49cc 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -93,6 +93,25 @@
qpoints->pLockObject = art_quick_lock_object;
qpoints->pUnlockObject = art_quick_unlock_object;
+ // More math.
+ qpoints->pCos = cos;
+ qpoints->pSin = sin;
+ qpoints->pAcos = acos;
+ qpoints->pAsin = asin;
+ qpoints->pAtan = atan;
+ qpoints->pAtan2 = atan2;
+ qpoints->pCbrt = cbrt;
+ qpoints->pCosh = cosh;
+ qpoints->pExp = exp;
+ qpoints->pExpm1 = expm1;
+ qpoints->pHypot = hypot;
+ qpoints->pLog = log;
+ qpoints->pLog10 = log10;
+ qpoints->pNextAfter = nextafter;
+ qpoints->pSinh = sinh;
+ qpoints->pTan = tan;
+ qpoints->pTanh = tanh;
+
// Math
qpoints->pD2l = art_quick_d2l;
qpoints->pF2l = art_quick_f2l;
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index 2b38c9d..ebe6d40 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -98,6 +98,25 @@
qpoints->pLockObject = art_quick_lock_object;
qpoints->pUnlockObject = art_quick_unlock_object;
+ // More math.
+ qpoints->pCos = cos;
+ qpoints->pSin = sin;
+ qpoints->pAcos = acos;
+ qpoints->pAsin = asin;
+ qpoints->pAtan = atan;
+ qpoints->pAtan2 = atan2;
+ qpoints->pCbrt = cbrt;
+ qpoints->pCosh = cosh;
+ qpoints->pExp = exp;
+ qpoints->pExpm1 = expm1;
+ qpoints->pHypot = hypot;
+ qpoints->pLog = log;
+ qpoints->pLog10 = log10;
+ qpoints->pNextAfter = nextafter;
+ qpoints->pSinh = sinh;
+ qpoints->pTan = tan;
+ qpoints->pTanh = tanh;
+
// Math
qpoints->pD2l = art_d2l;
qpoints->pF2l = art_f2l;
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index b548dfb..29c8232 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -122,7 +122,7 @@
art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_pos.
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 151 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 168 * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
art::Thread::ThreadLocalPosOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_end.
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 440d696..727f4fc 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -2508,11 +2508,12 @@
method_access_flags);
return false;
}
- // Abstract methods must be in an abstract class or interface.
+ // Abstract methods should be in an abstract class or interface.
if ((class_access_flags & (kAccInterface | kAccAbstract)) == 0) {
- *error_msg = StringPrintf("Method %" PRIu32 " is abstract, but the declaring class "
- "is neither abstract nor an interface", method_index);
- return false;
+ LOG(WARNING) << "Method " << PrettyMethod(method_index, *dex_file_)
+ << " is abstract, but the declaring class is neither abstract nor an "
+ << "interface in dex file "
+ << dex_file_->GetLocation();
}
}
// Interfaces are special.
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index ee7b986..3eea723 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -86,6 +86,23 @@
V(CmpgFloat, int32_t, float, float) \
V(CmplDouble, int32_t, double, double) \
V(CmplFloat, int32_t, float, float) \
+ V(Cos, double, double) \
+ V(Sin, double, double) \
+ V(Acos, double, double) \
+ V(Asin, double, double) \
+ V(Atan, double, double) \
+ V(Atan2, double, double, double) \
+ V(Cbrt, double, double) \
+ V(Cosh, double, double) \
+ V(Exp, double, double) \
+ V(Expm1, double, double) \
+ V(Hypot, double, double, double) \
+ V(Log, double, double) \
+ V(Log10, double, double) \
+ V(NextAfter, double, double, double) \
+ V(Sinh, double, double) \
+ V(Tan, double, double) \
+ V(Tanh, double, double) \
V(Fmod, double, double, double) \
V(L2d, double, int64_t) \
V(Fmodf, float, float, float) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 8587ede..391eb72 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -223,7 +223,24 @@
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgDouble, pCmpgFloat, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgFloat, pCmplDouble, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplDouble, pCmplFloat, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pFmod, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pCos, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCos, pSin, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSin, pAcos, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAcos, pAsin, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAsin, pAtan, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAtan, pAtan2, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAtan2, pCbrt, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCbrt, pCosh, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCosh, pExp, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pExp, pExpm1, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pExpm1, pHypot, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pHypot, pLog, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLog, pLog10, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLog10, pNextAfter, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pNextAfter, pSinh, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSinh, pTan, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTan, pTanh, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTanh, pFmod, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmod, pL2d, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2d, pFmodf, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmodf, pL2f, sizeof(void*));
diff --git a/runtime/oat.h b/runtime/oat.h
index a063b2b..5ed1977 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -31,7 +31,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '7', '3', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '7', '4', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index 837662d..6cea902 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -51,6 +51,23 @@
kIntrinsicMinMaxLong,
kIntrinsicMinMaxFloat,
kIntrinsicMinMaxDouble,
+ kIntrinsicCos,
+ kIntrinsicSin,
+ kIntrinsicAcos,
+ kIntrinsicAsin,
+ kIntrinsicAtan,
+ kIntrinsicAtan2,
+ kIntrinsicCbrt,
+ kIntrinsicCosh,
+ kIntrinsicExp,
+ kIntrinsicExpm1,
+ kIntrinsicHypot,
+ kIntrinsicLog,
+ kIntrinsicLog10,
+ kIntrinsicNextAfter,
+ kIntrinsicSinh,
+ kIntrinsicTan,
+ kIntrinsicTanh,
kIntrinsicSqrt,
kIntrinsicCeil,
kIntrinsicFloor,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7e5598b..bd481fd 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1293,6 +1293,11 @@
}
void Runtime::DumpForSigQuit(std::ostream& os) {
+ // Dumping for SIGQIT may cause deadlocks if the the debugger is active. b/26118154
+ if (Dbg::IsDebuggerActive()) {
+ LOG(INFO) << "Skipping DumpForSigQuit due to active debugger";
+ return;
+ }
GetClassLinker()->DumpForSigQuit(os);
GetInternTable()->DumpForSigQuit(os);
GetJavaVM()->DumpForSigQuit(os);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 90539b4..8a8c02f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2478,6 +2478,23 @@
QUICK_ENTRY_POINT_INFO(pCmpgFloat)
QUICK_ENTRY_POINT_INFO(pCmplDouble)
QUICK_ENTRY_POINT_INFO(pCmplFloat)
+ QUICK_ENTRY_POINT_INFO(pCos)
+ QUICK_ENTRY_POINT_INFO(pSin)
+ QUICK_ENTRY_POINT_INFO(pAcos)
+ QUICK_ENTRY_POINT_INFO(pAsin)
+ QUICK_ENTRY_POINT_INFO(pAtan)
+ QUICK_ENTRY_POINT_INFO(pAtan2)
+ QUICK_ENTRY_POINT_INFO(pCbrt)
+ QUICK_ENTRY_POINT_INFO(pCosh)
+ QUICK_ENTRY_POINT_INFO(pExp)
+ QUICK_ENTRY_POINT_INFO(pExpm1)
+ QUICK_ENTRY_POINT_INFO(pHypot)
+ QUICK_ENTRY_POINT_INFO(pLog)
+ QUICK_ENTRY_POINT_INFO(pLog10)
+ QUICK_ENTRY_POINT_INFO(pNextAfter)
+ QUICK_ENTRY_POINT_INFO(pSinh)
+ QUICK_ENTRY_POINT_INFO(pTan)
+ QUICK_ENTRY_POINT_INFO(pTanh)
QUICK_ENTRY_POINT_INFO(pFmod)
QUICK_ENTRY_POINT_INFO(pL2d)
QUICK_ENTRY_POINT_INFO(pFmodf)
diff --git a/test/123-inline-execute2/expected.txt b/test/123-inline-execute2/expected.txt
new file mode 100644
index 0000000..aa74fa3
--- /dev/null
+++ b/test/123-inline-execute2/expected.txt
@@ -0,0 +1,299 @@
+Math.sin(0.0) = 0.000000000000
+Math.sinh(0.0) = 0.000000000000
+Math.asin(0.0) = 0.000000000000
+Math.cos(0.0) = 1.000000000000
+Math.cosh(0.0) = 1.000000000000
+Math.acos(0.0) = 1.570796326795
+Math.tan(0.0) = 0.000000000000
+Math.tanh(0.0) = 0.000000000000
+Math.atan(0.0) = 0.000000000000
+Math.atan2(0.0, 1.0) = 0.000000000000
+Math.sin(0.7853981633974483) = 0.707106781187
+Math.sinh(0.7853981633974483) = 0.868670961486
+Math.asin(0.7853981633974483) = 0.903339110767
+Math.cos(0.7853981633974483) = 0.707106781187
+Math.cosh(0.7853981633974483) = 1.324609089252
+Math.acos(0.7853981633974483) = 0.667457216028
+Math.tan(0.7853981633974483) = 1.000000000000
+Math.tanh(0.7853981633974483) = 0.655794202633
+Math.atan(0.7853981633974483) = 0.665773750028
+Math.atan2(0.7853981633974483, 1.7853981633974483) = 0.414423800577
+Math.sin(1.5707963267948966) = 1.000000000000
+Math.sinh(1.5707963267948966) = 2.301298902307
+Math.asin(1.5707963267948966) = NaN
+Math.cos(1.5707963267948966) = 0.000000000000
+Math.cosh(1.5707963267948966) = 2.509178478658
+Math.acos(1.5707963267948966) = NaN
+Math.tanh(1.5707963267948966) = 0.917152335667
+Math.atan(1.5707963267948966) = 1.003884821854
+Math.atan2(1.5707963267948966, 2.5707963267948966) = 0.548479764417
+Math.sin(2.356194490192345) = 0.707106781187
+Math.sinh(2.356194490192345) = 5.227971924678
+Math.asin(2.356194490192345) = NaN
+Math.cos(2.356194490192345) = -0.707106781187
+Math.cosh(2.356194490192345) = 5.322752149520
+Math.acos(2.356194490192345) = NaN
+Math.tan(2.356194490192345) = -1.000000000000
+Math.tanh(2.356194490192345) = 0.982193380007
+Math.atan(2.356194490192345) = 1.169422824816
+Math.atan2(2.356194490192345, 3.356194490192345) = 0.612096117380
+Math.sin(3.141592653589793) = 0.000000000000
+Math.sinh(3.141592653589793) = 11.548739357258
+Math.asin(3.141592653589793) = NaN
+Math.cos(3.141592653589793) = -1.000000000000
+Math.cosh(3.141592653589793) = 11.591953275522
+Math.acos(3.141592653589793) = NaN
+Math.tan(3.141592653589793) = -0.000000000000
+Math.tanh(3.141592653589793) = 0.996272076221
+Math.atan(3.141592653589793) = 1.262627255679
+Math.atan2(3.141592653589793, 4.141592653589793) = 0.648948780815
+Math.sin(3.9269908169872414) = -0.707106781187
+Math.sinh(3.9269908169872414) = 25.367158319374
+Math.asin(3.9269908169872414) = NaN
+Math.cos(3.9269908169872414) = -0.707106781187
+Math.cosh(3.9269908169872414) = 25.386861192361
+Math.acos(3.9269908169872414) = NaN
+Math.tan(3.9269908169872414) = 1.000000000000
+Math.tanh(3.9269908169872414) = 0.999223894879
+Math.atan(3.9269908169872414) = 1.321447967784
+Math.atan2(3.9269908169872414, 4.926990816987241) = 0.672931229191
+Math.sin(4.71238898038469) = -1.000000000000
+Math.sinh(4.71238898038469) = 55.654397599418
+Math.asin(4.71238898038469) = NaN
+Math.cos(4.71238898038469) = -0.000000000000
+Math.cosh(4.71238898038469) = 55.663380890439
+Math.acos(4.71238898038469) = NaN
+Math.tanh(4.71238898038469) = 0.999838613989
+Math.atan(4.71238898038469) = 1.361691682971
+Math.atan2(4.71238898038469, 5.71238898038469) = 0.689765469251
+Math.sin(5.497787143782138) = -0.707106781187
+Math.sinh(5.497787143782138) = 122.073483514693
+Math.asin(5.497787143782138) = NaN
+Math.cos(5.497787143782138) = 0.707106781187
+Math.cosh(5.497787143782138) = 122.077579339582
+Math.acos(5.497787143782138) = NaN
+Math.tan(5.497787143782138) = -1.000000000000
+Math.tanh(5.497787143782138) = 0.999966449000
+Math.atan(5.497787143782138) = 1.390871988014
+Math.atan2(5.497787143782138, 6.497787143782138) = 0.702226398171
+Math.sin(6.283185307179586) = -0.000000000000
+Math.sinh(6.283185307179586) = 267.744894041016
+Math.asin(6.283185307179586) = NaN
+Math.cos(6.283185307179586) = 1.000000000000
+Math.cosh(6.283185307179586) = 267.746761483748
+Math.acos(6.283185307179586) = NaN
+Math.tan(6.283185307179586) = -0.000000000000
+Math.tanh(6.283185307179586) = 0.999993025340
+Math.atan(6.283185307179586) = 1.412965136507
+Math.atan2(6.283185307179586, 7.283185307179586) = 0.711819549590
+Math.cbrt(-3.0) = -1.442249570307
+Math.log(-3.0) = NaN
+Math.log10(-3.0) = NaN
+Math.log1p(-3.0) = NaN
+Math.exp(-3.0) = 0.049787068368
+Math.expm1(-3.0) = -0.950212931632
+Math.pow(-3.0, -2.0) = 0.111111111111
+Math.hypot(-3.0, -2.0) = 3.605551275464
+Math.cbrt(-2.0) = -1.259921049895
+Math.log(-2.0) = NaN
+Math.log10(-2.0) = NaN
+Math.log1p(-2.0) = NaN
+Math.exp(-2.0) = 0.135335283237
+Math.expm1(-2.0) = -0.864664716763
+Math.pow(-2.0, -1.0) = -0.500000000000
+Math.hypot(-2.0, -1.0) = 2.236067977500
+Math.cbrt(-1.0) = -1.000000000000
+Math.log(-1.0) = NaN
+Math.log10(-1.0) = NaN
+Math.log1p(-1.0) = -Infinity
+Math.exp(-1.0) = 0.367879441171
+Math.expm1(-1.0) = -0.632120558829
+Math.pow(-1.0, 0.0) = 1.000000000000
+Math.hypot(-1.0, 0.0) = 1.000000000000
+Math.cbrt(0.0) = 0.000000000000
+Math.log(0.0) = -Infinity
+Math.log10(0.0) = -Infinity
+Math.log1p(0.0) = 0.000000000000
+Math.exp(0.0) = 1.000000000000
+Math.expm1(0.0) = 0.000000000000
+Math.pow(0.0, 1.0) = 0.000000000000
+Math.hypot(0.0, 1.0) = 1.000000000000
+Math.cbrt(1.0) = 1.000000000000
+Math.log(1.0) = 0.000000000000
+Math.log10(1.0) = 0.000000000000
+Math.log1p(1.0) = 0.693147180560
+Math.exp(1.0) = 2.718281828459
+Math.expm1(1.0) = 1.718281828459
+Math.pow(1.0, 2.0) = 1.000000000000
+Math.hypot(1.0, 2.0) = 2.236067977500
+Math.cbrt(2.0) = 1.259921049895
+Math.log(2.0) = 0.693147180560
+Math.log10(2.0) = 0.301029995664
+Math.log1p(2.0) = 1.098612288668
+Math.exp(2.0) = 7.389056098931
+Math.expm1(2.0) = 6.389056098931
+Math.pow(2.0, 3.0) = 8.000000000000
+Math.hypot(2.0, 3.0) = 3.605551275464
+Math.cbrt(3.0) = 1.442249570307
+Math.log(3.0) = 1.098612288668
+Math.log10(3.0) = 0.477121254720
+Math.log1p(3.0) = 1.386294361120
+Math.exp(3.0) = 20.085536923188
+Math.expm1(3.0) = 19.085536923188
+Math.pow(3.0, 4.0) = 81.000000000000
+Math.hypot(3.0, 4.0) = 5.000000000000
+Math.ceil(0.0001) = 1.000000000000
+Math.floor(0.0001) = 0.000000000000
+Math.nextAfter(1.0, 2.0) = 1.000000000000
+Math.nextAfter(2.0, 1.0) = 2.000000000000
+Math.rint(0.5000001) = 1.000000000000
+StrictMath.sin(0.0) = 0.0
+StrictMath.sinh(0.0) = 0.0
+StrictMath.asin(0.0) = 0.0
+StrictMath.cos(0.0) = 1.0
+StrictMath.cosh(0.0) = 1.0
+StrictMath.acos(0.0) = 1.5707963267948966
+StrictMath.tan(0.0) = 0.0
+StrictMath.tanh(0.0) = 0.0
+StrictMath.atan(0.0) = 0.0
+StrictMath.atan2(0.0, 1.0) = 0.0
+StrictMath.sin(0.7853981633974483) = 0.7071067811865475
+StrictMath.sinh(0.7853981633974483) = 0.8686709614860095
+StrictMath.asin(0.7853981633974483) = 0.9033391107665127
+StrictMath.cos(0.7853981633974483) = 0.7071067811865476
+StrictMath.cosh(0.7853981633974483) = 1.3246090892520057
+StrictMath.acos(0.7853981633974483) = 0.6674572160283838
+StrictMath.tan(0.7853981633974483) = 0.9999999999999999
+StrictMath.tanh(0.7853981633974483) = 0.6557942026326724
+StrictMath.atan(0.7853981633974483) = 0.6657737500283538
+StrictMath.atan2(0.7853981633974483, 1.7853981633974483) = 0.41442380057704103
+StrictMath.sin(1.5707963267948966) = 1.0
+StrictMath.sinh(1.5707963267948966) = 2.3012989023072947
+StrictMath.asin(1.5707963267948966) = NaN
+StrictMath.cos(1.5707963267948966) = 6.123233995736766E-17
+StrictMath.cosh(1.5707963267948966) = 2.5091784786580567
+StrictMath.acos(1.5707963267948966) = NaN
+StrictMath.tan(1.5707963267948966) = 1.633123935319537E16
+StrictMath.tanh(1.5707963267948966) = 0.9171523356672744
+StrictMath.atan(1.5707963267948966) = 1.0038848218538872
+StrictMath.atan2(1.5707963267948966, 2.5707963267948966) = 0.5484797644174059
+StrictMath.sin(2.356194490192345) = 0.7071067811865476
+StrictMath.sinh(2.356194490192345) = 5.227971924677803
+StrictMath.asin(2.356194490192345) = NaN
+StrictMath.cos(2.356194490192345) = -0.7071067811865475
+StrictMath.cosh(2.356194490192345) = 5.322752149519959
+StrictMath.acos(2.356194490192345) = NaN
+StrictMath.tan(2.356194490192345) = -1.0000000000000002
+StrictMath.tanh(2.356194490192345) = 0.9821933800072388
+StrictMath.atan(2.356194490192345) = 1.1694228248157563
+StrictMath.atan2(2.356194490192345, 3.356194490192345) = 0.6120961173796371
+StrictMath.sin(3.141592653589793) = 1.2246467991473532E-16
+StrictMath.sinh(3.141592653589793) = 11.548739357257748
+StrictMath.asin(3.141592653589793) = NaN
+StrictMath.cos(3.141592653589793) = -1.0
+StrictMath.cosh(3.141592653589793) = 11.591953275521519
+StrictMath.acos(3.141592653589793) = NaN
+StrictMath.tan(3.141592653589793) = -1.2246467991473532E-16
+StrictMath.tanh(3.141592653589793) = 0.99627207622075
+StrictMath.atan(3.141592653589793) = 1.2626272556789115
+StrictMath.atan2(3.141592653589793, 4.141592653589793) = 0.6489487808147751
+StrictMath.sin(3.9269908169872414) = -0.7071067811865475
+StrictMath.sinh(3.9269908169872414) = 25.367158319374152
+StrictMath.asin(3.9269908169872414) = NaN
+StrictMath.cos(3.9269908169872414) = -0.7071067811865477
+StrictMath.cosh(3.9269908169872414) = 25.386861192360772
+StrictMath.acos(3.9269908169872414) = NaN
+StrictMath.tan(3.9269908169872414) = 0.9999999999999997
+StrictMath.tanh(3.9269908169872414) = 0.9992238948786412
+StrictMath.atan(3.9269908169872414) = 1.3214479677837223
+StrictMath.atan2(3.9269908169872414, 4.926990816987241) = 0.6729312291908799
+StrictMath.sin(4.71238898038469) = -1.0
+StrictMath.sinh(4.71238898038469) = 55.65439759941754
+StrictMath.asin(4.71238898038469) = NaN
+StrictMath.cos(4.71238898038469) = -1.8369701987210297E-16
+StrictMath.cosh(4.71238898038469) = 55.66338089043867
+StrictMath.acos(4.71238898038469) = NaN
+StrictMath.tan(4.71238898038469) = 5.443746451065123E15
+StrictMath.tanh(4.71238898038469) = 0.9998386139886326
+StrictMath.atan(4.71238898038469) = 1.3616916829711636
+StrictMath.atan2(4.71238898038469, 5.71238898038469) = 0.6897654692509959
+StrictMath.sin(5.497787143782138) = -0.7071067811865477
+StrictMath.sinh(5.497787143782138) = 122.07348351469281
+StrictMath.asin(5.497787143782138) = NaN
+StrictMath.cos(5.497787143782138) = 0.7071067811865474
+StrictMath.cosh(5.497787143782138) = 122.07757933958217
+StrictMath.acos(5.497787143782138) = NaN
+StrictMath.tan(5.497787143782138) = -1.0000000000000004
+StrictMath.tanh(5.497787143782138) = 0.9999664489997958
+StrictMath.atan(5.497787143782138) = 1.390871988014422
+StrictMath.atan2(5.497787143782138, 6.497787143782138) = 0.7022263981709682
+StrictMath.sin(6.283185307179586) = -2.4492935982947064E-16
+StrictMath.sinh(6.283185307179586) = 267.74489404101644
+StrictMath.asin(6.283185307179586) = NaN
+StrictMath.cos(6.283185307179586) = 1.0
+StrictMath.cosh(6.283185307179586) = 267.7467614837482
+StrictMath.acos(6.283185307179586) = NaN
+StrictMath.tan(6.283185307179586) = -2.4492935982947064E-16
+StrictMath.tanh(6.283185307179586) = 0.9999930253396107
+StrictMath.atan(6.283185307179586) = 1.4129651365067377
+StrictMath.atan2(6.283185307179586, 7.283185307179586) = 0.7118195495895945
+StrictMath.cbrt(-3.0) = -1.4422495703074083
+StrictMath.log(-3.0) = NaN
+StrictMath.log10(-3.0) = NaN
+StrictMath.log1p(-3.0) = NaN
+StrictMath.exp(-3.0) = 0.049787068367863944
+StrictMath.expm1(-3.0) = -0.950212931632136
+StrictMath.pow(-3.0, -2.0) = 0.1111111111111111
+StrictMath.hypot(-3.0, -2.0) = 3.605551275463989
+StrictMath.cbrt(-2.0) = -1.2599210498948732
+StrictMath.log(-2.0) = NaN
+StrictMath.log10(-2.0) = NaN
+StrictMath.log1p(-2.0) = NaN
+StrictMath.exp(-2.0) = 0.1353352832366127
+StrictMath.expm1(-2.0) = -0.8646647167633873
+StrictMath.pow(-2.0, -1.0) = -0.5
+StrictMath.hypot(-2.0, -1.0) = 2.23606797749979
+StrictMath.cbrt(-1.0) = -1.0
+StrictMath.log(-1.0) = NaN
+StrictMath.log10(-1.0) = NaN
+StrictMath.log1p(-1.0) = -Infinity
+StrictMath.exp(-1.0) = 0.36787944117144233
+StrictMath.expm1(-1.0) = -0.6321205588285577
+StrictMath.pow(-1.0, 0.0) = 1.0
+StrictMath.hypot(-1.0, 0.0) = 1.0
+StrictMath.cbrt(0.0) = 0.0
+StrictMath.log(0.0) = -Infinity
+StrictMath.log10(0.0) = -Infinity
+StrictMath.log1p(0.0) = 0.0
+StrictMath.exp(0.0) = 1.0
+StrictMath.expm1(0.0) = 0.0
+StrictMath.pow(0.0, 1.0) = 0.0
+StrictMath.hypot(0.0, 1.0) = 1.0
+StrictMath.cbrt(1.0) = 1.0
+StrictMath.log(1.0) = 0.0
+StrictMath.log10(1.0) = 0.0
+StrictMath.log1p(1.0) = 0.6931471805599453
+StrictMath.exp(1.0) = 2.7182818284590455
+StrictMath.expm1(1.0) = 1.718281828459045
+StrictMath.pow(1.0, 2.0) = 1.0
+StrictMath.hypot(1.0, 2.0) = 2.23606797749979
+StrictMath.cbrt(2.0) = 1.2599210498948732
+StrictMath.log(2.0) = 0.6931471805599453
+StrictMath.log10(2.0) = 0.3010299956639812
+StrictMath.log1p(2.0) = 1.0986122886681096
+StrictMath.exp(2.0) = 7.38905609893065
+StrictMath.expm1(2.0) = 6.38905609893065
+StrictMath.pow(2.0, 3.0) = 8.0
+StrictMath.hypot(2.0, 3.0) = 3.605551275463989
+StrictMath.cbrt(3.0) = 1.4422495703074083
+StrictMath.log(3.0) = 1.0986122886681096
+StrictMath.log10(3.0) = 0.47712125471966244
+StrictMath.log1p(3.0) = 1.3862943611198906
+StrictMath.exp(3.0) = 20.085536923187668
+StrictMath.expm1(3.0) = 19.085536923187668
+StrictMath.pow(3.0, 4.0) = 81.0
+StrictMath.hypot(3.0, 4.0) = 5.0
+StrictMath.ceil(0.0001) = 1.0
+StrictMath.floor(0.0001) = 0.0
+StrictMath.nextAfter(1.0, 2.0) = 1.0000000000000002
+StrictMath.rint(0.5000001) = 1.0
diff --git a/test/123-inline-execute2/info.txt b/test/123-inline-execute2/info.txt
new file mode 100644
index 0000000..4a728a7
--- /dev/null
+++ b/test/123-inline-execute2/info.txt
@@ -0,0 +1 @@
+Sanity checks for added InlineNative methods.
diff --git a/test/123-inline-execute2/src/Main.java b/test/123-inline-execute2/src/Main.java
new file mode 100644
index 0000000..9fadcfd
--- /dev/null
+++ b/test/123-inline-execute2/src/Main.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+import java.util.Locale;
+
+public class Main {
+ public static void main(String args[]) {
+ for (int i = 0; i <= 360; i += 45) {
+ double d = i * (Math.PI / 180.0);
+ System.out.println("Math.sin(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.sin(d)));
+
+ System.out.println("Math.sinh(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.sinh(d)));
+ System.out.println("Math.asin(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.asin(d)));
+ System.out.println("Math.cos(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.cos(d)));
+ System.out.println("Math.cosh(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.cosh(d)));
+ System.out.println("Math.acos(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.acos(d)));
+ if ((i + 90) % 180 != 0) {
+ System.out.println("Math.tan(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.tan(d)));
+ }
+ System.out.println("Math.tanh(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.tanh(d)));
+ System.out.println("Math.atan(" + d + ") = "
+ + String.format(Locale.US, "%.12f", Math.atan(d)));
+ System.out.println("Math.atan2(" + d + ", " + (d + 1.0) + ") = "
+ + String.format(Locale.US, "%.12f", Math.atan2(d, d + 1.0)));
+ }
+
+ for (int j = -3; j <= 3; j++) {
+ double e = (double) j;
+ System.out.println("Math.cbrt(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.cbrt(e)));
+ System.out.println("Math.log(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.log(e)));
+ System.out.println("Math.log10(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.log10(e)));
+ System.out.println("Math.log1p(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.log1p(e)));
+ System.out.println("Math.exp(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.exp(e)));
+ System.out.println("Math.expm1(" + e + ") = "
+ + String.format(Locale.US, "%.12f", Math.expm1(e)));
+ System.out.println("Math.pow(" + e + ", " + (e + 1.0) + ") = "
+ + String.format(Locale.US, "%.12f", Math.pow(e, e + 1.0)));
+ System.out.println("Math.hypot(" + e + ", " + (e + 1.0) + ") = "
+ + String.format(Locale.US, "%.12f", Math.hypot(e, e + 1.0)));
+ }
+
+ System.out.println("Math.ceil(0.0001) = "
+ + String.format(Locale.US, "%.12f", Math.ceil(0.0001)));
+ System.out.println("Math.floor(0.0001) = "
+ + String.format(Locale.US, "%.12f", Math.floor(0.0001)));
+ System.out.println("Math.nextAfter(1.0, 2.0) = "
+ + String.format(Locale.US, "%.12f", Math.nextAfter(1.0, 2.0)));
+ System.out.println("Math.nextAfter(2.0, 1.0) = "
+ + String.format(Locale.US, "%.12f", Math.nextAfter(2.0, 1.0)));
+ System.out.println("Math.rint(0.5000001) = "
+ + String.format(Locale.US, "%.12f", Math.rint(0.5000001)));
+
+ for (int i = 0; i <= 360; i += 45) {
+ double d = i * (StrictMath.PI / 180.0);
+ System.out.println("StrictMath.sin(" + d + ") = " + StrictMath.sin(d));
+ System.out.println("StrictMath.sinh(" + d + ") = " + StrictMath.sinh(d));
+ System.out.println("StrictMath.asin(" + d + ") = " + StrictMath.asin(d));
+ System.out.println("StrictMath.cos(" + d + ") = " + StrictMath.cos(d));
+ System.out.println("StrictMath.cosh(" + d + ") = " + StrictMath.cosh(d));
+ System.out.println("StrictMath.acos(" + d + ") = " + StrictMath.acos(d));
+ System.out.println("StrictMath.tan(" + d + ") = " + StrictMath.tan(d));
+ System.out.println("StrictMath.tanh(" + d + ") = " + StrictMath.tanh(d));
+ System.out.println("StrictMath.atan(" + d + ") = " + StrictMath.atan(d));
+ System.out.println("StrictMath.atan2(" + d + ", " + (d + 1.0) + ") = "
+ + StrictMath.atan2(d, d + 1.0));
+ }
+
+ for (int j = -3; j <= 3; j++) {
+ double e = (double) j;
+ System.out.println("StrictMath.cbrt(" + e + ") = " + StrictMath.cbrt(e));
+ System.out.println("StrictMath.log(" + e + ") = " + StrictMath.log(e));
+ System.out.println("StrictMath.log10(" + e + ") = " + StrictMath.log10(e));
+ System.out.println("StrictMath.log1p(" + e + ") = " + StrictMath.log1p(e));
+ System.out.println("StrictMath.exp(" + e + ") = " + StrictMath.exp(e));
+ System.out.println("StrictMath.expm1(" + e + ") = " + StrictMath.expm1(e));
+ System.out.println("StrictMath.pow(" + e + ", " + (e + 1.0) + ") = "
+ + StrictMath.pow(e, e + 1.0));
+ System.out.println("StrictMath.hypot(" + e + ", " + (e + 1.0) + ") = "
+ + StrictMath.hypot(e, e + 1.0));
+ }
+
+ System.out.println("StrictMath.ceil(0.0001) = " + StrictMath.ceil(0.0001));
+ System.out.println("StrictMath.floor(0.0001) = " + StrictMath.floor(0.0001));
+ System.out.println("StrictMath.nextAfter(1.0, 2.0) = " + StrictMath.nextAfter(1.0, 2.0));
+ System.out.println("StrictMath.rint(0.5000001) = " + StrictMath.rint(0.5000001));
+ }
+
+}
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 17e88ce..98251e4 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -25,6 +25,9 @@
}
class TestClass {
+ static {
+ sTestClassObj = new TestClass(-1, -2);
+ }
TestClass() {
}
TestClass(int i, int j) {
@@ -37,6 +40,7 @@
TestClass next;
String str;
static int si;
+ static TestClass sTestClassObj;
}
class SubTestClass extends TestClass {
@@ -115,10 +119,11 @@
}
/// CHECK-START: int Main.test3(TestClass) load_store_elimination (before)
- /// CHECK: InstanceFieldSet
- /// CHECK: InstanceFieldGet
- /// CHECK: InstanceFieldSet
/// CHECK: NewInstance
+ /// CHECK: StaticFieldGet
+ /// CHECK: NewInstance
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
/// CHECK: InstanceFieldSet
/// CHECK: InstanceFieldSet
/// CHECK: InstanceFieldGet
@@ -127,24 +132,31 @@
/// CHECK: InstanceFieldGet
/// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
- /// CHECK: InstanceFieldSet
- /// CHECK: InstanceFieldGet
- /// CHECK: InstanceFieldSet
/// CHECK: NewInstance
- /// CHECK-NOT: InstanceFieldSet
+ /// CHECK: StaticFieldGet
+ /// CHECK: NewInstance
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
/// CHECK-NOT: InstanceFieldGet
+ /// CHECK-NOT: StaticFieldGet
- // A new allocation shouldn't alias with pre-existing values.
+ // A new allocation (even non-singleton) shouldn't alias with pre-existing values.
static int test3(TestClass obj) {
// Do an allocation here to avoid the HLoadClass and HClinitCheck
// at the second allocation.
new TestClass();
+ TestClass obj1 = TestClass.sTestClassObj;
+ TestClass obj2 = new TestClass(); // Cannot alias with obj or obj1 which pre-exist.
+ obj.next = obj2; // Make obj2 a non-singleton.
+ // All stores below need to stay since obj/obj1/obj2 are not singletons.
obj.i = 1;
- obj.next.j = 2;
- TestClass obj2 = new TestClass();
+ obj1.j = 2;
+ // Following stores won't kill values of obj.i and obj1.j.
obj2.i = 3;
obj2.j = 4;
- return obj.i + obj.next.j + obj2.i + obj2.j;
+ return obj.i + obj1.j + obj2.i + obj2.j;
}
/// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before)
diff --git a/test/541-checker-instruction-simplifier-rotate/expected.txt b/test/541-checker-instruction-simplifier-rotate/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/541-checker-instruction-simplifier-rotate/expected.txt
diff --git a/test/541-checker-instruction-simplifier-rotate/info.txt b/test/541-checker-instruction-simplifier-rotate/info.txt
new file mode 100644
index 0000000..f9a86f8
--- /dev/null
+++ b/test/541-checker-instruction-simplifier-rotate/info.txt
@@ -0,0 +1 @@
+Tests simplification of bitfield rotate patterns in optimizing compiler.
diff --git a/test/541-checker-instruction-simplifier-rotate/src/Main.java b/test/541-checker-instruction-simplifier-rotate/src/Main.java
new file mode 100644
index 0000000..027f262
--- /dev/null
+++ b/test/541-checker-instruction-simplifier-rotate/src/Main.java
@@ -0,0 +1,659 @@
+/*
+ * 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.
+ */
+
+public class Main {
+
+ public static void assertIntEquals(int expected, int actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ public static void assertLongEquals(long expected, long actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ /// CHECK-START: int Main.rotateIntegerRight(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Invoke:i\d+>> InvokeStaticOrDirect intrinsic:IntegerRotateRight
+
+ /// CHECK-START: int Main.rotateIntegerRight(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.rotateIntegerRight(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: LoadClass
+ /// CHECK-NOT: ClinitCheck
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static int rotateIntegerRight(int value, int distance) {
+ return java.lang.Integer.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: int Main.rotateIntegerLeft(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Invoke:i\d+>> InvokeStaticOrDirect intrinsic:IntegerRotateLeft
+
+ /// CHECK-START: int Main.rotateIntegerLeft(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.rotateIntegerLeft(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: LoadClass
+ /// CHECK-NOT: ClinitCheck
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static int rotateIntegerLeft(int value, int distance) {
+ return java.lang.Integer.rotateLeft(value, distance);
+ }
+
+ /// CHECK-START: long Main.rotateLongRight(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Invoke:j\d+>> InvokeStaticOrDirect intrinsic:LongRotateRight
+
+ /// CHECK-START: long Main.rotateLongRight(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rotateLongRight(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: LoadClass
+ /// CHECK-NOT: ClinitCheck
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static long rotateLongRight(long value, int distance) {
+ return java.lang.Long.rotateRight(value, distance);
+ }
+
+ /// CHECK-START: long Main.rotateLongLeft(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Invoke:j\d+>> InvokeStaticOrDirect intrinsic:LongRotateLeft
+
+ /// CHECK-START: long Main.rotateLongLeft(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rotateLongLeft(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: LoadClass
+ /// CHECK-NOT: ClinitCheck
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static long rotateLongLeft(long value, int distance) {
+ return java.lang.Long.rotateLeft(value, distance);
+ }
+
+ // (i >>> #distance) | (i << #(reg_bits - distance))
+
+ /// CHECK-START: int Main.ror_int_constant_c_c(int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Const30:i\d+>> IntConstant 30
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<Const2>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Const30>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.ror_int_constant_c_c(int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Const2>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_constant_c_c(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_constant_c_c(int value) {
+ return (value >>> 2) | (value << 30);
+ }
+
+ /// CHECK-START: int Main.ror_int_constant_c_c_0(int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Const2>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_constant_c_c_0(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_constant_c_c_0(int value) {
+ return (value >>> 2) | (value << 62);
+ }
+
+ // (j >>> #distance) | (j << #(reg_bits - distance))
+
+ /// CHECK-START: long Main.ror_long_constant_c_c(long) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Const62:i\d+>> IntConstant 62
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Const2>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<Const62>>]
+ /// CHECK: <<Or:j\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.ror_long_constant_c_c(long) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Const2>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.ror_long_constant_c_c(long) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static long ror_long_constant_c_c(long value) {
+ return (value >>> 2) | (value << 62);
+ }
+
+ /// CHECK-START: long Main.ror_long_constant_c_c_0(long) instruction_simplifier (after)
+ /// CHECK-NOT: Ror
+ public static long ror_long_constant_c_c_0(long value) {
+ return (value >>> 2) | (value << 30);
+ }
+
+ // (i >>> #distance) | (i << #-distance)
+
+ /// CHECK-START: int Main.ror_int_constant_c_negc(int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<ConstNeg2:i\d+>> IntConstant -2
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<Const2>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<ConstNeg2>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.ror_int_constant_c_negc(int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Const2>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_constant_c_negc(int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_constant_c_negc(int value) {
+ return (value >>> 2) | (value << -2);
+ }
+
+ // (j >>> #distance) | (j << #-distance)
+
+ /// CHECK-START: long Main.ror_long_constant_c_negc(long) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<ConstNeg2:i\d+>> IntConstant -2
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Const2>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<ConstNeg2>>]
+ /// CHECK: <<Or:j\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.ror_long_constant_c_negc(long) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Const2>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.ror_long_constant_c_negc(long) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static long ror_long_constant_c_negc(long value) {
+ return (value >>> 2) | (value << -2);
+ }
+
+ // (i >>> distance) | (i << (#reg_bits - distance)
+
+ /// CHECK-START: int Main.ror_int_reg_v_csubv(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const32>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Sub>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_csubv(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_csubv(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Sub
+ public static int ror_int_reg_v_csubv(int value, int distance) {
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ // (distance = x - y)
+ // (i >>> distance) | (i << (#reg_bits - distance)
+
+ /// CHECK-START: int Main.ror_int_subv_csubv(int, int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK-DAG: <<Sub32:i\d+>> Sub [<<Const32>>,<<SubDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Sub32>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<SubDistance>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.ror_int_subv_csubv(int, int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<SubDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_subv_csubv(int, int, int) instruction_simplifier (after)
+ /// CHECK: Sub
+ /// CHECK-NOT: Sub
+
+ /// CHECK-START: int Main.ror_int_subv_csubv(int, int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_subv_csubv(int value, int x, int y) {
+ int distance = x - y;
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ /// CHECK-START: int Main.ror_int_subv_csubv_env(int, int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK-DAG: <<Sub32:i\d+>> Sub [<<Const32>>,<<SubDistance>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<SubDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Sub32>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: <<Add:i\d+>> Add [<<Or>>,<<Sub32>>]
+ /// CHECK: Return [<<Add>>]
+
+ /// CHECK-START: int Main.ror_int_subv_csubv_env(int, int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK-DAG: <<Sub32:i\d+>> Sub [<<Const32>>,<<SubDistance>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<SubDistance>>]
+ /// CHECK: <<Add:i\d+>> Add [<<Ror>>,<<Sub32>>]
+ /// CHECK: Return [<<Add>>]
+
+ /// CHECK-START: int Main.ror_int_subv_csubv_env(int, int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_subv_csubv_env(int value, int x, int y) {
+ int distance = x - y;
+ int bits_minus_dist = 32 - distance;
+ return ((value >>> distance) | (value << bits_minus_dist)) + bits_minus_dist;
+ }
+
+ // (j >>> distance) | (j << (#reg_bits - distance)
+
+ /// CHECK-START: long Main.ror_long_reg_v_csubv(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const64:i\d+>> IntConstant 64
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const64>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<Sub>>]
+ /// CHECK: <<Or:j\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.ror_long_reg_v_csubv(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.ror_long_reg_v_csubv(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Sub
+ public static long ror_long_reg_v_csubv(long value, int distance) {
+ return (value >>> distance) | (value << (64 - distance));
+ }
+
+ /// CHECK-START: long Main.ror_long_reg_v_csubv_0(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: Ror
+ public static long ror_long_reg_v_csubv_0(long value, int distance) {
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ /// CHECK-START: long Main.ror_long_subv_csubv_0(long, int, int) instruction_simplifier (after)
+ /// CHECK-NOT: Ror
+ public static long ror_long_subv_csubv_0(long value, int x, int y) {
+ int distance = x - y;
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ // (i >>> (#reg_bits - distance)) | (i << distance)
+
+ /// CHECK-START: int Main.rol_int_reg_csubv_v(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const32>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<Sub>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.rol_int_reg_csubv_v(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK: <<Sub:i\d+>> Sub [<<Const32>>,<<ArgDistance>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Sub>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.rol_int_reg_csubv_v(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int rol_int_reg_csubv_v(int value, int distance) {
+ return (value >>> (32 - distance)) | (value << distance);
+ }
+
+ // (distance = x - y)
+ // (i >>> (#reg_bits - distance)) | (i << distance)
+
+ /// CHECK-START: int Main.rol_int_csubv_subv(int, int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK-DAG: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK-DAG: <<Sub32:i\d+>> Sub [<<Const32>>,<<SubDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<SubDistance>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<Sub32>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.rol_int_csubv_subv(int, int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgX:i\d+>> ParameterValue
+ /// CHECK: <<ArgY:i\d+>> ParameterValue
+ /// CHECK: <<Const32:i\d+>> IntConstant 32
+ /// CHECK: <<SubDistance:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ /// CHECK: <<Sub:i\d+>> Sub [<<Const32>>,<<SubDistance>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Sub>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.rol_int_csubv_subv(int, int, int) instruction_simplifier (after)
+ /// CHECK: Sub
+ /// CHECK: Sub
+
+ /// CHECK-START: int Main.rol_int_csubv_subv(int, int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int rol_int_csubv_subv(int value, int x, int y) {
+ int distance = x - y;
+ return (value >>> (32 - distance)) | (value << distance);
+ }
+
+ // (j >>> (#reg_bits - distance)) | (j << distance)
+
+ /// CHECK-START: long Main.rol_long_reg_csubv_v(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const64:i\d+>> IntConstant 64
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const64>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Sub>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Or:j\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.rol_long_reg_csubv_v(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Const64:i\d+>> IntConstant 64
+ /// CHECK: <<Sub:i\d+>> Sub [<<Const64>>,<<ArgDistance>>]
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Sub>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rol_long_reg_csubv_v(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static long rol_long_reg_csubv_v(long value, int distance) {
+ return (value >>> (64 - distance)) | (value << distance);
+ }
+
+ /// CHECK-START: long Main.rol_long_reg_csubv_v_0(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: Ror
+ public static long rol_long_reg_csubv_v_0(long value, int distance) {
+ return (value >>> (32 - distance)) | (value << distance);
+ }
+
+ // (i >>> distance) | (i << -distance) (i.e. libcore's Integer.rotateRight)
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Neg>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Neg
+ public static int ror_int_reg_v_negv(int value, int distance) {
+ return (value >>> distance) | (value << -distance);
+ }
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv_env(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<Neg>>]
+ /// CHECK: <<Or:i\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: <<Add:i\d+>> Add [<<Or>>,<<Neg>>]
+ /// CHECK: Return [<<Add>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv_env(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Sub:i\d+>> Sub [<<Ror>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Sub>>]
+
+ /// CHECK-START: int Main.ror_int_reg_v_negv_env(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int ror_int_reg_v_negv_env(int value, int distance) {
+ int neg_distance = -distance;
+ return ((value >>> distance) | (value << neg_distance)) + neg_distance;
+ }
+
+ // (j >>> distance) | (j << -distance) (i.e. libcore's Long.rotateRight)
+
+ /// CHECK-START: long Main.ror_long_reg_v_negv(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<Neg>>]
+ /// CHECK: <<Or:j\d+>> Or [<<UShr>>,<<Shl>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.ror_long_reg_v_negv(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.ror_long_reg_v_negv(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: Neg
+ public static long ror_long_reg_v_negv(long value, int distance) {
+ return (value >>> distance) | (value << -distance);
+ }
+
+ // (i << distance) | (i >>> -distance) (i.e. libcore's Integer.rotateLeft)
+
+ /// CHECK-START: int Main.rol_int_reg_negv_v(int, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:i\d+>> UShr [<<ArgValue>>,<<Neg>>]
+ /// CHECK-DAG: <<Shl:i\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Or:i\d+>> Or [<<Shl>>,<<UShr>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: int Main.rol_int_reg_negv_v(int, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:i\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:i\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: int Main.rol_int_reg_negv_v(int, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static int rol_int_reg_negv_v(int value, int distance) {
+ return (value << distance) | (value >>> -distance);
+ }
+
+ // (j << distance) | (j >>> -distance) (i.e. libcore's Long.rotateLeft)
+
+ /// CHECK-START: long Main.rol_long_reg_negv_v(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Neg>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Or:j\d+>> Or [<<Shl>>,<<UShr>>]
+ /// CHECK: Return [<<Or>>]
+
+ /// CHECK-START: long Main.rol_long_reg_negv_v(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rol_long_reg_negv_v(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: UShr
+ /// CHECK-NOT: Shl
+ public static long rol_long_reg_negv_v(long value, int distance) {
+ return (value << distance) | (value >>> -distance);
+ }
+
+ // (j << distance) + (j >>> -distance)
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_add(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Neg>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Add:j\d+>> Add [<<Shl>>,<<UShr>>]
+ /// CHECK: Return [<<Add>>]
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_add(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_add(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: Add
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: UShr
+ public static long rol_long_reg_v_negv_add(long value, int distance) {
+ return (value << distance) + (value >>> -distance);
+ }
+
+ // (j << distance) ^ (j >>> -distance)
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_xor(long, int) instruction_simplifier (before)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK-DAG: <<UShr:j\d+>> UShr [<<ArgValue>>,<<Neg>>]
+ /// CHECK-DAG: <<Shl:j\d+>> Shl [<<ArgValue>>,<<ArgDistance>>]
+ /// CHECK: <<Xor:j\d+>> Xor [<<Shl>>,<<UShr>>]
+ /// CHECK: Return [<<Xor>>]
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_xor(long, int) instruction_simplifier (after)
+ /// CHECK: <<ArgValue:j\d+>> ParameterValue
+ /// CHECK: <<ArgDistance:i\d+>> ParameterValue
+ /// CHECK: <<Neg:i\d+>> Neg [<<ArgDistance>>]
+ /// CHECK: <<Ror:j\d+>> Ror [<<ArgValue>>,<<Neg>>]
+ /// CHECK: Return [<<Ror>>]
+
+ /// CHECK-START: long Main.rol_long_reg_v_negv_xor(long, int) instruction_simplifier (after)
+ /// CHECK-NOT: Xor
+ /// CHECK-NOT: Shl
+ /// CHECK-NOT: UShr
+ public static long rol_long_reg_v_negv_xor(long value, int distance) {
+ return (value << distance) ^ (value >>> -distance);
+ }
+
+ public static void main(String[] args) {
+ assertIntEquals(2, ror_int_constant_c_c(8));
+ assertIntEquals(2, ror_int_constant_c_c_0(8));
+ assertLongEquals(2L, ror_long_constant_c_c(8L));
+
+ assertIntEquals(2, ror_int_constant_c_negc(8));
+ assertLongEquals(2L, ror_long_constant_c_negc(8L));
+
+ assertIntEquals(2, ror_int_reg_v_csubv(8, 2));
+ assertLongEquals(2L, ror_long_reg_v_csubv(8L, 2));
+
+ assertIntEquals(2, ror_int_subv_csubv(8, 2, 0));
+ assertIntEquals(32, ror_int_subv_csubv_env(8, 2, 0));
+ assertIntEquals(32, rol_int_csubv_subv(8, 2, 0));
+
+ assertIntEquals(32, rol_int_reg_csubv_v(8, 2));
+ assertLongEquals(32L, rol_long_reg_csubv_v(8L, 2));
+
+ assertIntEquals(2, ror_int_reg_v_negv(8, 2));
+ assertIntEquals(0, ror_int_reg_v_negv_env(8, 2));
+ assertLongEquals(2L, ror_long_reg_v_negv(8L, 2));
+
+ assertIntEquals(32, rol_int_reg_negv_v(8, 2));
+ assertLongEquals(32L, rol_long_reg_negv_v(8L, 2));
+
+ assertLongEquals(32L, rol_long_reg_v_negv_add(8L, 2));
+ assertLongEquals(32L, rol_long_reg_v_negv_xor(8L, 2));
+ }
+}
diff --git a/test/542-bitfield-rotates/expected.txt b/test/542-bitfield-rotates/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/542-bitfield-rotates/expected.txt
diff --git a/test/542-bitfield-rotates/info.txt b/test/542-bitfield-rotates/info.txt
new file mode 100644
index 0000000..961be3b
--- /dev/null
+++ b/test/542-bitfield-rotates/info.txt
@@ -0,0 +1 @@
+Tests bitfield rotate simplification in optimizing compiler.
diff --git a/test/542-bitfield-rotates/src/Main.java b/test/542-bitfield-rotates/src/Main.java
new file mode 100644
index 0000000..9ef5f93
--- /dev/null
+++ b/test/542-bitfield-rotates/src/Main.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+public class Main {
+
+ public static void assertIntEquals(int expected, int actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ public static void assertLongEquals(long expected, long actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ test_Integer_right_v_csubv();
+ test_Long_right_v_csubv();
+
+ test_Integer_right_constant_v();
+ test_Long_right_constant_v();
+
+ test_Integer_left_csubv_v();
+ test_Long_left_csubv_v();
+
+ test_Integer_right_v_negv();
+ test_Long_right_v_negv();
+
+ test_Integer_left_negv_v();
+ test_Long_left_negv_v();
+
+ test_Integer_left_constant_v();
+ test_Long_left_constant_v();
+ }
+
+ public static boolean doThrow = false;
+
+ public static int $noinline$rotate_int_right_reg_v_csubv(int value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ public static void test_Integer_right_v_csubv() throws Exception {
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, 0), 0x11);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, 1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, Integer.SIZE - 1), 0x22);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, Integer.SIZE + 1), 0x80000008);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, -1), 0x22);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, -(Integer.SIZE - 1)), 0x80000008);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, -Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x11, -(Integer.SIZE + 1)), 0x22);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_csubv(0x80000000, 1), 0x40000000);
+ }
+
+ public static long $noinline$rotate_long_right_reg_v_csubv(long value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> distance) | (value << (64 - distance));
+ }
+
+ public static void test_Long_right_v_csubv() throws Exception {
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, 0), 0x11);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, 1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, Long.SIZE - 1), 0x22);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, Long.SIZE + 1), 0x8000000000000008L);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, -1), 0x22);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, -(Long.SIZE - 1)), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, -Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x11, -(Long.SIZE + 1)), 0x22);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_csubv(0x8000000000000000L, 1), 0x4000000000000000L);
+ }
+
+ public static int $noinline$rotate_int_left_reg_csubv_v(int value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> (32 - distance)) | (value << distance);
+ }
+
+ public static void test_Integer_left_csubv_v() throws Exception {
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, 0), 0x11);
+
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, 1), 0x22);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, Integer.SIZE - 1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, Integer.SIZE + 1), 0x22);
+
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, -1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, -(Integer.SIZE - 1)), 0x22);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, -Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0x11, -(Integer.SIZE + 1)), 0x80000008);
+
+ assertIntEquals($noinline$rotate_int_left_reg_csubv_v(0xC0000000, 1), 0x80000001);
+ }
+
+ public static long $noinline$rotate_long_left_reg_csubv_v(long value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> (64 - distance)) | (value << distance);
+ }
+
+ public static void test_Long_left_csubv_v() throws Exception {
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, 0), 0x11);
+
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, 1), 0x22);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, Long.SIZE - 1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, Long.SIZE + 1), 0x22);
+
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, -1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, -(Long.SIZE - 1)), 0x22);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, -Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0x11, -(Long.SIZE + 1)), 0x8000000000000008L);
+
+ assertLongEquals($noinline$rotate_long_left_reg_csubv_v(0xC000000000000000L, 1), 0x8000000000000001L);
+ }
+
+ public static int $noinline$rotate_int_right_reg_v_negv(int value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> distance) | (value << -distance);
+ }
+
+ public static void test_Integer_right_v_negv() throws Exception {
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, 0), 0x11);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, 1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, Integer.SIZE - 1), 0x22);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, Integer.SIZE + 1), 0x80000008);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, -1), 0x22);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, -(Integer.SIZE - 1)), 0x80000008);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, -Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x11, -(Integer.SIZE + 1)), 0x22);
+
+ assertIntEquals($noinline$rotate_int_right_reg_v_negv(0x80000000, 1), 0x40000000);
+ }
+
+ public static long $noinline$rotate_long_right_reg_v_negv(long value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> distance) | (value << -distance);
+ }
+
+ public static void test_Long_right_v_negv() throws Exception {
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, 0), 0x11);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, 1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, Long.SIZE - 1), 0x22);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, Long.SIZE + 1), 0x8000000000000008L);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, -1), 0x22);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, -(Long.SIZE - 1)), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, -Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x11, -(Long.SIZE + 1)), 0x22);
+
+ assertLongEquals($noinline$rotate_long_right_reg_v_negv(0x8000000000000000L, 1), 0x4000000000000000L);
+ }
+
+ public static int $noinline$rotate_int_left_reg_negv_v(int value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> -distance) | (value << distance);
+ }
+
+ public static void test_Integer_left_negv_v() throws Exception {
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, 0), 0x11);
+
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, 1), 0x22);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, Integer.SIZE - 1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, Integer.SIZE + 1), 0x22);
+
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, -1), 0x80000008);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, -(Integer.SIZE - 1)), 0x22);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, -Integer.SIZE), 0x11);
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0x11, -(Integer.SIZE + 1)), 0x80000008);
+
+ assertIntEquals($noinline$rotate_int_left_reg_negv_v(0xC0000000, 1), 0x80000001);
+ }
+
+ public static long $noinline$rotate_long_left_reg_negv_v(long value, int distance) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> -distance) | (value << distance);
+ }
+
+ public static void test_Long_left_negv_v() throws Exception {
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, 0), 0x11);
+
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, 1), 0x22);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, Long.SIZE - 1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, Long.SIZE + 1), 0x22);
+
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, -1), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, -(Long.SIZE - 1)), 0x22);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, -Long.SIZE), 0x11);
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0x11, -(Long.SIZE + 1)), 0x8000000000000008L);
+
+ assertLongEquals($noinline$rotate_long_left_reg_negv_v(0xC000000000000000L, 1), 0x8000000000000001L);
+ }
+
+ public static int $noinline$rotate_int_right_constant_0(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 0) | (value << 0);
+ }
+
+ public static int $noinline$rotate_int_right_constant_1(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 1) | (value << -1);
+ }
+
+ public static int $noinline$rotate_int_right_constant_m1(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> -1) | (value << 1);
+ }
+
+ public static int $noinline$rotate_int_right_constant_16(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 16) | (value << -16);
+ }
+
+ public static void test_Integer_right_constant_v() throws Exception {
+ assertIntEquals($noinline$rotate_int_right_constant_0(0x11), 0x11);
+ assertIntEquals($noinline$rotate_int_right_constant_1(0x11), 0x80000008);
+ assertIntEquals($noinline$rotate_int_right_constant_m1(0x11), 0x22);
+ assertIntEquals($noinline$rotate_int_right_constant_16(0x11), 0x110000);
+ }
+
+ public static long $noinline$rotate_long_right_constant_0(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 0) | (value << 0);
+ }
+
+ public static long $noinline$rotate_long_right_constant_1(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 1) | (value << -1);
+ }
+
+ public static long $noinline$rotate_long_right_constant_m1(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> -1) | (value << 1);
+ }
+
+ public static long $noinline$rotate_long_right_constant_16(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 16) | (value << -16);
+ }
+
+ public static long $noinline$rotate_long_right_constant_32(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 32) | (value << -32);
+ }
+
+ public static long $noinline$rotate_long_right_constant_48(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 48) | (value << -48);
+ }
+
+ public static long $noinline$rotate_long_right_constant_64(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value >>> 64) | (value << -64);
+ }
+
+ public static void test_Long_right_constant_v() throws Exception {
+ assertLongEquals($noinline$rotate_long_right_constant_0(0x11), 0x11);
+ assertLongEquals($noinline$rotate_long_right_constant_1(0x11), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_right_constant_m1(0x11), 0x22);
+ assertLongEquals($noinline$rotate_long_right_constant_16(0x11), 0x11000000000000L);
+ assertLongEquals($noinline$rotate_long_right_constant_32(0x11), 0x1100000000L);
+ assertLongEquals($noinline$rotate_long_right_constant_48(0x11), 0x110000L);
+ }
+
+ public static int $noinline$rotate_int_left_constant_0(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 0) | (value >>> 0);
+ }
+
+ public static int $noinline$rotate_int_left_constant_1(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 1) | (value >>> -1);
+ }
+
+ public static int $noinline$rotate_int_left_constant_m1(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << -1) | (value >>> 1);
+ }
+
+ public static int $noinline$rotate_int_left_constant_16(int value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 16) | (value >>> -16);
+ }
+
+ public static void test_Integer_left_constant_v() throws Exception {
+ assertIntEquals($noinline$rotate_int_left_constant_0(0x11), 0x11);
+ assertIntEquals($noinline$rotate_int_left_constant_1(0x11), 0x22);
+ assertIntEquals($noinline$rotate_int_left_constant_m1(0x11), 0x80000008);
+ assertIntEquals($noinline$rotate_int_left_constant_16(0x11), 0x110000);
+ }
+
+ public static long $noinline$rotate_long_left_constant_0(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 0) | (value >>> 0);
+ }
+
+ public static long $noinline$rotate_long_left_constant_1(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 1) | (value >>> -1);
+ }
+
+ public static long $noinline$rotate_long_left_constant_m1(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << -1) | (value >>> 1);
+ }
+
+ public static long $noinline$rotate_long_left_constant_16(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 16) | (value >>> -16);
+ }
+
+ public static long $noinline$rotate_long_left_constant_32(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 32) | (value >>> -32);
+ }
+
+ public static long $noinline$rotate_long_left_constant_48(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 48) | (value >>> -48);
+ }
+
+ public static long $noinline$rotate_long_left_constant_64(long value) {
+ if (doThrow) {
+ throw new Error();
+ }
+ return (value << 64) | (value >>> -64);
+ }
+
+ public static void test_Long_left_constant_v() throws Exception {
+ assertLongEquals($noinline$rotate_long_left_constant_0(0x11), 0x11);
+ assertLongEquals($noinline$rotate_long_left_constant_1(0x11), 0x22);
+ assertLongEquals($noinline$rotate_long_left_constant_m1(0x11), 0x8000000000000008L);
+ assertLongEquals($noinline$rotate_long_left_constant_16(0x11), 0x110000L);
+ assertLongEquals($noinline$rotate_long_left_constant_32(0x11), 0x1100000000L);
+ assertLongEquals($noinline$rotate_long_left_constant_48(0x11), 0x11000000000000L);
+ }
+
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index ebefeea..27f5b5d 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -48,4 +48,5 @@
b/23502994 (check-cast)
b/25494456
b/21869691
+b/26143249
Done!
diff --git a/test/800-smali/smali/b_26143249.smali b/test/800-smali/smali/b_26143249.smali
new file mode 100644
index 0000000..aa69e84
--- /dev/null
+++ b/test/800-smali/smali/b_26143249.smali
@@ -0,0 +1,20 @@
+# Make sure we accept non-abstract classes with abstract members.
+
+.class public LB26143249;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+ .registers 1
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method public run()V
+ .registers 1
+ invoke-virtual {p0}, LB26143249;->abs()V
+ return-void
+.end method
+
+.method public abstract abs()V
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 3b62a46..cc3b0b4 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -141,6 +141,8 @@
null));
testCases.add(new TestCase("b/21869691", "B21869691A", "run", null,
new IncompatibleClassChangeError(), null));
+ testCases.add(new TestCase("b/26143249", "B26143249", "run", null,
+ new AbstractMethodError(), null));
}
public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0925d36..beaafd0 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -454,6 +454,7 @@
441-checker-inliner \
510-checker-try-catch \
536-checker-intrinsic-optimization \
+ 541-checker-instruction-simplifier-rotate \
ifeq (mips,$(TARGET_ARCH))
ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
@@ -466,6 +467,21 @@
TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS :=
+# Known broken tests for the mips64 optimizing compiler backend.
+TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS := \
+ 541-checker-instruction-simplifier-rotate \
+
+ifeq (mips64,$(TARGET_ARCH))
+ ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
+ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
+ optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+ $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), \
+ $(TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+ endif
+endif
+
+TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS :=
+
# Tests that should fail when the optimizing compiler compiles them non-debuggable.
TEST_ART_BROKEN_OPTIMIZING_NONDEBUGGABLE_RUN_TESTS := \
454-get-vreg \
diff --git a/test/dexdump/bytecodes.xml b/test/dexdump/bytecodes.xml
index 8e54dd3..d08c2e9 100755
--- a/test/dexdump/bytecodes.xml
+++ b/test/dexdump/bytecodes.xml
@@ -3,6 +3,7 @@
>
<class name="SuppressLint"
extends="java.lang.Object"
+ interface="true"
abstract="true"
static="false"
final="false"
@@ -23,6 +24,7 @@
</class>
<class name="TargetApi"
extends="java.lang.Object"
+ interface="true"
abstract="true"
static="false"
final="false"
@@ -46,6 +48,7 @@
>
<class name="BuildConfig"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="true"
@@ -70,6 +73,7 @@
</class>
<class name="R.attr"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="true"
@@ -85,6 +89,7 @@
</class>
<class name="R.drawable"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="true"
@@ -110,6 +115,7 @@
</class>
<class name="R"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="true"
@@ -125,6 +131,7 @@
</class>
<class name="Test"
extends="android.app.Activity"
+ interface="false"
abstract="false"
static="false"
final="false"
diff --git a/test/dexdump/checkers.xml b/test/dexdump/checkers.xml
index 232254f..4e56ea2 100755
--- a/test/dexdump/checkers.xml
+++ b/test/dexdump/checkers.xml
@@ -3,6 +3,7 @@
>
<class name="Checkers"
extends="android.app.Activity"
+ interface="false"
abstract="false"
static="false"
final="false"
@@ -112,6 +113,7 @@
</class>
<class name="CheckersView"
extends="android.view.View"
+ interface="false"
abstract="false"
static="false"
final="false"
@@ -331,6 +333,7 @@
</class>
<class name="a"
extends="java.lang.Thread"
+ interface="false"
abstract="false"
static="false"
final="true"
@@ -500,6 +503,7 @@
</class>
<class name="g"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="true"
diff --git a/test/dexdump/staticfields.xml b/test/dexdump/staticfields.xml
index 6cff71b..c906f0a 100644
--- a/test/dexdump/staticfields.xml
+++ b/test/dexdump/staticfields.xml
@@ -3,6 +3,7 @@
>
<class name="StaticFields"
extends="java.lang.Object"
+ interface="false"
abstract="false"
static="false"
final="false"