diff options
author | Mark Mendell <mark.p.mendell@intel.com> | 2015-02-13 17:48:38 -0500 |
---|---|---|
committer | Mark Mendell <mark.p.mendell@intel.com> | 2015-03-02 11:27:05 -0500 |
commit | 09b8463493aeb6ea2bce05f67d3457d5fcc8a7d9 (patch) | |
tree | bc1b2eddb27143144c2ca1a7ac4a811cfaf42232 /compiler/optimizing | |
parent | 4ab52e75c782abf19ff9ebff8d19c87ec4ec97b6 (diff) | |
download | art-09b8463493aeb6ea2bce05f67d3457d5fcc8a7d9.zip art-09b8463493aeb6ea2bce05f67d3457d5fcc8a7d9.tar.gz art-09b8463493aeb6ea2bce05f67d3457d5fcc8a7d9.tar.bz2 |
[optimizing compiler] x86 goodness
Implement the x86 version of
https://android-review.googlesource.com/#/c/129560/, which made some
enhancements to x86_64 code.
- Use leal to implement 3 operand adds
- Use testl rather than cmpl to 0 for registers
- Use leaq for x86_64 for adds with constant in int32_t range
Note:
- The range and register allocator tests seem quite fragile. I had to
change ADD_INT_LIT8 to XOR_INT_LIT8 for the register allocator test to
get the code to run. It seems like this is a bit hard-coded to
expected code generation sequences. I also changes BuildTwoAdds to
BuildTwoSubs for the same reason.
- For the live range test, I just changed the expected output, as the
Locations were different.
Change-Id: I402f2e95ddc8be4eb0befb3dae1b29feadfa29ab
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 69 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 35 | ||||
-rw-r--r-- | compiler/optimizing/live_ranges_test.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator_test.cc | 60 |
4 files changed, 112 insertions, 56 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 7b35cfd..116dd15 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -819,7 +819,7 @@ void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { // Materialized condition, compare against 0. Location lhs = if_instr->GetLocations()->InAt(0); if (lhs.IsRegister()) { - __ cmpl(lhs.AsRegister<Register>(), Immediate(0)); + __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); } else { __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0)); } @@ -836,9 +836,12 @@ void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { if (rhs.IsRegister()) { __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); } else if (rhs.IsConstant()) { - HIntConstant* instruction = rhs.GetConstant()->AsIntConstant(); - Immediate imm(instruction->AsIntConstant()->GetValue()); - __ cmpl(lhs.AsRegister<Register>(), imm); + int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue(); + if (constant == 0) { + __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); + } else { + __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); + } } else { __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); } @@ -914,16 +917,19 @@ void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) { Register reg = locations->Out().AsRegister<Register>(); // Clear register: setcc only sets the low byte. __ xorl(reg, reg); - if (locations->InAt(1).IsRegister()) { - __ cmpl(locations->InAt(0).AsRegister<Register>(), - locations->InAt(1).AsRegister<Register>()); - } else if (locations->InAt(1).IsConstant()) { - HConstant* instruction = locations->InAt(1).GetConstant(); - Immediate imm(CodeGenerator::GetInt32ValueOf(instruction)); - __ cmpl(locations->InAt(0).AsRegister<Register>(), imm); + Location lhs = locations->InAt(0); + Location rhs = locations->InAt(1); + if (rhs.IsRegister()) { + __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); + } else if (rhs.IsConstant()) { + int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue(); + if (constant == 0) { + __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); + } else { + __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); + } } else { - __ cmpl(locations->InAt(0).AsRegister<Register>(), - Address(ESP, locations->InAt(1).GetStackIndex())); + __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); } __ setb(X86Condition(comp->GetCondition()), reg); } @@ -1798,7 +1804,13 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); switch (add->GetResultType()) { - case Primitive::kPrimInt: + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + } + case Primitive::kPrimLong: { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::Any()); @@ -1824,15 +1836,26 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { LocationSummary* locations = add->GetLocations(); Location first = locations->InAt(0); Location second = locations->InAt(1); - DCHECK(first.Equals(locations->Out())); + Location out = locations->Out(); + switch (add->GetResultType()) { case Primitive::kPrimInt: { if (second.IsRegister()) { - __ addl(first.AsRegister<Register>(), second.AsRegister<Register>()); + if (out.AsRegister<Register>() == first.AsRegister<Register>()) { + __ addl(out.AsRegister<Register>(), second.AsRegister<Register>()); + } else { + __ leal(out.AsRegister<Register>(), Address( + first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0)); + } } else if (second.IsConstant()) { - __ addl(first.AsRegister<Register>(), - Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + int32_t value = second.GetConstant()->AsIntConstant()->GetValue(); + if (out.AsRegister<Register>() == first.AsRegister<Register>()) { + __ addl(out.AsRegister<Register>(), Immediate(value)); + } else { + __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value)); + } } else { + DCHECK(first.Equals(locations->Out())); __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); } break; @@ -3502,12 +3525,16 @@ void ParallelMoveResolverX86::EmitMove(size_t index) { } else if (source.IsConstant()) { HConstant* constant = source.GetConstant(); if (constant->IsIntConstant() || constant->IsNullConstant()) { - Immediate imm(CodeGenerator::GetInt32ValueOf(constant)); + int32_t value = CodeGenerator::GetInt32ValueOf(constant); if (destination.IsRegister()) { - __ movl(destination.AsRegister<Register>(), imm); + if (value == 0) { + __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>()); + } else { + __ movl(destination.AsRegister<Register>(), Immediate(value)); + } } else { DCHECK(destination.IsStackSlot()) << destination; - __ movl(Address(ESP, destination.GetStackIndex()), imm); + __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value)); } } else { DCHECK(constant->IsFloatConstant()); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 74adb31..adc022a 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1868,8 +1868,19 @@ void LocationsBuilderX86_64::VisitAdd(HAdd* add) { case Primitive::kPrimLong: { locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::SameAsFirstInput()); + // We can use a leaq or addq if the constant can fit in an immediate. + HInstruction* rhs = add->InputAt(1); + bool is_int32_constant = false; + if (rhs->IsLongConstant()) { + int64_t value = rhs->AsLongConstant()->GetValue(); + if (static_cast<int32_t>(value) == value) { + is_int32_constant = true; + } + } + locations->SetInAt(1, + is_int32_constant ? Location::RegisterOrConstant(rhs) : + Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; } @@ -1917,7 +1928,25 @@ void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) { } case Primitive::kPrimLong: { - __ addq(first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>()); + if (second.IsRegister()) { + if (out.AsRegister<Register>() == first.AsRegister<Register>()) { + __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>()); + } else { + __ leaq(out.AsRegister<CpuRegister>(), Address( + first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0)); + } + } else { + DCHECK(second.IsConstant()); + int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); + int32_t int32_value = Low32Bits(value); + DCHECK_EQ(int32_value, value); + if (out.AsRegister<Register>() == first.AsRegister<Register>()) { + __ addq(out.AsRegister<CpuRegister>(), Immediate(int32_value)); + } else { + __ leaq(out.AsRegister<CpuRegister>(), Address( + first.AsRegister<CpuRegister>(), int32_value)); + } + } break; } diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index 17914e8..c102c4f 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -399,11 +399,11 @@ TEST(LiveRangesTest, CFG4) { LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); LiveRange* range = interval->GetFirstRange(); ASSERT_EQ(2u, range->GetStart()); - ASSERT_EQ(16u, range->GetEnd()); + ASSERT_EQ(17u, range->GetEnd()); range = range->GetNext(); ASSERT_TRUE(range != nullptr); ASSERT_EQ(20u, range->GetStart()); - ASSERT_EQ(22u, range->GetEnd()); + ASSERT_EQ(23u, range->GetEnd()); ASSERT_TRUE(range->GetNext() == nullptr); // Test for the 4 constant. diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index e5d06a9..b757a3b 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -322,9 +322,9 @@ TEST(RegisterAllocatorTest, Loop3) { TEST(RegisterAllocatorTest, FirstRegisterUse) { const uint16_t data[] = THREE_REGISTERS_CODE_ITEM( Instruction::CONST_4 | 0 | 0, - Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8, - Instruction::ADD_INT_LIT8 | 0 << 8, 1 << 8, - Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8 | 1, + Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8, + Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8, + Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1, Instruction::RETURN_VOID); ArenaPool pool; @@ -334,27 +334,27 @@ TEST(RegisterAllocatorTest, FirstRegisterUse) { SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); - HAdd* first_add = graph->GetBlocks().Get(1)->GetFirstInstruction()->AsAdd(); - HAdd* last_add = graph->GetBlocks().Get(1)->GetLastInstruction()->GetPrevious()->AsAdd(); - ASSERT_EQ(last_add->InputAt(0), first_add); - LiveInterval* interval = first_add->GetLiveInterval(); - ASSERT_EQ(interval->GetEnd(), last_add->GetLifetimePosition()); + HXor* first_xor = graph->GetBlocks().Get(1)->GetFirstInstruction()->AsXor(); + HXor* last_xor = graph->GetBlocks().Get(1)->GetLastInstruction()->GetPrevious()->AsXor(); + ASSERT_EQ(last_xor->InputAt(0), first_xor); + LiveInterval* interval = first_xor->GetLiveInterval(); + ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition()); ASSERT_TRUE(interval->GetNextSibling() == nullptr); // We need a register for the output of the instruction. - ASSERT_EQ(interval->FirstRegisterUse(), first_add->GetLifetimePosition()); + ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition()); // Split at the next instruction. - interval = interval->SplitAt(first_add->GetLifetimePosition() + 2); + interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2); // The user of the split is the last add. - ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition()); + ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition()); // Split before the last add. - LiveInterval* new_interval = interval->SplitAt(last_add->GetLifetimePosition() - 1); + LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1); // Ensure the current interval has no register use... ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime); // And the new interval has it for the last add. - ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition()); + ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition()); } TEST(RegisterAllocatorTest, DeadPhi) { @@ -634,9 +634,9 @@ TEST(RegisterAllocatorTest, ExpectedInRegisterHint) { } } -static HGraph* BuildTwoAdds(ArenaAllocator* allocator, - HInstruction** first_add, - HInstruction** second_add) { +static HGraph* BuildTwoSubs(ArenaAllocator* allocator, + HInstruction** first_sub, + HInstruction** second_sub) { HGraph* graph = new (allocator) HGraph(allocator); HBasicBlock* entry = new (allocator) HBasicBlock(graph); graph->AddBlock(entry); @@ -652,10 +652,10 @@ static HGraph* BuildTwoAdds(ArenaAllocator* allocator, graph->AddBlock(block); entry->AddSuccessor(block); - *first_add = new (allocator) HAdd(Primitive::kPrimInt, parameter, constant1); - block->AddInstruction(*first_add); - *second_add = new (allocator) HAdd(Primitive::kPrimInt, *first_add, constant2); - block->AddInstruction(*second_add); + *first_sub = new (allocator) HSub(Primitive::kPrimInt, parameter, constant1); + block->AddInstruction(*first_sub); + *second_sub = new (allocator) HSub(Primitive::kPrimInt, *first_sub, constant2); + block->AddInstruction(*second_sub); block->AddInstruction(new (allocator) HExit()); return graph; @@ -664,10 +664,10 @@ static HGraph* BuildTwoAdds(ArenaAllocator* allocator, TEST(RegisterAllocatorTest, SameAsFirstInputHint) { ArenaPool pool; ArenaAllocator allocator(&pool); - HInstruction *first_add, *second_add; + HInstruction *first_sub, *second_sub; { - HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); + HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub); x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); @@ -676,27 +676,27 @@ TEST(RegisterAllocatorTest, SameAsFirstInputHint) { register_allocator.AllocateRegisters(); // Sanity check that in normal conditions, the registers are the same. - ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 1); - ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 1); + ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1); + ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1); } { - HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add); + HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub); x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); SsaLivenessAnalysis liveness(*graph, &codegen); liveness.Analyze(); // check that both adds get the same register. // Don't use UpdateOutput because output is already allocated. - first_add->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2); - ASSERT_EQ(first_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); - ASSERT_EQ(second_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); + first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2); + ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); + ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput); RegisterAllocator register_allocator(&allocator, &codegen, liveness); register_allocator.AllocateRegisters(); - ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 2); - ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 2); + ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2); + ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2); } } |