summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/debug/elf_debug_loc_writer.h27
-rw-r--r--compiler/optimizing/code_generator_mips.cc30
-rw-r--r--compiler/optimizing/code_generator_mips.h5
-rw-r--r--compiler/optimizing/code_generator_mips64.cc6
-rw-r--r--compiler/optimizing/code_generator_mips64.h2
-rw-r--r--compiler/optimizing/constant_folding.cc2
-rw-r--r--compiler/optimizing/graph_visualizer.cc7
-rw-r--r--compiler/optimizing/intrinsics_mips.cc228
-rw-r--r--compiler/optimizing/nodes.cc34
-rw-r--r--compiler/optimizing/nodes.h625
-rw-r--r--compiler/utils/mips/assembler_mips.cc20
-rw-r--r--compiler/utils/mips/assembler_mips.h4
-rw-r--r--compiler/utils/mips/assembler_mips_test.cc40
13 files changed, 811 insertions, 219 deletions
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index a19b36f9cc..8fd20aa428 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
#define ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+#include <cstring>
#include <map>
#include "arch/instruction_set.h"
@@ -172,11 +173,6 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
return;
}
- dwarf::Writer<> debug_loc(debug_loc_buffer);
- dwarf::Writer<> debug_ranges(debug_ranges_buffer);
- debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc.size());
- debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges.size());
-
std::vector<VariableLocation> variable_locations = GetVariableLocations(
method_info,
vreg,
@@ -185,6 +181,8 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
dex_pc_high);
// Write .debug_loc entries.
+ dwarf::Writer<> debug_loc(debug_loc_buffer);
+ const size_t debug_loc_offset = debug_loc.size();
const bool is64bit = Is64BitInstructionSet(isa);
std::vector<uint8_t> expr_buffer;
for (const VariableLocation& variable_location : variable_locations) {
@@ -271,6 +269,8 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
// Write .debug_ranges entries.
// This includes ranges where the variable is in scope but the location is not known.
+ dwarf::Writer<> debug_ranges(debug_ranges_buffer);
+ size_t debug_ranges_offset = debug_ranges.size();
for (size_t i = 0; i < variable_locations.size(); i++) {
uint32_t low_pc = variable_locations[i].low_pc;
uint32_t high_pc = variable_locations[i].high_pc;
@@ -294,6 +294,23 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
debug_ranges.PushUint32(0);
debug_ranges.PushUint32(0);
}
+
+ // Simple de-duplication - check whether this entry is same as the last one (or tail of it).
+ size_t debug_ranges_entry_size = debug_ranges.size() - debug_ranges_offset;
+ if (debug_ranges_offset >= debug_ranges_entry_size) {
+ size_t previous_offset = debug_ranges_offset - debug_ranges_entry_size;
+ if (memcmp(debug_ranges_buffer->data() + previous_offset,
+ debug_ranges_buffer->data() + debug_ranges_offset,
+ debug_ranges_entry_size) == 0) {
+ // Remove what we have just written and use the last entry instead.
+ debug_ranges_buffer->resize(debug_ranges_offset);
+ debug_ranges_offset = previous_offset;
+ }
+ }
+
+ // Write attributes to .debug_info.
+ debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc_offset);
+ debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges_offset);
}
} // namespace debug
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 3eda8639c1..c500ea4408 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2107,7 +2107,6 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
LocationSummary* locations = instruction->GetLocations();
Register res = locations->Out().AsRegister<Register>();
Primitive::Type in_type = instruction->InputAt(0)->GetType();
- bool gt_bias = instruction->IsGtBias();
bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
// 0 if: left == right
@@ -2141,6 +2140,7 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
}
case Primitive::kPrimFloat: {
+ bool gt_bias = instruction->IsGtBias();
FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
MipsLabel done;
@@ -2180,6 +2180,7 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
break;
}
case Primitive::kPrimDouble: {
+ bool gt_bias = instruction->IsGtBias();
FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
MipsLabel done;
@@ -3953,28 +3954,19 @@ void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDire
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
-void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
- if (TryGenerateIntrinsicCode(invoke, codegen_)) {
- return;
- }
-
+void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
LocationSummary* locations = invoke->GetLocations();
Location receiver = locations->InAt(0);
- Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
+ Register temp = temp_location.AsRegister<Register>();
size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsWordSize);
// temp = object->GetClass();
- if (receiver.IsStackSlot()) {
- __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
- __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
- } else {
- DCHECK(receiver.IsRegister());
- __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
- }
- codegen_->MaybeRecordImplicitNullCheck(invoke);
+ DCHECK(receiver.IsRegister());
+ __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
+ MaybeRecordImplicitNullCheck(invoke);
// temp = temp->GetMethodAt(method_offset);
__ LoadFromOffset(kLoadWord, temp, temp, method_offset);
// T9 = temp->GetEntryPoint();
@@ -3982,6 +3974,14 @@ void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
// T9();
__ Jalr(T9);
__ Nop();
+}
+
+void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+ if (TryGenerateIntrinsicCode(invoke, codegen_)) {
+ return;
+ }
+
+ codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 12964b0b6a..dd0641c7ca 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -353,10 +353,7 @@ class CodeGeneratorMIPS : public CodeGenerator {
MethodReference target_method) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
- void GenerateVirtualCall(HInvokeVirtual* invoke ATTRIBUTE_UNUSED,
- Location temp ATTRIBUTE_UNUSED) OVERRIDE {
- UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
- }
+ void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 119084e026..e3a44f1c96 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1727,7 +1727,6 @@ void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
LocationSummary* locations = instruction->GetLocations();
GpuRegister res = locations->Out().AsRegister<GpuRegister>();
Primitive::Type in_type = instruction->InputAt(0)->GetType();
- bool gt_bias = instruction->IsGtBias();
// 0 if: left == right
// 1 if: left > right
@@ -1769,7 +1768,7 @@ void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
__ CmpEqS(FTMP, lhs, rhs);
__ LoadConst32(res, 0);
__ Bc1nez(FTMP, &done);
- if (gt_bias) {
+ if (instruction->IsGtBias()) {
__ CmpLtS(FTMP, lhs, rhs);
__ LoadConst32(res, -1);
__ Bc1nez(FTMP, &done);
@@ -1791,7 +1790,7 @@ void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
__ CmpEqD(FTMP, lhs, rhs);
__ LoadConst32(res, 0);
__ Bc1nez(FTMP, &done);
- if (gt_bias) {
+ if (instruction->IsGtBias()) {
__ CmpLtD(FTMP, lhs, rhs);
__ LoadConst32(res, -1);
__ Bc1nez(FTMP, &done);
@@ -4258,4 +4257,3 @@ void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet*) {
} // namespace mips64
} // namespace art
-
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 1161253792..eb7315aa7a 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -349,7 +349,7 @@ class CodeGeneratorMIPS64 : public CodeGenerator {
void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
- UNIMPLEMENTED(FATAL);
+ UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64";
}
private:
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 57452cc076..014353d615 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -178,7 +178,7 @@ void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction
((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
(input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
// Replace code looking like
- // CMP{G,L} dst, src, NaN
+ // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
// with
// CONSTANT +1 (gt bias)
// or
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 4cf0eb1565..c0263e4e5b 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -384,6 +384,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
<< array_set->GetValueCanBeNull() << std::noboolalpha;
}
+ void VisitCompare(HCompare* compare) OVERRIDE {
+ ComparisonBias bias = compare->GetBias();
+ StartAttributeStream("bias") << (bias == ComparisonBias::kGtBias
+ ? "gt"
+ : (bias == ComparisonBias::kLtBias ? "lt" : "none"));
+ }
+
void VisitInvoke(HInvoke* invoke) OVERRIDE {
StartAttributeStream("dex_file_index") << invoke->GetDexMethodIndex();
StartAttributeStream("method_name") << PrettyMethod(
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 2294713a3e..5d6e8c280f 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -113,11 +113,10 @@ class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
if (invoke_->IsInvokeStaticOrDirect()) {
codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
Location::RegisterLocation(A0));
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
} else {
- UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
- UNREACHABLE();
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
}
+ codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
@@ -825,6 +824,220 @@ void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
GetAssembler());
}
+// byte libcore.io.Memory.peekByte(long address)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register out = invoke->GetLocations()->Out().AsRegister<Register>();
+
+ __ Lb(out, adr, 0);
+}
+
+// short libcore.io.Memory.peekShort(long address)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register out = invoke->GetLocations()->Out().AsRegister<Register>();
+
+ if (IsR6()) {
+ __ Lh(out, adr, 0);
+ } else if (IsR2OrNewer()) {
+ // Unlike for words, there are no lhl/lhr instructions to load
+ // unaligned halfwords so the code loads individual bytes, in case
+ // the address isn't halfword-aligned, and assembles them into a
+ // signed halfword.
+ __ Lb(AT, adr, 1); // This byte must be sign-extended.
+ __ Lb(out, adr, 0); // This byte can be either sign-extended, or
+ // zero-extended because the following
+ // instruction overwrites the sign bits.
+ __ Ins(out, AT, 8, 24);
+ } else {
+ __ Lbu(AT, adr, 0); // This byte must be zero-extended. If it's not
+ // the "or" instruction below will destroy the upper
+ // 24 bits of the final result.
+ __ Lb(out, adr, 1); // This byte must be sign-extended.
+ __ Sll(out, out, 8);
+ __ Or(out, out, AT);
+ }
+}
+
+// int libcore.io.Memory.peekInt(long address)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register out = invoke->GetLocations()->Out().AsRegister<Register>();
+
+ if (IsR6()) {
+ __ Lw(out, adr, 0);
+ } else {
+ __ Lwr(out, adr, 0);
+ __ Lwl(out, adr, 3);
+ }
+}
+
+// long libcore.io.Memory.peekLong(long address)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register out_lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
+ Register out_hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
+
+ if (IsR6()) {
+ __ Lw(out_lo, adr, 0);
+ __ Lw(out_hi, adr, 4);
+ } else {
+ __ Lwr(out_lo, adr, 0);
+ __ Lwl(out_lo, adr, 3);
+ __ Lwr(out_hi, adr, 4);
+ __ Lwl(out_hi, adr, 7);
+ }
+}
+
+static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
+ LocationSummary* locations = new (arena) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+}
+
+// void libcore.io.Memory.pokeByte(long address, byte value)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
+ CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
+
+ __ Sb(val, adr, 0);
+}
+
+// void libcore.io.Memory.pokeShort(long address, short value)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
+ CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
+
+ if (IsR6()) {
+ __ Sh(val, adr, 0);
+ } else {
+ // Unlike for words, there are no shl/shr instructions to store
+ // unaligned halfwords so the code stores individual bytes, in case
+ // the address isn't halfword-aligned.
+ __ Sb(val, adr, 0);
+ __ Srl(AT, val, 8);
+ __ Sb(AT, adr, 1);
+ }
+}
+
+// void libcore.io.Memory.pokeInt(long address, int value)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
+ CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
+
+ if (IsR6()) {
+ __ Sw(val, adr, 0);
+ } else {
+ __ Swr(val, adr, 0);
+ __ Swl(val, adr, 3);
+ }
+}
+
+// void libcore.io.Memory.pokeLong(long address, long value)
+void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
+ CreateIntIntToVoidLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
+ Register val_lo = invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>();
+ Register val_hi = invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>();
+
+ if (IsR6()) {
+ __ Sw(val_lo, adr, 0);
+ __ Sw(val_hi, adr, 4);
+ } else {
+ __ Swr(val_lo, adr, 0);
+ __ Swl(val_lo, adr, 3);
+ __ Swr(val_hi, adr, 4);
+ __ Swl(val_hi, adr, 7);
+ }
+}
+
+// char java.lang.String.charAt(int index)
+void IntrinsicLocationsBuilderMIPS::VisitStringCharAt(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kCallOnSlowPath,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitStringCharAt(HInvoke* invoke) {
+ LocationSummary* locations = invoke->GetLocations();
+ MipsAssembler* assembler = GetAssembler();
+
+ // Location of reference to data array
+ const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
+ // Location of count
+ const int32_t count_offset = mirror::String::CountOffset().Int32Value();
+
+ Register obj = locations->InAt(0).AsRegister<Register>();
+ Register idx = locations->InAt(1).AsRegister<Register>();
+ Register out = locations->Out().AsRegister<Register>();
+
+ // TODO: Maybe we can support range check elimination. Overall,
+ // though, I think it's not worth the cost.
+ // TODO: For simplicity, the index parameter is requested in a
+ // register, so different from Quick we will not optimize the
+ // code for constants (which would save a register).
+
+ SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ // Load the string size
+ __ Lw(TMP, obj, count_offset);
+ codegen_->MaybeRecordImplicitNullCheck(invoke);
+ // Revert to slow path if idx is too large, or negative
+ __ Bgeu(idx, TMP, slow_path->GetEntryLabel());
+
+ // out = obj[2*idx].
+ __ Sll(TMP, idx, 1); // idx * 2
+ __ Addu(TMP, TMP, obj); // Address of char at location idx
+ __ Lhu(out, TMP, value_offset); // Load char at location idx
+
+ __ Bind(slow_path->GetExitLabel());
+}
+
// boolean java.lang.String.equals(Object anObject)
void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
@@ -956,14 +1169,6 @@ UNIMPLEMENTED_INTRINSIC(MathFloor)
UNIMPLEMENTED_INTRINSIC(MathRint)
UNIMPLEMENTED_INTRINSIC(MathRoundDouble)
UNIMPLEMENTED_INTRINSIC(MathRoundFloat)
-UNIMPLEMENTED_INTRINSIC(MemoryPeekByte)
-UNIMPLEMENTED_INTRINSIC(MemoryPeekIntNative)
-UNIMPLEMENTED_INTRINSIC(MemoryPeekLongNative)
-UNIMPLEMENTED_INTRINSIC(MemoryPeekShortNative)
-UNIMPLEMENTED_INTRINSIC(MemoryPokeByte)
-UNIMPLEMENTED_INTRINSIC(MemoryPokeIntNative)
-UNIMPLEMENTED_INTRINSIC(MemoryPokeLongNative)
-UNIMPLEMENTED_INTRINSIC(MemoryPokeShortNative)
UNIMPLEMENTED_INTRINSIC(ThreadCurrentThread)
UNIMPLEMENTED_INTRINSIC(UnsafeGet)
UNIMPLEMENTED_INTRINSIC(UnsafeGetVolatile)
@@ -983,7 +1188,6 @@ UNIMPLEMENTED_INTRINSIC(UnsafePutLongVolatile)
UNIMPLEMENTED_INTRINSIC(UnsafeCASInt)
UNIMPLEMENTED_INTRINSIC(UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(UnsafeCASObject)
-UNIMPLEMENTED_INTRINSIC(StringCharAt)
UNIMPLEMENTED_INTRINSIC(StringCompareTo)
UNIMPLEMENTED_INTRINSIC(StringIndexOf)
UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter)
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 27015c0ac6..b26ce0aa13 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -15,6 +15,8 @@
*/
#include "nodes.h"
+#include <cfloat>
+
#include "code_generator.h"
#include "common_dominator.h"
#include "ssa_builder.h"
@@ -27,6 +29,12 @@
namespace art {
+// Enable floating-point static evaluation during constant folding
+// only if all floating-point operations and constants evaluate in the
+// range and precision of the type used (i.e., 32-bit float, 64-bit
+// double).
+static constexpr bool kEnableFloatingPointStaticEvaluation = (FLT_EVAL_METHOD == 0);
+
void HGraph::InitializeInexactObjectRTI(StackHandleScopeCollection* handles) {
ScopedObjectAccess soa(Thread::Current());
// Create the inexact Object reference type and store it in the HGraph.
@@ -1159,6 +1167,12 @@ HConstant* HUnaryOperation::TryStaticEvaluation() const {
return Evaluate(GetInput()->AsIntConstant());
} else if (GetInput()->IsLongConstant()) {
return Evaluate(GetInput()->AsLongConstant());
+ } else if (kEnableFloatingPointStaticEvaluation) {
+ if (GetInput()->IsFloatConstant()) {
+ return Evaluate(GetInput()->AsFloatConstant());
+ } else if (GetInput()->IsDoubleConstant()) {
+ return Evaluate(GetInput()->AsDoubleConstant());
+ }
}
return nullptr;
}
@@ -1178,6 +1192,12 @@ HConstant* HBinaryOperation::TryStaticEvaluation() const {
}
} else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) {
return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant());
+ } else if (kEnableFloatingPointStaticEvaluation) {
+ if (GetLeft()->IsFloatConstant() && GetRight()->IsFloatConstant()) {
+ return Evaluate(GetLeft()->AsFloatConstant(), GetRight()->AsFloatConstant());
+ } else if (GetLeft()->IsDoubleConstant() && GetRight()->IsDoubleConstant()) {
+ return Evaluate(GetLeft()->AsDoubleConstant(), GetRight()->AsDoubleConstant());
+ }
}
return nullptr;
}
@@ -1205,6 +1225,20 @@ HInstruction* HBinaryOperation::GetLeastConstantLeft() const {
}
}
+std::ostream& operator<<(std::ostream& os, const ComparisonBias& rhs) {
+ switch (rhs) {
+ case ComparisonBias::kNoBias:
+ return os << "no_bias";
+ case ComparisonBias::kGtBias:
+ return os << "gt_bias";
+ case ComparisonBias::kLtBias:
+ return os << "lt_bias";
+ default:
+ LOG(FATAL) << "Unknown ComparisonBias: " << static_cast<int>(rhs);
+ UNREACHABLE();
+ }
+}
+
bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const {
return this == instruction->GetPreviousDisregardingMoves();
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 854854f238..01ba704610 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2394,7 +2394,7 @@ class HIntConstant : public HConstant {
}
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- DCHECK(other->IsIntConstant());
+ DCHECK(other->IsIntConstant()) << other->DebugName();
return other->AsIntConstant()->value_ == value_;
}
@@ -2427,7 +2427,7 @@ class HLongConstant : public HConstant {
uint64_t GetValueAsUint64() const OVERRIDE { return value_; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- DCHECK(other->IsLongConstant());
+ DCHECK(other->IsLongConstant()) << other->DebugName();
return other->AsLongConstant()->value_ == value_;
}
@@ -2449,6 +2449,92 @@ class HLongConstant : public HConstant {
DISALLOW_COPY_AND_ASSIGN(HLongConstant);
};
+class HFloatConstant : public HConstant {
+ public:
+ float GetValue() const { return value_; }
+
+ uint64_t GetValueAsUint64() const OVERRIDE {
+ return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_));
+ }
+
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ DCHECK(other->IsFloatConstant()) << other->DebugName();
+ return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64();
+ }
+
+ size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
+
+ bool IsMinusOne() const OVERRIDE {
+ return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
+ }
+ bool IsZero() const OVERRIDE {
+ return value_ == 0.0f;
+ }
+ bool IsOne() const OVERRIDE {
+ return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
+ }
+ bool IsNaN() const {
+ return std::isnan(value_);
+ }
+
+ DECLARE_INSTRUCTION(FloatConstant);
+
+ private:
+ explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {}
+ explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
+
+ const float value_;
+
+ // Only the SsaBuilder and HGraph can create floating-point constants.
+ friend class SsaBuilder;
+ friend class HGraph;
+ DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
+};
+
+class HDoubleConstant : public HConstant {
+ public:
+ double GetValue() const { return value_; }
+
+ uint64_t GetValueAsUint64() const OVERRIDE { return bit_cast<uint64_t, double>(value_); }
+
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ DCHECK(other->IsDoubleConstant()) << other->DebugName();
+ return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64();
+ }
+
+ size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
+
+ bool IsMinusOne() const OVERRIDE {
+ return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
+ }
+ bool IsZero() const OVERRIDE {
+ return value_ == 0.0;
+ }
+ bool IsOne() const OVERRIDE {
+ return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
+ }
+ bool IsNaN() const {
+ return std::isnan(value_);
+ }
+
+ DECLARE_INSTRUCTION(DoubleConstant);
+
+ private:
+ explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {}
+ explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
+
+ const double value_;
+
+ // Only the SsaBuilder and HGraph can create floating-point constants.
+ friend class SsaBuilder;
+ friend class HGraph;
+ DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
+};
+
// Conditional branch. A block ending with an HIf instruction must have
// two successors.
class HIf : public HTemplateInstruction<1> {
@@ -2650,14 +2736,16 @@ class HUnaryOperation : public HExpression<1> {
return true;
}
- // Try to statically evaluate `operation` and return a HConstant
- // containing the result of this evaluation. If `operation` cannot
+ // Try to statically evaluate `this` and return a HConstant
+ // containing the result of this evaluation. If `this` cannot
// be evaluated as a constant, return null.
HConstant* TryStaticEvaluation() const;
// Apply this operation to `x`.
virtual HConstant* Evaluate(HIntConstant* x) const = 0;
virtual HConstant* Evaluate(HLongConstant* x) const = 0;
+ virtual HConstant* Evaluate(HFloatConstant* x) const = 0;
+ virtual HConstant* Evaluate(HDoubleConstant* x) const = 0;
DECLARE_ABSTRACT_INSTRUCTION(UnaryOperation);
@@ -2720,12 +2808,17 @@ class HBinaryOperation : public HExpression<2> {
return true;
}
- // Try to statically evaluate `operation` and return a HConstant
- // containing the result of this evaluation. If `operation` cannot
+ // Try to statically evaluate `this` and return a HConstant
+ // containing the result of this evaluation. If `this` cannot
// be evaluated as a constant, return null.
HConstant* TryStaticEvaluation() const;
// Apply this operation to `x` and `y`.
+ virtual HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const {
+ VLOG(compiler) << DebugName() << " is not defined for the (null, null) case.";
+ return nullptr;
+ }
virtual HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const = 0;
virtual HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const = 0;
virtual HConstant* Evaluate(HIntConstant* x ATTRIBUTE_UNUSED,
@@ -2738,11 +2831,8 @@ class HBinaryOperation : public HExpression<2> {
VLOG(compiler) << DebugName() << " is not defined for the (long, int) case.";
return nullptr;
}
- virtual HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
- HNullConstant* y ATTRIBUTE_UNUSED) const {
- VLOG(compiler) << DebugName() << " is not defined for the (null, null) case.";
- return nullptr;
- }
+ virtual HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const = 0;
+ virtual HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const = 0;
// Returns an input that can legally be used as the right input and is
// constant, or null.
@@ -2766,6 +2856,8 @@ enum class ComparisonBias {
kLtBias, // return -1 for NaN comparisons
};
+std::ostream& operator<<(std::ostream& os, const ComparisonBias& rhs);
+
class HCondition : public HBinaryOperation {
public:
HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
@@ -2783,7 +2875,7 @@ class HCondition : public HBinaryOperation {
virtual IfCondition GetOppositeCondition() const = 0;
bool IsGtBias() const { return bias_ == ComparisonBias::kGtBias; }
-
+ ComparisonBias GetBias() const { return bias_; }
void SetBias(ComparisonBias bias) { bias_ = bias; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2791,17 +2883,34 @@ class HCondition : public HBinaryOperation {
}
bool IsFPConditionTrueIfNaN() const {
- DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
IfCondition if_cond = GetCondition();
return IsGtBias() ? ((if_cond == kCondGT) || (if_cond == kCondGE)) : (if_cond == kCondNE);
}
bool IsFPConditionFalseIfNaN() const {
- DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
IfCondition if_cond = GetCondition();
return IsGtBias() ? ((if_cond == kCondLT) || (if_cond == kCondLE)) : (if_cond == kCondEQ);
}
+ protected:
+ template <typename T>
+ int32_t Compare(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); }
+
+ template <typename T>
+ int32_t CompareFP(T x, T y) const {
+ DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+ DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
+ // Handle the bias.
+ return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compare(x, y);
+ }
+
+ // Return an integer constant containing the result of a condition evaluated at compile time.
+ HIntConstant* MakeConstantCondition(bool value, uint32_t dex_pc) const {
+ return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc);
+ }
+
private:
// Needed if we merge a HCompare into a HCondition.
ComparisonBias bias_;
@@ -2817,17 +2926,25 @@ class HEqual : public HCondition {
bool IsCommutative() const OVERRIDE { return true; }
+ HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ return MakeConstantCondition(true, GetDexPc());
+ }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HEqual instruction; evaluate it as
+ // `Compare(x, y) == 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0),
+ GetDexPc());
}
- HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
- HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(1);
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(Equal);
@@ -2853,17 +2970,24 @@ class HNotEqual : public HCondition {
bool IsCommutative() const OVERRIDE { return true; }
+ HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
+ HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ return MakeConstantCondition(false, GetDexPc());
+ }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HNotEqual instruction; evaluate it as
+ // `Compare(x, y) != 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
- HConstant* Evaluate(HNullConstant* x ATTRIBUTE_UNUSED,
- HNullConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(0);
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(NotEqual);
@@ -2888,12 +3012,19 @@ class HLessThan : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HLessThan instruction; evaluate it as
+ // `Compare(x, y) < 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(LessThan);
@@ -2918,12 +3049,19 @@ class HLessThanOrEqual : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HLessThanOrEqual instruction; evaluate it as
+ // `Compare(x, y) <= 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(LessThanOrEqual);
@@ -2948,12 +3086,19 @@ class HGreaterThan : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HGreaterThan instruction; evaluate it as
+ // `Compare(x, y) > 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(GreaterThan);
@@ -2978,12 +3123,19 @@ class HGreaterThanOrEqual : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ // In the following Evaluate methods, a HCompare instruction has
+ // been merged into this HGreaterThanOrEqual instruction; evaluate it as
+ // `Compare(x, y) >= 0`.
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantCondition(Compute(Compare(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantCondition(Compute(CompareFP(x->GetValue(), y->GetValue()), 0), GetDexPc());
}
DECLARE_INSTRUCTION(GreaterThanOrEqual);
@@ -3008,14 +3160,20 @@ class HBelow : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint32_t>(x->GetValue()),
- static_cast<uint32_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint64_t>(x->GetValue()),
- static_cast<uint64_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
}
DECLARE_INSTRUCTION(Below);
@@ -3029,7 +3187,9 @@ class HBelow : public HCondition {
}
private:
- template <typename T> bool Compute(T x, T y) const { return x < y; }
+ template <typename T> bool Compute(T x, T y) const {
+ return MakeUnsigned(x) < MakeUnsigned(y);
+ }
DISALLOW_COPY_AND_ASSIGN(HBelow);
};
@@ -3040,14 +3200,20 @@ class HBelowOrEqual : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint32_t>(x->GetValue()),
- static_cast<uint32_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint64_t>(x->GetValue()),
- static_cast<uint64_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
}
DECLARE_INSTRUCTION(BelowOrEqual);
@@ -3061,7 +3227,9 @@ class HBelowOrEqual : public HCondition {
}
private:
- template <typename T> bool Compute(T x, T y) const { return x <= y; }
+ template <typename T> bool Compute(T x, T y) const {
+ return MakeUnsigned(x) <= MakeUnsigned(y);
+ }
DISALLOW_COPY_AND_ASSIGN(HBelowOrEqual);
};
@@ -3072,14 +3240,20 @@ class HAbove : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint32_t>(x->GetValue()),
- static_cast<uint32_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint64_t>(x->GetValue()),
- static_cast<uint64_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
}
DECLARE_INSTRUCTION(Above);
@@ -3093,7 +3267,9 @@ class HAbove : public HCondition {
}
private:
- template <typename T> bool Compute(T x, T y) const { return x > y; }
+ template <typename T> bool Compute(T x, T y) const {
+ return MakeUnsigned(x) > MakeUnsigned(y);
+ }
DISALLOW_COPY_AND_ASSIGN(HAbove);
};
@@ -3104,14 +3280,20 @@ class HAboveOrEqual : public HCondition {
: HCondition(first, second, dex_pc) {}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint32_t>(x->GetValue()),
- static_cast<uint32_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(static_cast<uint64_t>(x->GetValue()),
- static_cast<uint64_t>(y->GetValue())), GetDexPc());
+ return MakeConstantCondition(Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
}
DECLARE_INSTRUCTION(AboveOrEqual);
@@ -3125,7 +3307,9 @@ class HAboveOrEqual : public HCondition {
}
private:
- template <typename T> bool Compute(T x, T y) const { return x >= y; }
+ template <typename T> bool Compute(T x, T y) const {
+ return MakeUnsigned(x) >= MakeUnsigned(y);
+ }
DISALLOW_COPY_AND_ASSIGN(HAboveOrEqual);
};
@@ -3150,15 +3334,32 @@ class HCompare : public HBinaryOperation {
}
template <typename T>
- int32_t Compute(T x, T y) const { return x == y ? 0 : x > y ? 1 : -1; }
+ int32_t Compute(T x, T y) const { return x > y ? 1 : (x < y ? -1 : 0); }
+
+ template <typename T>
+ int32_t ComputeFP(T x, T y) const {
+ DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+ DCHECK_NE(GetBias(), ComparisonBias::kNoBias);
+ // Handle the bias.
+ return std::isunordered(x, y) ? (IsGtBias() ? 1 : -1) : Compute(x, y);
+ }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ // Note that there is no "cmp-int" Dex instruction so we shouldn't
+ // reach this code path when processing a freshly built HIR
+ // graph. However HCompare integer instructions can be synthesized
+ // by the instruction simplifier to implement IntegerCompare and
+ // IntegerSignum intrinsics, so we have to handle this case.
+ return MakeConstantComparison(Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ return MakeConstantComparison(Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return MakeConstantComparison(ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
}
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -3167,8 +3368,12 @@ class HCompare : public HBinaryOperation {
ComparisonBias GetBias() const { return bias_; }
- bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; }
-
+ // Does this compare instruction have a "gt bias" (vs an "lt bias")?
+ // Only meaninfgul for floating-point comparisons.
+ bool IsGtBias() const {
+ DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType())) << InputAt(0)->GetType();
+ return bias_ == ComparisonBias::kGtBias;
+ }
static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) {
// MIPS64 uses a runtime call for FP comparisons.
@@ -3177,6 +3382,13 @@ class HCompare : public HBinaryOperation {
DECLARE_INSTRUCTION(Compare);
+ protected:
+ // Return an integer constant containing the result of a comparison evaluated at compile time.
+ HIntConstant* MakeConstantComparison(int32_t value, uint32_t dex_pc) const {
+ DCHECK(value == -1 || value == 0 || value == 1) << value;
+ return GetBlock()->GetGraph()->GetIntConstant(value, dex_pc);
+ }
+
private:
const ComparisonBias bias_;
@@ -3234,92 +3446,6 @@ class HStoreLocal : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HStoreLocal);
};
-class HFloatConstant : public HConstant {
- public:
- float GetValue() const { return value_; }
-
- uint64_t GetValueAsUint64() const OVERRIDE {
- return static_cast<uint64_t>(bit_cast<uint32_t, float>(value_));
- }
-
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- DCHECK(other->IsFloatConstant());
- return other->AsFloatConstant()->GetValueAsUint64() == GetValueAsUint64();
- }
-
- size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
-
- bool IsMinusOne() const OVERRIDE {
- return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
- }
- bool IsZero() const OVERRIDE {
- return value_ == 0.0f;
- }
- bool IsOne() const OVERRIDE {
- return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
- }
- bool IsNaN() const {
- return std::isnan(value_);
- }
-
- DECLARE_INSTRUCTION(FloatConstant);
-
- private:
- explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
- : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {}
- explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
- : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
-
- const float value_;
-
- // Only the SsaBuilder and HGraph can create floating-point constants.
- friend class SsaBuilder;
- friend class HGraph;
- DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
-};
-
-class HDoubleConstant : public HConstant {
- public:
- double GetValue() const { return value_; }
-
- uint64_t GetValueAsUint64() const OVERRIDE { return bit_cast<uint64_t, double>(value_); }
-
- bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
- DCHECK(other->IsDoubleConstant());
- return other->AsDoubleConstant()->GetValueAsUint64() == GetValueAsUint64();
- }
-
- size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
-
- bool IsMinusOne() const OVERRIDE {
- return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
- }
- bool IsZero() const OVERRIDE {
- return value_ == 0.0;
- }
- bool IsOne() const OVERRIDE {
- return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
- }
- bool IsNaN() const {
- return std::isnan(value_);
- }
-
- DECLARE_INSTRUCTION(DoubleConstant);
-
- private:
- explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
- : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {}
- explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
- : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
-
- const double value_;
-
- // Only the SsaBuilder and HGraph can create floating-point constants.
- friend class SsaBuilder;
- friend class HGraph;
- DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
-};
-
class HNewInstance : public HExpression<2> {
public:
HNewInstance(HInstruction* cls,
@@ -3871,6 +3997,12 @@ class HNeg : public HUnaryOperation {
HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(Compute(x->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(Compute(x->GetValue()), GetDexPc());
+ }
DECLARE_INSTRUCTION(Neg);
@@ -3937,6 +4069,14 @@ class HAdd : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
DECLARE_INSTRUCTION(Add);
@@ -3962,6 +4102,14 @@ class HSub : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
DECLARE_INSTRUCTION(Sub);
@@ -3989,6 +4137,14 @@ class HMul : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ }
DECLARE_INSTRUCTION(Mul);
@@ -4005,7 +4161,8 @@ class HDiv : public HBinaryOperation {
: HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
template <typename T>
- T Compute(T x, T y) const {
+ T ComputeIntegral(T x, T y) const {
+ DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType();
// Our graph structure ensures we never have 0 for `y` during
// constant folding.
DCHECK_NE(y, 0);
@@ -4013,13 +4170,27 @@ class HDiv : public HBinaryOperation {
return (y == -1) ? -x : x / y;
}
+ template <typename T>
+ T ComputeFP(T x, T y) const {
+ DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
+ return x / y;
+ }
+
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(
+ ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(
+ ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
}
static SideEffects SideEffectsForArchRuntimeCalls() {
@@ -4042,7 +4213,8 @@ class HRem : public HBinaryOperation {
: HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
template <typename T>
- T Compute(T x, T y) const {
+ T ComputeIntegral(T x, T y) const {
+ DCHECK(!Primitive::IsFloatingPointType(GetType())) << GetType();
// Our graph structure ensures we never have 0 for `y` during
// constant folding.
DCHECK_NE(y, 0);
@@ -4050,15 +4222,28 @@ class HRem : public HBinaryOperation {
return (y == -1) ? 0 : x % y;
}
+ template <typename T>
+ T ComputeFP(T x, T y) const {
+ DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
+ return std::fmod(x, y);
+ }
+
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue()), GetDexPc());
+ ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HFloatConstant* x, HFloatConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetFloatConstant(
+ ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
+ }
+ HConstant* Evaluate(HDoubleConstant* x, HDoubleConstant* y) const OVERRIDE {
+ return GetBlock()->GetGraph()->GetDoubleConstant(
+ ComputeFP(x->GetValue(), y->GetValue()), GetDexPc());
}
-
static SideEffects SideEffectsForArchRuntimeCalls() {
return SideEffects::CanTriggerGC();
@@ -4125,6 +4310,16 @@ class HShl : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Shl);
@@ -4161,6 +4356,16 @@ class HShr : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Shr);
@@ -4198,6 +4403,16 @@ class HUShr : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(UShr);
@@ -4234,6 +4449,16 @@ class HAnd : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(And);
@@ -4270,6 +4495,16 @@ class HOr : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Or);
@@ -4306,6 +4541,16 @@ class HXor : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Xor);
@@ -4344,6 +4589,16 @@ class HRor : public HBinaryOperation {
return GetBlock()->GetGraph()->GetLongConstant(
Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
+ HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
+ HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Ror);
@@ -4410,6 +4665,14 @@ class HNot : public HUnaryOperation {
HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(Not);
@@ -4428,7 +4691,7 @@ class HBooleanNot : public HUnaryOperation {
}
template <typename T> bool Compute(T x) const {
- DCHECK(IsUint<1>(x));
+ DCHECK(IsUint<1>(x)) << x;
return !x;
}
@@ -4439,6 +4702,14 @@ class HBooleanNot : public HUnaryOperation {
LOG(FATAL) << DebugName() << " is not defined for long values";
UNREACHABLE();
}
+ HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for float values";
+ UNREACHABLE();
+ }
+ HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
+ LOG(FATAL) << DebugName() << " is not defined for double values";
+ UNREACHABLE();
+ }
DECLARE_INSTRUCTION(BooleanNot);
@@ -4786,10 +5057,10 @@ class HArrayGet : public HExpression<2> {
DCHECK_EQ(GetArray(), other->GetArray());
DCHECK_EQ(GetIndex(), other->GetIndex());
if (Primitive::IsIntOrLongType(GetType())) {
- DCHECK(Primitive::IsFloatingPointType(other->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(other->GetType())) << other->GetType();
} else {
- DCHECK(Primitive::IsFloatingPointType(GetType()));
- DCHECK(Primitive::IsIntOrLongType(other->GetType()));
+ DCHECK(Primitive::IsFloatingPointType(GetType())) << GetType();
+ DCHECK(Primitive::IsIntOrLongType(other->GetType())) << other->GetType();
}
}
return result;
@@ -6004,7 +6275,7 @@ inline int64_t Int64FromConstant(HConstant* constant) {
} else if (constant->IsLongConstant()) {
return constant->AsLongConstant()->GetValue();
} else {
- DCHECK(constant->IsNullConstant());
+ DCHECK(constant->IsNullConstant()) << constant->DebugName();
return 0;
}
}
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index ac9c097892..6fd65ee9a4 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -426,6 +426,16 @@ void MipsAssembler::Lw(Register rt, Register rs, uint16_t imm16) {
EmitI(0x23, rs, rt, imm16);
}
+void MipsAssembler::Lwl(Register rt, Register rs, uint16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x22, rs, rt, imm16);
+}
+
+void MipsAssembler::Lwr(Register rt, Register rs, uint16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x26, rs, rt, imm16);
+}
+
void MipsAssembler::Lbu(Register rt, Register rs, uint16_t imm16) {
EmitI(0x24, rs, rt, imm16);
}
@@ -465,6 +475,16 @@ void MipsAssembler::Sw(Register rt, Register rs, uint16_t imm16) {
EmitI(0x2b, rs, rt, imm16);
}
+void MipsAssembler::Swl(Register rt, Register rs, uint16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x2a, rs, rt, imm16);
+}
+
+void MipsAssembler::Swr(Register rt, Register rs, uint16_t imm16) {
+ CHECK(!IsR6());
+ EmitI(0x2e, rs, rt, imm16);
+}
+
void MipsAssembler::Slt(Register rd, Register rs, Register rt) {
EmitR(0, rs, rt, rd, 0, 0x2a);
}
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 01c6490f88..2262af49b3 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -162,6 +162,8 @@ class MipsAssembler FINAL : public Assembler {
void Lb(Register rt, Register rs, uint16_t imm16);
void Lh(Register rt, Register rs, uint16_t imm16);
void Lw(Register rt, Register rs, uint16_t imm16);
+ void Lwl(Register rt, Register rs, uint16_t imm16);
+ void Lwr(Register rt, Register rs, uint16_t imm16);
void Lbu(Register rt, Register rs, uint16_t imm16);
void Lhu(Register rt, Register rs, uint16_t imm16);
void Lui(Register rt, uint16_t imm16);
@@ -172,6 +174,8 @@ class MipsAssembler FINAL : public Assembler {
void Sb(Register rt, Register rs, uint16_t imm16);
void Sh(Register rt, Register rs, uint16_t imm16);
void Sw(Register rt, Register rs, uint16_t imm16);
+ void Swl(Register rt, Register rs, uint16_t imm16);
+ void Swr(Register rt, Register rs, uint16_t imm16);
void Slt(Register rd, Register rs, Register rt);
void Sltu(Register rd, Register rs, Register rt);
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 5fc3deebd3..9e27f07ff2 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -335,6 +335,18 @@ TEST_F(AssemblerMIPSTest, Nor) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Nor, "nor ${reg1}, ${reg2}, ${reg3}"), "Nor");
}
+//////////
+// MISC //
+//////////
+
+TEST_F(AssemblerMIPSTest, Movz) {
+ DriverStr(RepeatRRR(&mips::MipsAssembler::Movz, "movz ${reg1}, ${reg2}, ${reg3}"), "Movz");
+}
+
+TEST_F(AssemblerMIPSTest, Movn) {
+ DriverStr(RepeatRRR(&mips::MipsAssembler::Movn, "movn ${reg1}, ${reg2}, ${reg3}"), "Movn");
+}
+
TEST_F(AssemblerMIPSTest, Seb) {
DriverStr(RepeatRR(&mips::MipsAssembler::Seb, "seb ${reg1}, ${reg2}"), "Seb");
}
@@ -363,6 +375,10 @@ TEST_F(AssemblerMIPSTest, Srlv) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Srlv, "srlv ${reg1}, ${reg2}, ${reg3}"), "Srlv");
}
+TEST_F(AssemblerMIPSTest, Rotrv) {
+ DriverStr(RepeatRRR(&mips::MipsAssembler::Rotrv, "rotrv ${reg1}, ${reg2}, ${reg3}"), "rotrv");
+}
+
TEST_F(AssemblerMIPSTest, Srav) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Srav, "srav ${reg1}, ${reg2}, ${reg3}"), "Srav");
}
@@ -405,6 +421,14 @@ TEST_F(AssemblerMIPSTest, Ext) {
DriverStr(expected, "Ext");
}
+TEST_F(AssemblerMIPSTest, ClzR2) {
+ DriverStr(RepeatRR(&mips::MipsAssembler::ClzR2, "clz ${reg1}, ${reg2}"), "clzR2");
+}
+
+TEST_F(AssemblerMIPSTest, CloR2) {
+ DriverStr(RepeatRR(&mips::MipsAssembler::CloR2, "clo ${reg1}, ${reg2}"), "cloR2");
+}
+
TEST_F(AssemblerMIPSTest, Lb) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Lb, -16, "lb ${reg1}, {imm}(${reg2})"), "Lb");
}
@@ -413,10 +437,18 @@ TEST_F(AssemblerMIPSTest, Lh) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Lh, -16, "lh ${reg1}, {imm}(${reg2})"), "Lh");
}
+TEST_F(AssemblerMIPSTest, Lwl) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::Lwl, -16, "lwl ${reg1}, {imm}(${reg2})"), "Lwl");
+}
+
TEST_F(AssemblerMIPSTest, Lw) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Lw, -16, "lw ${reg1}, {imm}(${reg2})"), "Lw");
}
+TEST_F(AssemblerMIPSTest, Lwr) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::Lwr, -16, "lwr ${reg1}, {imm}(${reg2})"), "Lwr");
+}
+
TEST_F(AssemblerMIPSTest, Lbu) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Lbu, -16, "lbu ${reg1}, {imm}(${reg2})"), "Lbu");
}
@@ -445,10 +477,18 @@ TEST_F(AssemblerMIPSTest, Sh) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Sh, -16, "sh ${reg1}, {imm}(${reg2})"), "Sh");
}
+TEST_F(AssemblerMIPSTest, Swl) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::Swl, -16, "swl ${reg1}, {imm}(${reg2})"), "Swl");
+}
+
TEST_F(AssemblerMIPSTest, Sw) {
DriverStr(RepeatRRIb(&mips::MipsAssembler::Sw, -16, "sw ${reg1}, {imm}(${reg2})"), "Sw");
}
+TEST_F(AssemblerMIPSTest, Swr) {
+ DriverStr(RepeatRRIb(&mips::MipsAssembler::Swr, -16, "swr ${reg1}, {imm}(${reg2})"), "Swr");
+}
+
TEST_F(AssemblerMIPSTest, Slt) {
DriverStr(RepeatRRR(&mips::MipsAssembler::Slt, "slt ${reg1}, ${reg2}, ${reg3}"), "Slt");
}