summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/builder.cc220
-rw-r--r--compiler/optimizing/builder.h13
-rw-r--r--compiler/optimizing/code_generator.cc41
-rw-r--r--compiler/optimizing/code_generator.h1
-rw-r--r--compiler/optimizing/code_generator_arm.cc189
-rw-r--r--compiler/optimizing/code_generator_arm.h52
-rw-r--r--compiler/optimizing/code_generator_arm64.cc9
-rw-r--r--compiler/optimizing/code_generator_arm64.h47
-rw-r--r--compiler/optimizing/code_generator_x86.cc225
-rw-r--r--compiler/optimizing/code_generator_x86.h52
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc249
-rw-r--r--compiler/optimizing/code_generator_x86_64.h56
-rw-r--r--compiler/optimizing/codegen_test.cc120
-rw-r--r--compiler/optimizing/constant_folding_test.cc3
-rw-r--r--compiler/optimizing/nodes.h105
-rw-r--r--compiler/optimizing/optimizing_compiler.cc33
-rw-r--r--compiler/optimizing/optimizing_unit_test.h18
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.cc4
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.h1
-rw-r--r--compiler/optimizing/register_allocator.cc14
-rw-r--r--compiler/optimizing/register_allocator_test.cc41
21 files changed, 1270 insertions, 223 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index d168fc80f1..64fb764937 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -119,13 +119,6 @@ bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
return true;
}
-static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
- if (code_item.tries_size_ > 0) {
- return false;
- }
- return true;
-}
-
template<typename T>
void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
int32_t target_offset = instruction.GetTargetOffset();
@@ -164,10 +157,6 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset)
}
HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
- if (!CanHandleCodeItem(code_item)) {
- return nullptr;
- }
-
const uint16_t* code_ptr = code_item.insns_;
const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
code_start_ = code_ptr;
@@ -187,6 +176,25 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
// start a new block, and create these blocks.
ComputeBranchTargets(code_ptr, code_end);
+ // Also create blocks for catch handlers.
+ if (code_item.tries_size_ != 0) {
+ const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0);
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ for (uint32_t idx = 0; idx < handlers_size; ++idx) {
+ CatchHandlerIterator iterator(handlers_ptr);
+ for (; iterator.HasNext(); iterator.Next()) {
+ uint32_t address = iterator.GetHandlerAddress();
+ HBasicBlock* block = FindBlockStartingAt(address);
+ if (block == nullptr) {
+ block = new (arena_) HBasicBlock(graph_, address);
+ branch_targets_.Put(address, block);
+ }
+ block->SetIsCatchBlock();
+ }
+ handlers_ptr = iterator.EndDataPointer();
+ }
+ }
+
if (!InitializeParameters(code_item.ins_size_)) {
return nullptr;
}
@@ -273,6 +281,14 @@ void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type typ
UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
}
+void HGraphBuilder::Conversion_12x(const Instruction& instruction,
+ Primitive::Type input_type,
+ Primitive::Type result_type) {
+ HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
+ current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
template<typename T>
void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
HInstruction* first = LoadLocal(instruction.VRegB(), type);
@@ -529,6 +545,27 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
return true;
}
+void HGraphBuilder::BuildCheckedDiv(uint16_t out_reg,
+ uint16_t first_reg,
+ int32_t second_reg,
+ uint32_t dex_offset,
+ Primitive::Type type,
+ bool second_is_lit) {
+ DCHECK(type == Primitive::kPrimInt);
+
+ HInstruction* first = LoadLocal(first_reg, type);
+ HInstruction* second = second_is_lit ? GetIntConstant(second_reg) : LoadLocal(second_reg, type);
+ if (!second->IsIntConstant() || (second->AsIntConstant()->GetValue() == 0)) {
+ second = new (arena_) HDivZeroCheck(second, dex_offset);
+ Temporaries temps(graph_, 1);
+ current_block_->AddInstruction(second);
+ temps.Add(current_block_->GetLastInstruction());
+ }
+
+ current_block_->AddInstruction(new (arena_) HDiv(type, first, second));
+ UpdateLocal(out_reg, current_block_->GetLastInstruction());
+}
+
void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
uint32_t dex_offset,
bool is_put,
@@ -609,6 +646,60 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object,
}
}
+void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_offset) {
+ Temporaries temps(graph_, 1);
+ HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+ HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset);
+ current_block_->AddInstruction(null_check);
+ temps.Add(null_check);
+
+ HInstruction* length = new (arena_) HArrayLength(null_check);
+ current_block_->AddInstruction(length);
+
+ int32_t payload_offset = instruction.VRegB_31t() + dex_offset;
+ const Instruction::ArrayDataPayload* payload =
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset);
+ const uint8_t* data = payload->data;
+ uint32_t element_count = payload->element_count;
+
+ // Implementation of this DEX instruction seems to be that the bounds check is
+ // done before doing any stores.
+ HInstruction* last_index = GetIntConstant(payload->element_count - 1);
+ current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset));
+
+ switch (payload->element_width) {
+ case 1:
+ BuildFillArrayData(null_check,
+ reinterpret_cast<const int8_t*>(data),
+ element_count,
+ Primitive::kPrimByte,
+ dex_offset);
+ break;
+ case 2:
+ BuildFillArrayData(null_check,
+ reinterpret_cast<const int16_t*>(data),
+ element_count,
+ Primitive::kPrimShort,
+ dex_offset);
+ break;
+ case 4:
+ BuildFillArrayData(null_check,
+ reinterpret_cast<const int32_t*>(data),
+ element_count,
+ Primitive::kPrimInt,
+ dex_offset);
+ break;
+ case 8:
+ BuildFillWideArrayData(null_check,
+ reinterpret_cast<const int64_t*>(data),
+ element_count,
+ dex_offset);
+ break;
+ default:
+ LOG(FATAL) << "Unknown element width for " << payload->element_width;
+ }
+}
+
void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
const int64_t* data,
uint32_t element_count,
@@ -813,6 +904,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::NEG_FLOAT: {
+ Unop_12x<HNeg>(instruction, Primitive::kPrimFloat);
+ break;
+ }
+
+ case Instruction::NEG_DOUBLE: {
+ Unop_12x<HNeg>(instruction, Primitive::kPrimDouble);
+ break;
+ }
+
case Instruction::NOT_INT: {
Unop_12x<HNot>(instruction, Primitive::kPrimInt);
break;
@@ -823,6 +924,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::INT_TO_LONG: {
+ Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong);
+ break;
+ }
+
case Instruction::ADD_INT: {
Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
break;
@@ -888,6 +994,12 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::DIV_INT: {
+ BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+ dex_offset, Primitive::kPrimInt, false);
+ break;
+ }
+
case Instruction::DIV_FLOAT: {
Binop_23x<HDiv>(instruction, Primitive::kPrimFloat);
break;
@@ -953,6 +1065,12 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::DIV_INT_2ADDR: {
+ BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(),
+ dex_offset, Primitive::kPrimInt, false);
+ break;
+ }
+
case Instruction::DIV_FLOAT_2ADDR: {
Binop_12x<HDiv>(instruction, Primitive::kPrimFloat);
break;
@@ -993,6 +1111,13 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::DIV_INT_LIT8: {
+ BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(),
+ dex_offset, Primitive::kPrimInt, true);
+ break;
+ }
+
case Instruction::NEW_INSTANCE: {
current_block_->AddInstruction(
new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
@@ -1027,57 +1152,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::FILL_ARRAY_DATA: {
- Temporaries temps(graph_, 1);
- HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
- HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset);
- current_block_->AddInstruction(null_check);
- temps.Add(null_check);
-
- HInstruction* length = new (arena_) HArrayLength(null_check);
- current_block_->AddInstruction(length);
-
- int32_t payload_offset = instruction.VRegB_31t() + dex_offset;
- const Instruction::ArrayDataPayload* payload =
- reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset);
- const uint8_t* data = payload->data;
- uint32_t element_count = payload->element_count;
-
- // Implementation of this DEX instruction seems to be that the bounds check is
- // done before doing any stores.
- HInstruction* last_index = GetIntConstant(payload->element_count - 1);
- current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset));
-
- switch (payload->element_width) {
- case 1:
- BuildFillArrayData(null_check,
- reinterpret_cast<const int8_t*>(data),
- element_count,
- Primitive::kPrimByte,
- dex_offset);
- break;
- case 2:
- BuildFillArrayData(null_check,
- reinterpret_cast<const int16_t*>(data),
- element_count,
- Primitive::kPrimShort,
- dex_offset);
- break;
- case 4:
- BuildFillArrayData(null_check,
- reinterpret_cast<const int32_t*>(data),
- element_count,
- Primitive::kPrimInt,
- dex_offset);
- break;
- case 8:
- BuildFillWideArrayData(null_check,
- reinterpret_cast<const int64_t*>(data),
- element_count,
- dex_offset);
- break;
- default:
- LOG(FATAL) << "Unknown element width for " << payload->element_width;
- }
+ BuildFillArrayData(instruction, dex_offset);
break;
}
@@ -1168,6 +1243,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::ARRAY_LENGTH: {
HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+ // No need for a temporary for the null check, it is the only input of the following
+ // instruction.
+ object = new (arena_) HNullCheck(object, dex_offset);
+ current_block_->AddInstruction(object);
current_block_->AddInstruction(new (arena_) HArrayLength(object));
UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
break;
@@ -1202,6 +1281,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::MOVE_EXCEPTION: {
+ current_block_->AddInstruction(new (arena_) HLoadException());
+ UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
+ break;
+ }
+
+ case Instruction::THROW: {
+ HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+ current_block_->AddInstruction(new (arena_) HThrow(exception, dex_offset));
+ // A throw instruction must branch to the exit block.
+ current_block_->AddSuccessor(exit_block_);
+ // We finished building this block. Set the current block to null to avoid
+ // adding dead instructions to it.
+ current_block_ = nullptr;
+ break;
+ }
+
default:
return false;
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index eea762f834..030f45b609 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -116,6 +116,17 @@ class HGraphBuilder : public ValueObject {
template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_offset);
template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_offset);
+ void Conversion_12x(const Instruction& instruction,
+ Primitive::Type input_type,
+ Primitive::Type result_type);
+
+ void BuildCheckedDiv(uint16_t out_reg,
+ uint16_t first_reg,
+ int32_t second_reg, // can be a constant
+ uint32_t dex_offset,
+ Primitive::Type type,
+ bool second_is_lit);
+
void BuildReturn(const Instruction& instruction, Primitive::Type type);
// Builds an instance field access node and returns whether the instruction is supported.
@@ -146,6 +157,8 @@ class HGraphBuilder : public ValueObject {
uint32_t* args,
uint32_t register_index);
+ void BuildFillArrayData(const Instruction& instruction, uint32_t dex_offset);
+
// Fills the given object with data as specified in the fill-array-data
// instruction. Currently only used for non-reference and non-floating point
// arrays.
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index ac72a333c3..c75980d856 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -356,12 +356,13 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
int32_t pc2dex_dalvik_offset = 0;
uint32_t dex2pc_data_size = 0u;
uint32_t dex2pc_entries = 0u;
+ uint32_t dex2pc_offset = 0u;
+ int32_t dex2pc_dalvik_offset = 0;
if (src_map != nullptr) {
src_map->reserve(pc2dex_entries);
}
- // We currently only have pc2dex entries.
for (size_t i = 0; i < pc2dex_entries; i++) {
struct PcInfo pc_info = pc_infos_.Get(i);
pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset);
@@ -373,6 +374,19 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
}
}
+ // Walk over the blocks and find which ones correspond to catch block entries.
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ intptr_t native_pc = GetAddressOf(block);
+ ++dex2pc_entries;
+ dex2pc_data_size += UnsignedLeb128Size(native_pc - dex2pc_offset);
+ dex2pc_data_size += SignedLeb128Size(block->GetDexPc() - dex2pc_dalvik_offset);
+ dex2pc_offset = native_pc;
+ dex2pc_dalvik_offset = block->GetDexPc();
+ }
+ }
+
uint32_t total_entries = pc2dex_entries + dex2pc_entries;
uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
@@ -380,6 +394,7 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
uint8_t* data_ptr = &(*data)[0];
uint8_t* write_pos = data_ptr;
+
write_pos = EncodeUnsignedLeb128(write_pos, total_entries);
write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries);
DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size);
@@ -387,6 +402,9 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
pc2dex_offset = 0u;
pc2dex_dalvik_offset = 0u;
+ dex2pc_offset = 0u;
+ dex2pc_dalvik_offset = 0u;
+
for (size_t i = 0; i < pc2dex_entries; i++) {
struct PcInfo pc_info = pc_infos_.Get(i);
DCHECK(pc2dex_offset <= pc_info.native_pc);
@@ -395,6 +413,19 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
pc2dex_offset = pc_info.native_pc;
pc2dex_dalvik_offset = pc_info.dex_pc;
}
+
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ intptr_t native_pc = GetAddressOf(block);
+ write_pos2 = EncodeUnsignedLeb128(write_pos2, native_pc - dex2pc_offset);
+ write_pos2 = EncodeSignedLeb128(write_pos2, block->GetDexPc() - dex2pc_dalvik_offset);
+ dex2pc_offset = native_pc;
+ dex2pc_dalvik_offset = block->GetDexPc();
+ }
+ }
+
+
DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size + pc2dex_data_size);
DCHECK_EQ(static_cast<size_t>(write_pos2 - data_ptr), data_size);
@@ -411,6 +442,14 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_ma
CHECK_EQ(pc_info.dex_pc, it.DexPc());
++it;
}
+ for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
+ HBasicBlock* block = graph_->GetBlocks().Get(i);
+ if (block->IsCatchBlock()) {
+ CHECK_EQ(GetAddressOf(block), it2.NativePcOffset());
+ CHECK_EQ(block->GetDexPc(), it2.DexPc());
+ ++it2;
+ }
+ }
CHECK(it == table.PcToDexEnd());
CHECK(it2 == table.DexToPcEnd());
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 01c5cc9637..fc4ea4b5d3 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -92,6 +92,7 @@ class CodeGenerator : public ArenaObject<kArenaAllocMisc> {
virtual HGraphVisitor* GetInstructionVisitor() = 0;
virtual Assembler* GetAssembler() = 0;
virtual size_t GetWordSize() const = 0;
+ virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
void ComputeFrameSize(size_t number_of_spill_slots,
size_t maximum_number_of_live_registers,
size_t number_of_out_slots);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 6e6d64cbfc..fef7f0e80f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -92,6 +92,22 @@ class NullCheckSlowPathARM : public SlowPathCodeARM {
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
};
+class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
+ public:
+ explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
+ __ Bind(GetEntryLabel());
+ arm_codegen->InvokeRuntime(
+ QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc());
+ }
+
+ private:
+ HDivZeroCheck* const instruction_;
+ DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
+};
+
class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
public:
StackOverflowCheckSlowPathARM() {}
@@ -373,9 +389,6 @@ void CodeGeneratorARM::SetupBlockedRegisters() const {
blocked_core_registers_[LR] = true;
blocked_core_registers_[PC] = true;
- // Reserve R4 for suspend check.
- blocked_core_registers_[R4] = true;
-
// Reserve thread register.
blocked_core_registers_[TR] = true;
@@ -385,6 +398,7 @@ void CodeGeneratorARM::SetupBlockedRegisters() const {
// TODO: We currently don't use Quick's callee saved registers.
// We always save and restore R6 and R7 to make sure we can use three
// register pairs for long operations.
+ blocked_core_registers_[R4] = true;
blocked_core_registers_[R5] = true;
blocked_core_registers_[R8] = true;
blocked_core_registers_[R10] = true;
@@ -785,6 +799,7 @@ void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset,
DCHECK(instruction->IsSuspendCheck()
|| instruction->IsBoundsCheck()
|| instruction->IsNullCheck()
+ || instruction->IsDivZeroCheck()
|| !IsLeafMethod());
}
@@ -1174,7 +1189,8 @@ void LocationsBuilderARM::VisitNeg(HNeg* neg) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
default:
@@ -1214,8 +1230,14 @@ void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
break;
case Primitive::kPrimFloat:
+ DCHECK(in.IsFpuRegister());
+ __ vnegs(out.As<SRegister>(), in.As<SRegister>());
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ DCHECK(in.IsFpuRegisterPair());
+ __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
+ FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
break;
default:
@@ -1223,6 +1245,94 @@ void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
}
}
+void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
+void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations = conversion->GetLocations();
+ Location out = locations->Out();
+ Location in = locations->InAt(0);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ DCHECK(out.IsRegisterPair());
+ DCHECK(in.IsRegister());
+ __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>());
+ // Sign extension.
+ __ Asr(out.AsRegisterPairHigh<Register>(),
+ out.AsRegisterPairLow<Register>(),
+ 31);
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
void LocationsBuilderARM::VisitAdd(HAdd* add) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -1445,7 +1555,12 @@ void LocationsBuilderARM::VisitDiv(HDiv* div) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+ }
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1470,7 +1585,11 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
Location second = locations->InAt(1);
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ __ sdiv(out.As<Register>(), first.As<Register>(), second.As<Register>());
+ break;
+ }
+
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1493,6 +1612,27 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
}
}
+void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::RequiresRegister());
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
+ codegen_->AddSlowPath(slow_path);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location value = locations->InAt(0);
+
+ DCHECK(value.IsRegister()) << value;
+ __ cmp(value.As<Register>(), ShifterOperand(0));
+ __ b(slow_path->GetEntryLabel(), EQ);
+}
+
void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -2069,12 +2209,15 @@ void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instructio
new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
codegen_->AddSlowPath(slow_path);
- __ subs(R4, R4, ShifterOperand(1));
+ __ LoadFromOffset(
+ kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
+ __ cmp(IP, ShifterOperand(0));
+ // TODO: Figure out the branch offsets and use cbz/cbnz.
if (successor == nullptr) {
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ b(slow_path->GetEntryLabel(), NE);
__ Bind(slow_path->GetReturnLabel());
} else {
- __ b(codegen_->GetLabelOf(successor), NE);
+ __ b(codegen_->GetLabelOf(successor), EQ);
__ b(slow_path->GetEntryLabel());
}
}
@@ -2373,5 +2516,31 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
+ Register out = load->GetLocations()->Out().As<Register>();
+ int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
+ __ LoadFromOffset(kLoadWord, out, TR, offset);
+ __ LoadImmediate(IP, 0);
+ __ StoreToOffset(kStoreWord, IP, TR, offset);
+}
+
+void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
+ codegen_->InvokeRuntime(
+ QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc());
+}
+
} // namespace arm
} // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 5076a4bc38..5d519937f4 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -77,10 +77,10 @@ class ParallelMoveResolverARM : public ParallelMoveResolver {
ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
ArmAssembler* GetAssembler() const;
@@ -99,7 +99,7 @@ class LocationsBuilderARM : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr);
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -119,7 +119,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor {
InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr);
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -145,39 +145,43 @@ class CodeGeneratorARM : public CodeGenerator {
explicit CodeGeneratorARM(HGraph* graph);
virtual ~CodeGeneratorARM() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kArmWordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual ArmAssembler* GetAssembler() OVERRIDE {
+ ArmAssembler* GetAssembler() OVERRIDE {
return &assembler_;
}
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
// Blocks all register pairs made out of blocked core registers.
void UpdateBlockedPairRegisters() const;
@@ -186,7 +190,7 @@ class CodeGeneratorARM : public CodeGenerator {
return &move_resolver_;
}
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kThumb2;
}
@@ -208,7 +212,7 @@ class CodeGeneratorARM : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 90d7c35975..1be5717737 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -537,14 +537,18 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
M(ClinitCheck) \
M(DoubleConstant) \
M(Div) \
+ M(DivZeroCheck) \
M(FloatConstant) \
M(LoadClass) \
+ M(LoadException) \
M(LoadString) \
M(Neg) \
M(NewArray) \
M(ParallelMove) \
M(StaticFieldGet) \
M(StaticFieldSet) \
+ M(Throw) \
+ M(TypeConversion) \
#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
@@ -1065,11 +1069,8 @@ void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
break;
case Primitive::kPrimInt:
- __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
- break;
-
case Primitive::kPrimLong:
- LOG(FATAL) << "Not yet implemented type for not operation " << instruction->GetResultType();
+ __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
break;
default:
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 5530f46065..4a41000e8d 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -95,7 +95,7 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor {
InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
#undef DECLARE_VISIT_INSTRUCTION
@@ -118,7 +118,7 @@ class LocationsBuilderARM64 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
#undef DECLARE_VISIT_INSTRUCTION
@@ -135,10 +135,10 @@ class LocationsBuilderARM64 : public HGraphVisitor {
class CodeGeneratorARM64 : public CodeGenerator {
public:
explicit CodeGeneratorARM64(HGraph* graph);
- virtual ~CodeGeneratorARM64() { }
+ virtual ~CodeGeneratorARM64() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
static const vixl::CPURegList& GetFramePreservedRegisters() {
static const vixl::CPURegList frame_preserved_regs =
@@ -149,44 +149,49 @@ class CodeGeneratorARM64 : public CodeGenerator {
return GetFramePreservedRegisters().TotalSizeInBytes();
}
- virtual void Bind(HBasicBlock* block) OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
vixl::Label* GetLabelOf(HBasicBlock* block) const {
return block_labels_ + block->GetBlockId();
}
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kArm64WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block ATTRIBUTE_UNUSED) const OVERRIDE {
+ UNIMPLEMENTED(INFO) << "TODO: GetAddressOf";
+ return 0u;
+ }
+
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
- virtual Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+ HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
+ Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
// Emit a write barrier.
void MarkGCCard(vixl::Register object, vixl::Register value);
// Register allocation.
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ void SetupBlockedRegisters() const OVERRIDE;
// AllocateFreeRegister() is only used when allocating registers locally
// during CompileBaseline().
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
UNUSED(stack_index);
UNUSED(reg_id);
UNIMPLEMENTED(INFO) << "TODO: SaveCoreRegister";
return 0;
}
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
UNUSED(stack_index);
UNUSED(reg_id);
UNIMPLEMENTED(INFO) << "TODO: RestoreCoreRegister";
@@ -205,16 +210,16 @@ class CodeGeneratorARM64 : public CodeGenerator {
kNumberOfAllocatableCoreRegisters + kNumberOfAllocatableFloatingPointRegisters;
static constexpr int kNumberOfAllocatableRegisterPairs = 0;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kArm64;
}
void MoveHelper(Location destination, Location source, Primitive::Type type);
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
HGraph* graph = GetGraph();
int length = graph->GetBlocks().Size();
block_labels_ = graph->GetArena()->AllocArray<vixl::Label>(length);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 1e37909be9..127ddbeab1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -85,6 +85,36 @@ class NullCheckSlowPathX86 : public SlowPathCodeX86 {
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
};
+class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
+ public:
+ explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+ }
+
+ private:
+ HDivZeroCheck* const instruction_;
+ DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
+};
+
+class DivMinusOneSlowPathX86 : public SlowPathCodeX86 {
+ public:
+ explicit DivMinusOneSlowPathX86(Register reg) : reg_(reg) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ negl(reg_);
+ __ jmp(GetExitLabel());
+ }
+
+ private:
+ Register reg_;
+ DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86);
+};
+
class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 {
public:
StackOverflowCheckSlowPathX86() {}
@@ -1086,7 +1116,10 @@ void LocationsBuilderX86::VisitNeg(HNeg* neg) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ // Output overlaps as we need a fresh (zero-initialized)
+ // register to perform subtraction from zero.
+ locations->SetOut(Location::RequiresFpuRegister());
break;
default:
@@ -1101,11 +1134,13 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
switch (neg->GetResultType()) {
case Primitive::kPrimInt:
DCHECK(in.IsRegister());
+ DCHECK(in.Equals(out));
__ negl(out.As<Register>());
break;
case Primitive::kPrimLong:
DCHECK(in.IsRegisterPair());
+ DCHECK(in.Equals(out));
__ negl(out.AsRegisterPairLow<Register>());
// Negation is similar to subtraction from zero. The least
// significant byte triggers a borrow when it is different from
@@ -1117,8 +1152,19 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
break;
case Primitive::kPrimFloat:
+ DCHECK(!in.Equals(out));
+ // out = 0
+ __ xorps(out.As<XmmRegister>(), out.As<XmmRegister>());
+ // out = out - in
+ __ subss(out.As<XmmRegister>(), in.As<XmmRegister>());
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ DCHECK(!in.Equals(out));
+ // out = 0
+ __ xorpd(out.As<XmmRegister>(), out.As<XmmRegister>());
+ // out = out - in
+ __ subsd(out.As<XmmRegister>(), in.As<XmmRegister>());
break;
default:
@@ -1126,6 +1172,91 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
}
}
+void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ locations->SetInAt(0, Location::RegisterLocation(EAX));
+ locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
+void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations = conversion->GetLocations();
+ Location out = locations->Out();
+ Location in = locations->InAt(0);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
+ DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
+ DCHECK_EQ(in.As<Register>(), EAX);
+ __ cdq();
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
void LocationsBuilderX86::VisitAdd(HAdd* add) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -1386,7 +1517,14 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ locations->SetInAt(0, Location::RegisterLocation(EAX));
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ // Intel uses edx:eax as the dividend.
+ locations->AddTemp(Location::RegisterLocation(EDX));
+ break;
+ }
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1411,7 +1549,32 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
DCHECK(first.Equals(locations->Out()));
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ Register first_reg = first.As<Register>();
+ Register second_reg = second.As<Register>();
+ DCHECK_EQ(EAX, first_reg);
+ DCHECK_EQ(EDX, locations->GetTemp(0).As<Register>());
+
+ SlowPathCodeX86* slow_path =
+ new (GetGraph()->GetArena()) DivMinusOneSlowPathX86(first_reg);
+ codegen_->AddSlowPath(slow_path);
+
+ // 0x80000000/-1 triggers an arithmetic exception!
+ // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
+ // it's safe to just use negl instead of more complex comparisons.
+
+ __ cmpl(second_reg, Immediate(-1));
+ __ j(kEqual, slow_path->GetEntryLabel());
+
+ // edx:eax <- sign-extended of eax
+ __ cdq();
+ // eax = quotient, edx = remainder
+ __ idivl(second_reg);
+
+ __ Bind(slow_path->GetExitLabel());
+ break;
+ }
+
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1432,6 +1595,36 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
}
}
+void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::Any());
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
+ codegen_->AddSlowPath(slow_path);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location value = locations->InAt(0);
+
+ if (value.IsRegister()) {
+ __ testl(value.As<Register>(), value.As<Register>());
+ } else if (value.IsStackSlot()) {
+ __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+ __ jmp(slow_path->GetEntryLabel());
+ }
+ return;
+ }
+ __ j(kEqual, slow_path->GetEntryLabel());
+}
+
void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -2419,5 +2612,29 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
+ Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
+ __ fs()->movl(load->GetLocations()->Out().As<Register>(), address);
+ __ fs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
} // namespace x86
} // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 176a269ac4..85fe21ca76 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -71,10 +71,10 @@ class ParallelMoveResolverX86 : public ParallelMoveResolver {
ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
X86Assembler* GetAssembler() const;
@@ -94,7 +94,7 @@ class LocationsBuilderX86 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -114,7 +114,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor {
InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -140,39 +140,43 @@ class CodeGeneratorX86 : public CodeGenerator {
explicit CodeGeneratorX86(HGraph* graph);
virtual ~CodeGeneratorX86() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kX86WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual X86Assembler* GetAssembler() OVERRIDE {
+ X86Assembler* GetAssembler() OVERRIDE {
return &assembler_;
}
- virtual void SetupBlockedRegisters() const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
// Blocks all register pairs made out of blocked core registers.
void UpdateBlockedPairRegisters() const;
@@ -181,7 +185,7 @@ class CodeGeneratorX86 : public CodeGenerator {
return &move_resolver_;
}
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kX86;
}
@@ -199,7 +203,7 @@ class CodeGeneratorX86 : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 40eec9b15d..8c0842cb89 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -90,6 +90,37 @@ class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
};
+class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+ explicit DivZeroCheckSlowPathX86_64(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ gs()->call(
+ Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowDivZero), true));
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+ }
+
+ private:
+ HDivZeroCheck* const instruction_;
+ DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
+};
+
+class DivMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 {
+ public:
+ explicit DivMinusOneSlowPathX86_64(Register reg) : reg_(reg) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ negl(CpuRegister(reg_));
+ __ jmp(GetExitLabel());
+ }
+
+ private:
+ Register reg_;
+ DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86_64);
+};
+
class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
public:
StackOverflowCheckSlowPathX86_64() {}
@@ -1071,7 +1102,10 @@ void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ // Output overlaps as we need a fresh (zero-initialized)
+ // register to perform subtraction from zero.
+ locations->SetOut(Location::RequiresFpuRegister());
break;
default:
@@ -1086,17 +1120,49 @@ void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
switch (neg->GetResultType()) {
case Primitive::kPrimInt:
DCHECK(in.IsRegister());
+ DCHECK(in.Equals(out));
__ negl(out.As<CpuRegister>());
break;
case Primitive::kPrimLong:
DCHECK(in.IsRegister());
+ DCHECK(in.Equals(out));
__ negq(out.As<CpuRegister>());
break;
case Primitive::kPrimFloat:
+ DCHECK(in.IsFpuRegister());
+ DCHECK(out.IsFpuRegister());
+ DCHECK(!in.Equals(out));
+ // TODO: Instead of computing negation as a subtraction from
+ // zero, implement it with an exclusive or with value 0x80000000
+ // (mask for bit 31, representing the sign of a single-precision
+ // floating-point number), fetched from a constant pool:
+ //
+ // xorps out, [RIP:...] // value at RIP is 0x80 00 00 00
+
+ // out = 0
+ __ xorps(out.As<XmmRegister>(), out.As<XmmRegister>());
+ // out = out - in
+ __ subss(out.As<XmmRegister>(), in.As<XmmRegister>());
+ break;
+
case Primitive::kPrimDouble:
- LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+ DCHECK(in.IsFpuRegister());
+ DCHECK(out.IsFpuRegister());
+ DCHECK(!in.Equals(out));
+ // TODO: Instead of computing negation as a subtraction from
+ // zero, implement it with an exclusive or with value
+ // 0x8000000000000000 (mask for bit 63, representing the sign of
+ // a double-precision floating-point number), fetched from a
+ // constant pool:
+ //
+ // xorpd out, [RIP:...] // value at RIP is 0x80 00 00 00 00 00 00 00
+
+ // out = 0
+ __ xorpd(out.As<XmmRegister>(), out.As<XmmRegister>());
+ // out = out - in
+ __ subsd(out.As<XmmRegister>(), in.As<XmmRegister>());
break;
default:
@@ -1104,6 +1170,92 @@ void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
}
}
+void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ // TODO: We would benefit from a (to-be-implemented)
+ // Location::RegisterOrStackSlot requirement for this input.
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
+void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+ LocationSummary* locations = conversion->GetLocations();
+ Location out = locations->Out();
+ Location in = locations->InAt(0);
+ Primitive::Type result_type = conversion->GetResultType();
+ Primitive::Type input_type = conversion->GetInputType();
+ switch (result_type) {
+ case Primitive::kPrimLong:
+ switch (input_type) {
+ DCHECK(out.IsRegister());
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimInt:
+ // int-to-long conversion.
+ DCHECK(in.IsRegister());
+ __ movsxd(out.As<CpuRegister>(), in.As<CpuRegister>());
+ break;
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type << " to "
+ << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Type conversion from " << input_type
+ << " to " << result_type << " not yet implemented";
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+}
+
void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -1310,7 +1462,14 @@ void LocationsBuilderX86_64::VisitDiv(HDiv* div) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ locations->SetInAt(0, Location::RegisterLocation(RAX));
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ // Intel uses edx:eax as the dividend.
+ locations->AddTemp(Location::RegisterLocation(RDX));
+ break;
+ }
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1335,7 +1494,32 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
DCHECK(first.Equals(locations->Out()));
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ CpuRegister first_reg = first.As<CpuRegister>();
+ CpuRegister second_reg = second.As<CpuRegister>();
+ DCHECK_EQ(RAX, first_reg.AsRegister());
+ DCHECK_EQ(RDX, locations->GetTemp(0).As<CpuRegister>().AsRegister());
+
+ SlowPathCodeX86_64* slow_path =
+ new (GetGraph()->GetArena()) DivMinusOneSlowPathX86_64(first_reg.AsRegister());
+ codegen_->AddSlowPath(slow_path);
+
+ // 0x80000000/-1 triggers an arithmetic exception!
+ // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
+ // it's safe to just use negl instead of more complex comparisons.
+
+ __ cmpl(second_reg, Immediate(-1));
+ __ j(kEqual, slow_path->GetEntryLabel());
+
+ // edx:eax <- sign-extended of eax
+ __ cdq();
+ // eax = quotient, edx = remainder
+ __ idivl(second_reg);
+
+ __ Bind(slow_path->GetExitLabel());
+ break;
+ }
+
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1356,6 +1540,37 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) {
}
}
+void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::Any());
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ SlowPathCodeX86_64* slow_path =
+ new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86_64(instruction);
+ codegen_->AddSlowPath(slow_path);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location value = locations->InAt(0);
+
+ if (value.IsRegister()) {
+ __ testl(value.As<CpuRegister>(), value.As<CpuRegister>());
+ } else if (value.IsStackSlot()) {
+ __ cmpl(Address(CpuRegister(RSP), value.GetStackIndex()), Immediate(0));
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+ __ jmp(slow_path->GetEntryLabel());
+ }
+ return;
+ }
+ __ j(kEqual, slow_path->GetEntryLabel());
+}
+
void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -2369,5 +2584,31 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
__ Bind(slow_path->GetExitLabel());
}
+void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
+ Address address = Address::Absolute(
+ Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
+ __ gs()->movl(load->GetLocations()->Out().As<CpuRegister>(), address);
+ __ gs()->movl(address, Immediate(0));
+}
+
+void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitThrow(HThrow* instruction) {
+ __ gs()->call(
+ Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pDeliverException), true));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
} // namespace x86_64
} // namespace art
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 0de304538f..9565b6f876 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -72,10 +72,10 @@ class ParallelMoveResolverX86_64 : public ParallelMoveResolver {
ParallelMoveResolverX86_64(ArenaAllocator* allocator, CodeGeneratorX86_64* codegen)
: ParallelMoveResolver(allocator), codegen_(codegen) {}
- virtual void EmitMove(size_t index) OVERRIDE;
- virtual void EmitSwap(size_t index) OVERRIDE;
- virtual void SpillScratch(int reg) OVERRIDE;
- virtual void RestoreScratch(int reg) OVERRIDE;
+ void EmitMove(size_t index) OVERRIDE;
+ void EmitSwap(size_t index) OVERRIDE;
+ void SpillScratch(int reg) OVERRIDE;
+ void RestoreScratch(int reg) OVERRIDE;
X86_64Assembler* GetAssembler() const;
@@ -98,7 +98,7 @@ class LocationsBuilderX86_64 : public HGraphVisitor {
: HGraphVisitor(graph), codegen_(codegen) {}
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -118,7 +118,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor {
InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen);
#define DECLARE_VISIT_INSTRUCTION(name, super) \
- virtual void Visit##name(H##name* instr);
+ void Visit##name(H##name* instr) OVERRIDE;
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
@@ -144,30 +144,30 @@ class CodeGeneratorX86_64 : public CodeGenerator {
explicit CodeGeneratorX86_64(HGraph* graph);
virtual ~CodeGeneratorX86_64() {}
- virtual void GenerateFrameEntry() OVERRIDE;
- virtual void GenerateFrameExit() OVERRIDE;
- virtual void Bind(HBasicBlock* block) OVERRIDE;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
- virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ void GenerateFrameEntry() OVERRIDE;
+ void GenerateFrameExit() OVERRIDE;
+ void Bind(HBasicBlock* block) OVERRIDE;
+ void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
- virtual size_t GetWordSize() const OVERRIDE {
+ size_t GetWordSize() const OVERRIDE {
return kX86_64WordSize;
}
- virtual size_t FrameEntrySpillSize() const OVERRIDE;
+ size_t FrameEntrySpillSize() const OVERRIDE;
- virtual HGraphVisitor* GetLocationBuilder() OVERRIDE {
+ HGraphVisitor* GetLocationBuilder() OVERRIDE {
return &location_builder_;
}
- virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE {
+ HGraphVisitor* GetInstructionVisitor() OVERRIDE {
return &instruction_visitor_;
}
- virtual X86_64Assembler* GetAssembler() OVERRIDE {
+ X86_64Assembler* GetAssembler() OVERRIDE {
return &assembler_;
}
@@ -175,14 +175,18 @@ class CodeGeneratorX86_64 : public CodeGenerator {
return &move_resolver_;
}
- virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+ uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
+ return GetLabelOf(block)->Position();
+ }
+
+ Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- virtual void SetupBlockedRegisters() const OVERRIDE;
- virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
- virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void SetupBlockedRegisters() const OVERRIDE;
+ Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+ void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+ void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
- virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ InstructionSet GetInstructionSet() const OVERRIDE {
return InstructionSet::kX86_64;
}
@@ -198,7 +202,7 @@ class CodeGeneratorX86_64 : public CodeGenerator {
return block_labels_.GetRawStorage() + block->GetBlockId();
}
- virtual void Initialize() OVERRIDE {
+ void Initialize() OVERRIDE {
block_labels_.SetSize(GetGraph()->GetBlocks().Size());
}
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 68fcb25036..ecee44392e 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -31,6 +31,7 @@
#include "prepare_for_register_allocation.h"
#include "register_allocator.h"
#include "ssa_liveness_analysis.h"
+#include "utils.h"
#include "gtest/gtest.h"
@@ -56,24 +57,26 @@ class InternalCodeAllocator : public CodeAllocator {
DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
};
+template <typename Expected>
static void Run(const InternalCodeAllocator& allocator,
const CodeGenerator& codegen,
bool has_result,
- int32_t expected) {
- typedef int32_t (*fptr)();
+ Expected expected) {
+ typedef Expected (*fptr)();
CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
if (codegen.GetInstructionSet() == kThumb2) {
// For thumb we need the bottom bit set.
f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
}
- int32_t result = f();
+ Expected result = f();
if (has_result) {
ASSERT_EQ(result, expected);
}
}
-static void RunCodeBaseline(HGraph* graph, bool has_result, int32_t expected) {
+template <typename Expected>
+static void RunCodeBaseline(HGraph* graph, bool has_result, Expected expected) {
InternalCodeAllocator allocator;
x86::CodeGeneratorX86 codegenX86(graph);
@@ -103,11 +106,12 @@ static void RunCodeBaseline(HGraph* graph, bool has_result, int32_t expected) {
}
}
+template <typename Expected>
static void RunCodeOptimized(CodeGenerator* codegen,
HGraph* graph,
std::function<void(HGraph*)> hook_before_codegen,
bool has_result,
- int32_t expected) {
+ Expected expected) {
SsaLivenessAnalysis liveness(*graph, codegen);
liveness.Analyze();
@@ -120,10 +124,11 @@ static void RunCodeOptimized(CodeGenerator* codegen,
Run(allocator, *codegen, has_result, expected);
}
+template <typename Expected>
static void RunCodeOptimized(HGraph* graph,
std::function<void(HGraph*)> hook_before_codegen,
bool has_result,
- int32_t expected) {
+ Expected expected) {
if (kRuntimeISA == kX86) {
x86::CodeGeneratorX86 codegenX86(graph);
RunCodeOptimized(&codegenX86, graph, hook_before_codegen, has_result, expected);
@@ -148,6 +153,18 @@ static void TestCode(const uint16_t* data, bool has_result = false, int32_t expe
RunCodeBaseline(graph, has_result, expected);
}
+static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
+ ArenaPool pool;
+ ArenaAllocator arena(&pool);
+ HGraphBuilder builder(&arena, Primitive::kPrimLong);
+ const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
+ HGraph* graph = builder.BuildGraph(*item);
+ ASSERT_NE(graph, nullptr);
+ // Remove suspend checks, they cannot be executed in this context.
+ RemoveSuspendChecks(graph);
+ RunCodeBaseline(graph, has_result, expected);
+}
+
TEST(CodegenTest, ReturnVoid) {
const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
TestCode(data);
@@ -272,8 +289,8 @@ TEST(CodegenTest, ReturnIf2) {
#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
TEST(CodegenTest, TEST_NAME) { \
const int32_t input = INPUT; \
- const uint16_t input_lo = input & 0x0000FFFF; \
- const uint16_t input_hi = input >> 16; \
+ const uint16_t input_lo = Low16Bits(input); \
+ const uint16_t input_hi = High16Bits(input); \
const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
Instruction::CONST | 0 << 8, input_lo, input_hi, \
Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
@@ -286,13 +303,65 @@ NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
NOT_INT_TEST(ReturnNotInt0, 0, -1)
NOT_INT_TEST(ReturnNotInt1, 1, -2)
-NOT_INT_TEST(ReturnNotIntINT_MIN, -2147483648, 2147483647) // (2^31) - 1
-NOT_INT_TEST(ReturnNotIntINT_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
-NOT_INT_TEST(ReturnNotIntINT_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
-NOT_INT_TEST(ReturnNotIntINT_MAX, 2147483647, -2147483648) // -(2^31)
+NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
+NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
#undef NOT_INT_TEST
+// Exercise bit-wise (one's complement) not-long instruction.
+#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
+TEST(CodegenTest, TEST_NAME) { \
+ const int64_t input = INPUT; \
+ const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
+ const uint16_t word1 = High16Bits(Low32Bits(input)); \
+ const uint16_t word2 = Low16Bits(High32Bits(input)); \
+ const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
+ const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
+ Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
+ Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
+ Instruction::RETURN_WIDE | 2 << 8); \
+ \
+ TestCodeLong(data, true, EXPECTED_OUTPUT); \
+}
+
+NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
+NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
+NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
+NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
+
+NOT_LONG_TEST(ReturnNotLongINT32_MIN,
+ INT64_C(-2147483648),
+ INT64_C(2147483647)) // (2^31) - 1
+NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
+ INT64_C(-2147483647),
+ INT64_C(2147483646)) // (2^31) - 2
+NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
+ INT64_C(2147483646),
+ INT64_C(-2147483647)) // -(2^31) - 1
+NOT_LONG_TEST(ReturnNotLongINT32_MAX,
+ INT64_C(2147483647),
+ INT64_C(-2147483648)) // -(2^31)
+
+// Note that the C++ compiler won't accept
+// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
+// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
+NOT_LONG_TEST(ReturnNotINT64_MIN,
+ INT64_C(-9223372036854775807)-1,
+ INT64_C(9223372036854775807)); // (2^63) - 1
+NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
+ INT64_C(-9223372036854775807),
+ INT64_C(9223372036854775806)); // (2^63) - 2
+NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
+ INT64_C(9223372036854775806),
+ INT64_C(-9223372036854775807)); // -(2^63) - 1
+NOT_LONG_TEST(ReturnNotLongINT64_MAX,
+ INT64_C(9223372036854775807),
+ INT64_C(-9223372036854775807)-1); // -(2^63)
+
+#undef NOT_LONG_TEST
+
TEST(CodegenTest, ReturnAdd1) {
const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
@@ -543,4 +612,31 @@ TEST(CodegenTest, MaterializedCondition2) {
}
}
+#if defined(__aarch64__)
+TEST(CodegenTest, DISABLED_ReturnDivIntLit8) {
+#else
+TEST(CodegenTest, ReturnDivIntLit8) {
+#endif
+ const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ Instruction::CONST_4 | 4 << 12 | 0 << 8,
+ Instruction::DIV_INT_LIT8, 3 << 8 | 0,
+ Instruction::RETURN);
+
+ TestCode(data, true, 1);
+}
+
+#if defined(__aarch64__)
+TEST(CodegenTest, DISABLED_ReturnDivInt2Addr) {
+#else
+TEST(CodegenTest, ReturnDivInt2Addr) {
+#endif
+ const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ Instruction::CONST_4 | 4 << 12 | 0,
+ Instruction::CONST_4 | 2 << 12 | 1 << 8,
+ Instruction::DIV_INT_2ADDR | 1 << 12,
+ Instruction::RETURN);
+
+ TestCode(data, true, 2);
+}
+
} // namespace art
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 09bf2c8d7d..856c5165a3 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -332,9 +332,6 @@ TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
check_after_cf);
}
-#define SIX_REGISTERS_CODE_ITEM(...) \
- { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
-
/**
* Tiny three-register-pair program exercising long constant folding
* on addition.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 79638b3545..37e5e6b9aa 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -292,7 +292,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
block_id_(-1),
dex_pc_(dex_pc),
lifetime_start_(kNoLifetime),
- lifetime_end_(kNoLifetime) {}
+ lifetime_end_(kNoLifetime),
+ is_catch_block_(false) {}
const GrowableArray<HBasicBlock*>& GetPredecessors() const {
return predecessors_;
@@ -450,6 +451,9 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
uint32_t GetDexPc() const { return dex_pc_; }
+ bool IsCatchBlock() const { return is_catch_block_; }
+ void SetIsCatchBlock() { is_catch_block_ = true; }
+
private:
HGraph* const graph_;
GrowableArray<HBasicBlock*> predecessors_;
@@ -464,6 +468,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
const uint32_t dex_pc_;
size_t lifetime_start_;
size_t lifetime_end_;
+ bool is_catch_block_;
DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
};
@@ -478,6 +483,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
M(Compare, BinaryOperation) \
M(Condition, BinaryOperation) \
M(Div, BinaryOperation) \
+ M(DivZeroCheck, Instruction) \
M(DoubleConstant, Constant) \
M(Equal, Condition) \
M(Exit, Instruction) \
@@ -494,6 +500,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
M(LessThan, Condition) \
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
+ M(LoadException, Instruction) \
M(LoadLocal, Instruction) \
M(LoadString, Instruction) \
M(Local, Instruction) \
@@ -516,6 +523,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
M(Sub, BinaryOperation) \
M(SuspendCheck, Instruction) \
M(Temporary, Instruction) \
+ M(Throw, Instruction) \
+ M(TypeConversion, Instruction) \
#define FOR_EACH_INSTRUCTION(M) \
FOR_EACH_CONCRETE_INSTRUCTION(M) \
@@ -1050,7 +1059,7 @@ class HReturn : public HTemplateInstruction<1> {
};
// The exit instruction is the only instruction of the exit block.
-// Instructions aborting the method (HTrow and HReturn) must branch to the
+// Instructions aborting the method (HThrow and HReturn) must branch to the
// exit block.
class HExit : public HTemplateInstruction<0> {
public:
@@ -1069,7 +1078,7 @@ class HGoto : public HTemplateInstruction<0> {
public:
HGoto() : HTemplateInstruction(SideEffects::None()) {}
- virtual bool IsControlFlow() const { return true; }
+ bool IsControlFlow() const OVERRIDE { return true; }
HBasicBlock* GetSuccessor() const {
return GetBlock()->GetSuccessors().Get(0);
@@ -1090,7 +1099,7 @@ class HIf : public HTemplateInstruction<1> {
SetRawInputAt(0, input);
}
- virtual bool IsControlFlow() const { return true; }
+ bool IsControlFlow() const OVERRIDE { return true; }
HBasicBlock* IfTrueSuccessor() const {
return GetBlock()->GetSuccessors().Get(0);
@@ -1713,7 +1722,12 @@ class HDiv : public HBinaryOperation {
HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right)
: HBinaryOperation(result_type, left, right) {}
- virtual int32_t Evaluate(int32_t x, int32_t y) const { return x / y; }
+ virtual int32_t Evaluate(int32_t x, int32_t y) const {
+ // Our graph structure ensures we never have 0 for `y` during constant folding.
+ DCHECK_NE(y, 0);
+ // Special case -1 to avoid getting a SIGFPE on x86.
+ return (y == -1) ? -x : x / y;
+ }
virtual int64_t Evaluate(int64_t x, int64_t y) const { return x / y; }
DECLARE_INSTRUCTION(Div);
@@ -1722,6 +1736,33 @@ class HDiv : public HBinaryOperation {
DISALLOW_COPY_AND_ASSIGN(HDiv);
};
+class HDivZeroCheck : public HExpression<1> {
+ public:
+ HDivZeroCheck(HInstruction* value, uint32_t dex_pc)
+ : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+ SetRawInputAt(0, value);
+ }
+
+ bool CanBeMoved() const OVERRIDE { return true; }
+
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+ UNUSED(other);
+ return true;
+ }
+
+ bool NeedsEnvironment() const OVERRIDE { return true; }
+ bool CanThrow() const OVERRIDE { return true; }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
+ DECLARE_INSTRUCTION(DivZeroCheck);
+
+ private:
+ const uint32_t dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
+};
+
// The value of a parameter in this method. Its location depends on
// the calling convention.
class HParameterValue : public HExpression<0> {
@@ -1761,6 +1802,28 @@ class HNot : public HUnaryOperation {
DISALLOW_COPY_AND_ASSIGN(HNot);
};
+class HTypeConversion : public HExpression<1> {
+ public:
+ // Instantiate a type conversion of `input` to `result_type`.
+ HTypeConversion(Primitive::Type result_type, HInstruction* input)
+ : HExpression(result_type, SideEffects::None()) {
+ SetRawInputAt(0, input);
+ DCHECK_NE(input->GetType(), result_type);
+ }
+
+ HInstruction* GetInput() const { return InputAt(0); }
+ Primitive::Type GetInputType() const { return GetInput()->GetType(); }
+ Primitive::Type GetResultType() const { return GetType(); }
+
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+
+ DECLARE_INSTRUCTION(TypeConversion);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
+};
+
class HPhi : public HInstruction {
public:
HPhi(ArenaAllocator* arena, uint32_t reg_number, size_t number_of_inputs, Primitive::Type type)
@@ -2228,6 +2291,38 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
};
+// Implement the move-exception DEX instruction.
+class HLoadException : public HExpression<0> {
+ public:
+ HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+
+ DECLARE_INSTRUCTION(LoadException);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HLoadException);
+};
+
+class HThrow : public HTemplateInstruction<1> {
+ public:
+ HThrow(HInstruction* exception, uint32_t dex_pc)
+ : HTemplateInstruction(SideEffects::None()), dex_pc_(dex_pc) {
+ SetRawInputAt(0, exception);
+ }
+
+ bool IsControlFlow() const OVERRIDE { return true; }
+
+ bool NeedsEnvironment() const OVERRIDE { return true; }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
+ DECLARE_INSTRUCTION(Throw);
+
+ private:
+ uint32_t dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HThrow);
+};
+
class MoveOperands : public ArenaObject<kArenaAllocMisc> {
public:
MoveOperands(Location source, Location destination, HInstruction* instruction)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 08b74c7988..6e3653a359 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -206,6 +206,11 @@ static bool IsInstructionSetSupported(InstructionSet instruction_set) {
|| instruction_set == kX86_64;
}
+static bool CanOptimize(const DexFile::CodeItem& code_item) {
+ // TODO: We currently cannot optimize methods with try/catch.
+ return code_item.tries_size_ == 0;
+}
+
CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -264,7 +269,9 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
CodeVectorAllocator allocator;
- if (run_optimizations_ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
+ if (run_optimizations_
+ && CanOptimize(*code_item)
+ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
optimized_compiled_methods_++;
graph->BuildDominatorTree();
graph->TransformToSSA();
@@ -315,17 +322,19 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite
unoptimized_compiled_methods_++;
codegen->CompileBaseline(&allocator);
- // Run these phases to get some test coverage.
- graph->BuildDominatorTree();
- graph->TransformToSSA();
- visualizer.DumpGraph("ssa");
- graph->FindNaturalLoops();
- SsaRedundantPhiElimination(graph).Run();
- SsaDeadPhiElimination(graph).Run();
- GlobalValueNumberer(graph->GetArena(), graph).Run();
- SsaLivenessAnalysis liveness(*graph, codegen);
- liveness.Analyze();
- visualizer.DumpGraph(kLivenessPassName);
+ if (CanOptimize(*code_item)) {
+ // Run these phases to get some test coverage.
+ graph->BuildDominatorTree();
+ graph->TransformToSSA();
+ visualizer.DumpGraph("ssa");
+ graph->FindNaturalLoops();
+ SsaRedundantPhiElimination(graph).Run();
+ SsaDeadPhiElimination(graph).Run();
+ GlobalValueNumberer(graph->GetArena(), graph).Run();
+ SsaLivenessAnalysis liveness(*graph, codegen);
+ liveness.Analyze();
+ visualizer.DumpGraph(kLivenessPassName);
+ }
std::vector<uint8_t> mapping_table;
SrcMap src_mapping_table;
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index aae7f9b95e..c4106b72b5 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -30,17 +30,17 @@ namespace art {
#define NUM_INSTRUCTIONS(...) \
(sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t))
-#define ZERO_REGISTER_CODE_ITEM(...) \
- { 0, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
+#define N_REGISTERS_CODE_ITEM(NUM_REGS, ...) \
+ { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
-#define ONE_REGISTER_CODE_ITEM(...) \
- { 1, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
+#define ZERO_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(0, __VA_ARGS__)
+#define ONE_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(1, __VA_ARGS__)
+#define TWO_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(2, __VA_ARGS__)
+#define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__)
+#define FOUR_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(4, __VA_ARGS__)
+#define FIVE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(5, __VA_ARGS__)
+#define SIX_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(6, __VA_ARGS__)
-#define TWO_REGISTERS_CODE_ITEM(...) \
- { 2, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
-
-#define THREE_REGISTERS_CODE_ITEM(...) \
- { 3, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
LiveInterval* BuildInterval(const size_t ranges[][2],
size_t number_of_ranges,
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index c4db840f33..7186dbe85e 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -34,6 +34,10 @@ void PrepareForRegisterAllocation::VisitNullCheck(HNullCheck* check) {
check->ReplaceWith(check->InputAt(0));
}
+void PrepareForRegisterAllocation::VisitDivZeroCheck(HDivZeroCheck* check) {
+ check->ReplaceWith(check->InputAt(0));
+}
+
void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) {
check->ReplaceWith(check->InputAt(0));
}
diff --git a/compiler/optimizing/prepare_for_register_allocation.h b/compiler/optimizing/prepare_for_register_allocation.h
index 3e63ecb4f4..0fdb65ffe0 100644
--- a/compiler/optimizing/prepare_for_register_allocation.h
+++ b/compiler/optimizing/prepare_for_register_allocation.h
@@ -34,6 +34,7 @@ class PrepareForRegisterAllocation : public HGraphDelegateVisitor {
private:
virtual void VisitNullCheck(HNullCheck* check) OVERRIDE;
+ virtual void VisitDivZeroCheck(HDivZeroCheck* check) OVERRIDE;
virtual void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE;
virtual void VisitClinitCheck(HClinitCheck* check) OVERRIDE;
virtual void VisitCondition(HCondition* condition) OVERRIDE;
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 2a9c88506d..0745f9c5da 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -257,7 +257,13 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
//
// The backwards walking ensures the ranges are ordered on increasing start positions.
Location output = locations->Out();
- if (output.IsRegister() || output.IsFpuRegister()) {
+ if (output.IsUnallocated() && output.GetPolicy() == Location::kSameAsFirstInput) {
+ Location first = locations->InAt(0);
+ if (first.IsRegister() || first.IsFpuRegister()) {
+ current->SetFrom(position + 1);
+ current->SetRegister(first.reg());
+ }
+ } else if (output.IsRegister() || output.IsFpuRegister()) {
// Shift the interval's start by one to account for the blocked register.
current->SetFrom(position + 1);
current->SetRegister(output.reg());
@@ -1172,7 +1178,11 @@ void RegisterAllocator::Resolve() {
if (location.IsUnallocated()) {
if (location.GetPolicy() == Location::kSameAsFirstInput) {
- locations->SetInAt(0, source);
+ if (locations->InAt(0).IsUnallocated()) {
+ locations->SetInAt(0, source);
+ } else {
+ DCHECK(locations->InAt(0).Equals(source));
+ }
}
locations->SetOut(source);
} else {
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 6845deacb9..9b1a121fbe 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -696,4 +696,45 @@ TEST(RegisterAllocatorTest, SameAsFirstInputHint) {
}
}
+static HGraph* BuildDiv(ArenaAllocator* allocator,
+ HInstruction** div) {
+ HGraph* graph = new (allocator) HGraph(allocator);
+ HBasicBlock* entry = new (allocator) HBasicBlock(graph);
+ graph->AddBlock(entry);
+ graph->SetEntryBlock(entry);
+ HInstruction* first = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+ HInstruction* second = new (allocator) HParameterValue(0, Primitive::kPrimInt);
+ entry->AddInstruction(first);
+ entry->AddInstruction(second);
+
+ HBasicBlock* block = new (allocator) HBasicBlock(graph);
+ graph->AddBlock(block);
+ entry->AddSuccessor(block);
+
+ *div = new (allocator) HDiv(Primitive::kPrimInt, first, second);
+ block->AddInstruction(*div);
+
+ block->AddInstruction(new (allocator) HExit());
+ return graph;
+}
+
+TEST(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
+ ArenaPool pool;
+ ArenaAllocator allocator(&pool);
+ HInstruction *div;
+
+ {
+ HGraph* graph = BuildDiv(&allocator, &div);
+ x86::CodeGeneratorX86 codegen(graph);
+ SsaLivenessAnalysis liveness(*graph, &codegen);
+ liveness.Analyze();
+
+ RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+ register_allocator.AllocateRegisters();
+
+ // div on x86 requires its first input in eax and the output be the same as the first input.
+ ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
+ }
+}
+
} // namespace art