diff options
| author | 2015-09-09 10:04:41 +0000 | |
|---|---|---|
| committer | 2015-09-09 10:04:41 +0000 | |
| commit | 67c5d28da9b0c40343e8a8f68fea4dc86ff554d1 (patch) | |
| tree | 3e661d9922c1c220e333f805cc751457090a094f | |
| parent | 426514cada274714244290d6447d9f62dc3394bf (diff) | |
| parent | 0616ae081e648f4b9b64b33e2624a943c5fce977 (diff) | |
Merge "[optimizing] Add support for x86 constant area"
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 357 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.h | 33 | ||||
| -rw-r--r-- | compiler/optimizing/constant_area_fixups_x86.h | 37 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 12 | ||||
| -rw-r--r-- | compiler/optimizing/nodes_x86.h | 66 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 15 | ||||
| -rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 55 | ||||
| -rw-r--r-- | compiler/utils/x86/assembler_x86.h | 90 |
8 files changed, 649 insertions, 16 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index f48395b1e1..ecf5eedcd5 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -19,6 +19,7 @@ #include "art_method.h" #include "code_generator_utils.h" #include "compiled_method.h" +#include "constant_area_fixups_x86.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "gc/accounting/card_table.h" @@ -2213,7 +2214,7 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::Any()); locations->SetOut(Location::SameAsFirstInput()); break; } @@ -2275,6 +2276,16 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { case Primitive::kPrimFloat: { if (second.IsFpuRegister()) { __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ addss(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress( + const_area->GetConstant()->AsFloatConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsStackSlot()); + __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); } break; } @@ -2282,6 +2293,16 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { case Primitive::kPrimDouble: { if (second.IsFpuRegister()) { __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ addsd(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress( + const_area->GetConstant()->AsDoubleConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsDoubleStackSlot()); + __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); } break; } @@ -2305,7 +2326,7 @@ void LocationsBuilderX86::VisitSub(HSub* sub) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::Any()); locations->SetOut(Location::SameAsFirstInput()); break; } @@ -2351,12 +2372,36 @@ void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { } case Primitive::kPrimFloat: { - __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + if (second.IsFpuRegister()) { + __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ subss(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress( + const_area->GetConstant()->AsFloatConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsStackSlot()); + __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } case Primitive::kPrimDouble: { - __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + if (second.IsFpuRegister()) { + __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ subsd(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress( + const_area->GetConstant()->AsDoubleConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsDoubleStackSlot()); + __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } @@ -2391,7 +2436,7 @@ void LocationsBuilderX86::VisitMul(HMul* mul) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::Any()); locations->SetOut(Location::SameAsFirstInput()); break; } @@ -2507,12 +2552,38 @@ void InstructionCodeGeneratorX86::VisitMul(HMul* mul) { } case Primitive::kPrimFloat: { - __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + DCHECK(first.Equals(locations->Out())); + if (second.IsFpuRegister()) { + __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ mulss(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress( + const_area->GetConstant()->AsFloatConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsStackSlot()); + __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } case Primitive::kPrimDouble: { - __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + DCHECK(first.Equals(locations->Out())); + if (second.IsFpuRegister()) { + __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ mulsd(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress( + const_area->GetConstant()->AsDoubleConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsDoubleStackSlot()); + __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } @@ -2855,7 +2926,7 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::Any()); locations->SetOut(Location::SameAsFirstInput()); break; } @@ -2867,7 +2938,6 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) { void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { LocationSummary* locations = div->GetLocations(); - Location out = locations->Out(); Location first = locations->InAt(0); Location second = locations->InAt(1); @@ -2879,14 +2949,36 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { } case Primitive::kPrimFloat: { - DCHECK(first.Equals(out)); - __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + if (second.IsFpuRegister()) { + __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ divss(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress( + const_area->GetConstant()->AsFloatConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsStackSlot()); + __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } case Primitive::kPrimDouble: { - DCHECK(first.Equals(out)); - __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + if (second.IsFpuRegister()) { + __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); + } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) { + HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable(); + DCHECK(!const_area->NeedsMaterialization()); + __ divsd(first.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress( + const_area->GetConstant()->AsDoubleConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(second.IsDoubleStackSlot()); + __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); + } break; } @@ -5085,6 +5177,245 @@ void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRI // Will be generated at use site. } +void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress( + HX86ComputeBaseMethodAddress* insn) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall); + locations->SetOut(Location::RequiresRegister()); +} + +void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress( + HX86ComputeBaseMethodAddress* insn) { + LocationSummary* locations = insn->GetLocations(); + Register reg = locations->Out().AsRegister<Register>(); + + // Generate call to next instruction. + Label next_instruction; + __ call(&next_instruction); + __ Bind(&next_instruction); + + // Remember this offset for later use with constant area. + codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize()); + + // Grab the return address off the stack. + __ popl(reg); +} + +void LocationsBuilderX86::VisitX86LoadFromConstantTable( + HX86LoadFromConstantTable* insn) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall); + + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant())); + + // If we don't need to be materialized, we only need the inputs to be set. + if (!insn->NeedsMaterialization()) { + return; + } + + switch (insn->GetType()) { + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + locations->SetOut(Location::RequiresFpuRegister()); + break; + + case Primitive::kPrimInt: + locations->SetOut(Location::RequiresRegister()); + break; + + default: + LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType(); + } +} + +void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) { + if (!insn->NeedsMaterialization()) { + return; + } + + LocationSummary* locations = insn->GetLocations(); + Location out = locations->Out(); + Register const_area = locations->InAt(0).AsRegister<Register>(); + HConstant *value = insn->GetConstant(); + + switch (insn->GetType()) { + case Primitive::kPrimFloat: + __ movss(out.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area)); + break; + + case Primitive::kPrimDouble: + __ movsd(out.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area)); + break; + + case Primitive::kPrimInt: + __ movl(out.AsRegister<Register>(), + codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area)); + break; + + default: + LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType(); + } +} + +void CodeGeneratorX86::Finalize(CodeAllocator* allocator) { + // Generate the constant area if needed. + X86Assembler* assembler = GetAssembler(); + if (!assembler->IsConstantAreaEmpty()) { + // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8 + // byte values. + assembler->Align(4, 0); + constant_area_start_ = assembler->CodeSize(); + assembler->AddConstantArea(); + } + + // And finish up. + CodeGenerator::Finalize(allocator); +} + +/** + * Class to handle late fixup of offsets into constant area. + */ +class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> { + public: + RIPFixup(const CodeGeneratorX86& codegen, int offset) + : codegen_(codegen), offset_into_constant_area_(offset) {} + + private: + void Process(const MemoryRegion& region, int pos) OVERRIDE { + // Patch the correct offset for the instruction. The place to patch is the + // last 4 bytes of the instruction. + // The value to patch is the distance from the offset in the constant area + // from the address computed by the HX86ComputeBaseMethodAddress instruction. + int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_; + int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();; + + // Patch in the right value. + region.StoreUnaligned<int32_t>(pos - 4, relative_position); + } + + const CodeGeneratorX86& codegen_; + + // Location in constant area that the fixup refers to. + int offset_into_constant_area_; +}; + +Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) { + AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v)); + return Address(reg, kDummy32BitOffset, fixup); +} + +Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) { + AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v)); + return Address(reg, kDummy32BitOffset, fixup); +} + +Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) { + AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v)); + return Address(reg, kDummy32BitOffset, fixup); +} + +Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) { + AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v)); + return Address(reg, kDummy32BitOffset, fixup); +} + +/** + * Finds instructions that need the constant area base as an input. + */ +class ConstantHandlerVisitor : public HGraphVisitor { + public: + explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {} + + private: + void VisitAdd(HAdd* add) OVERRIDE { + BinaryFP(add); + } + + void VisitSub(HSub* sub) OVERRIDE { + BinaryFP(sub); + } + + void VisitMul(HMul* mul) OVERRIDE { + BinaryFP(mul); + } + + void VisitDiv(HDiv* div) OVERRIDE { + BinaryFP(div); + } + + void VisitReturn(HReturn* ret) OVERRIDE { + HConstant* value = ret->InputAt(0)->AsConstant(); + if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) { + ReplaceInput(ret, value, 0, true); + } + } + + void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { + HandleInvoke(invoke); + } + + void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE { + HandleInvoke(invoke); + } + + void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE { + HandleInvoke(invoke); + } + + void BinaryFP(HBinaryOperation* bin) { + HConstant* rhs = bin->InputAt(1)->AsConstant(); + if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) { + ReplaceInput(bin, rhs, 1, false); + } + } + + void InitializeConstantAreaPointer(HInstruction* user) { + // Ensure we only initialize the pointer once. + if (base_ != nullptr) { + return; + } + + HGraph* graph = GetGraph(); + HBasicBlock* entry = graph->GetEntryBlock(); + base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress(); + HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction(); + entry->InsertInstructionBefore(base_, insert_pos); + DCHECK(base_ != nullptr); + } + + void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) { + InitializeConstantAreaPointer(insn); + HGraph* graph = GetGraph(); + HBasicBlock* block = insn->GetBlock(); + HX86LoadFromConstantTable* load_constant = + new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize); + block->InsertInstructionBefore(load_constant, insn); + insn->ReplaceInput(load_constant, input_index); + } + + void HandleInvoke(HInvoke* invoke) { + // Ensure that we can load FP arguments from the constant area. + for (size_t i = 0, e = invoke->InputCount(); i < e; i++) { + HConstant* input = invoke->InputAt(i)->AsConstant(); + if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) { + ReplaceInput(invoke, input, i, true); + } + } + } + + // The generated HX86ComputeBaseMethodAddress in the entry block needed as an + // input to the HX86LoadFromConstantTable instructions. + HX86ComputeBaseMethodAddress* base_; +}; + +void ConstantAreaFixups::Run() { + ConstantHandlerVisitor visitor(graph_); + visitor.VisitInsertionOrder(); +} + #undef __ } // namespace x86 diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 17787a82df..edf289d581 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -325,6 +325,25 @@ class CodeGeneratorX86 : public CodeGenerator { return isa_features_; } + void SetMethodAddressOffset(int32_t offset) { + method_address_offset_ = offset; + } + + int32_t GetMethodAddressOffset() const { + return method_address_offset_; + } + + int32_t ConstantAreaStart() const { + return constant_area_start_; + } + + Address LiteralDoubleAddress(double v, Register reg); + Address LiteralFloatAddress(float v, Register reg); + Address LiteralInt32Address(int32_t v, Register reg); + Address LiteralInt64Address(int64_t v, Register reg); + + void Finalize(CodeAllocator* allocator) OVERRIDE; + private: // Labels for each block that will be compiled. GrowableArray<Label> block_labels_; @@ -339,6 +358,20 @@ class CodeGeneratorX86 : public CodeGenerator { ArenaDeque<MethodPatchInfo<Label>> method_patches_; ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_; + // Offset to the start of the constant area in the assembled code. + // Used for fixups to the constant area. + int32_t constant_area_start_; + + // If there is a HX86ComputeBaseMethodAddress instruction in the graph + // (which shall be the sole instruction of this kind), subtracting this offset + // from the value contained in the out register of this HX86ComputeBaseMethodAddress + // instruction gives the address of the start of this method. + int32_t method_address_offset_; + + // When we don't know the proper offset for the value, we use kDummy32BitOffset. + // The correct value will be inserted when processing Assembler fixups. + static constexpr int32_t kDummy32BitOffset = 256; + DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86); }; diff --git a/compiler/optimizing/constant_area_fixups_x86.h b/compiler/optimizing/constant_area_fixups_x86.h new file mode 100644 index 0000000000..4138039cdd --- /dev/null +++ b/compiler/optimizing/constant_area_fixups_x86.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_ +#define ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_ + +#include "nodes.h" +#include "optimization.h" + +namespace art { +namespace x86 { + +class ConstantAreaFixups : public HOptimization { + public: + ConstantAreaFixups(HGraph* graph, OptimizingCompilerStats* stats) + : HOptimization(graph, "constant_area_fixups_x86", stats) {} + + void Run() OVERRIDE; +}; + +} // namespace x86 +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_ diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index fef6f21b46..dc0a5df8ae 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1076,7 +1076,9 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M) -#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) +#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \ + M(X86ComputeBaseMethodAddress, Instruction) \ + M(X86LoadFromConstantTable, Instruction) #define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) @@ -4955,6 +4957,14 @@ class HParallelMove : public HTemplateInstruction<0> { DISALLOW_COPY_AND_ASSIGN(HParallelMove); }; +} // namespace art + +#ifdef ART_ENABLE_CODEGEN_x86 +#include "nodes_x86.h" +#endif + +namespace art { + class HGraphVisitor : public ValueObject { public: explicit HGraphVisitor(HGraph* graph) : graph_(graph) {} diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h new file mode 100644 index 0000000000..ddc5730215 --- /dev/null +++ b/compiler/optimizing/nodes_x86.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_OPTIMIZING_NODES_X86_H_ +#define ART_COMPILER_OPTIMIZING_NODES_X86_H_ + +namespace art { + +// Compute the address of the method for X86 Constant area support. +class HX86ComputeBaseMethodAddress : public HExpression<0> { + public: + // Treat the value as an int32_t, but it is really a 32 bit native pointer. + HX86ComputeBaseMethodAddress() : HExpression(Primitive::kPrimInt, SideEffects::None()) {} + + DECLARE_INSTRUCTION(X86ComputeBaseMethodAddress); + + private: + DISALLOW_COPY_AND_ASSIGN(HX86ComputeBaseMethodAddress); +}; + +// Load a constant value from the constant table. +class HX86LoadFromConstantTable : public HExpression<2> { + public: + HX86LoadFromConstantTable(HX86ComputeBaseMethodAddress* method_base, + HConstant* constant, + bool needs_materialization = true) + : HExpression(constant->GetType(), SideEffects::None()), + needs_materialization_(needs_materialization) { + SetRawInputAt(0, method_base); + SetRawInputAt(1, constant); + } + + bool NeedsMaterialization() const { return needs_materialization_; } + + HX86ComputeBaseMethodAddress* GetBaseMethodAddress() const { + return InputAt(0)->AsX86ComputeBaseMethodAddress(); + } + + HConstant* GetConstant() const { + return InputAt(1)->AsConstant(); + } + + DECLARE_INSTRUCTION(X86LoadFromConstantTable); + + private: + const bool needs_materialization_; + + DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable); +}; + +} // namespace art + +#endif // ART_COMPILER_OPTIMIZING_NODES_X86_H_ diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 91b03d4bd1..f549ba8391 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -23,6 +23,10 @@ #include "instruction_simplifier_arm64.h" #endif +#ifdef ART_ENABLE_CODEGEN_x86 +#include "constant_area_fixups_x86.h" +#endif + #include "art_method-inl.h" #include "base/arena_allocator.h" #include "base/arena_containers.h" @@ -424,6 +428,17 @@ static void RunArchOptimizations(InstructionSet instruction_set, break; } #endif +#ifdef ART_ENABLE_CODEGEN_x86 + case kX86: { + x86::ConstantAreaFixups* constant_area_fixups = + new (arena) x86::ConstantAreaFixups(graph, stats); + HOptimization* x86_optimizations[] = { + constant_area_fixups + }; + RunOptimizations(x86_optimizations, arraysize(x86_optimizations), pass_observer); + break; + } +#endif default: break; } diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index a03f857e88..e3962b4d69 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1750,6 +1750,10 @@ void X86Assembler::EmitOperand(int reg_or_opcode, const Operand& operand) { for (int i = 1; i < length; i++) { EmitUint8(operand.encoding_[i]); } + AssemblerFixup* fixup = operand.GetFixup(); + if (fixup != nullptr) { + EmitFixup(fixup); + } } @@ -2322,5 +2326,56 @@ void X86ExceptionSlowPath::Emit(Assembler *sasm) { #undef __ } +void X86Assembler::AddConstantArea() { + const std::vector<int32_t>& area = constant_area_.GetBuffer(); + // Generate the data for the literal area. + for (size_t i = 0, e = area.size(); i < e; i++) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitInt32(area[i]); + } +} + +int ConstantArea::AddInt32(int32_t v) { + for (size_t i = 0, e = buffer_.size(); i < e; i++) { + if (v == buffer_[i]) { + return i * kEntrySize; + } + } + + // Didn't match anything. + int result = buffer_.size() * kEntrySize; + buffer_.push_back(v); + return result; +} + +int ConstantArea::AddInt64(int64_t v) { + int32_t v_low = Low32Bits(v); + int32_t v_high = High32Bits(v); + if (buffer_.size() > 1) { + // Ensure we don't pass the end of the buffer. + for (size_t i = 0, e = buffer_.size() - 1; i < e; i++) { + if (v_low == buffer_[i] && v_high == buffer_[i + 1]) { + return i * kEntrySize; + } + } + } + + // Didn't match anything. + int result = buffer_.size() * kEntrySize; + buffer_.push_back(v_low); + buffer_.push_back(v_high); + return result; +} + +int ConstantArea::AddDouble(double v) { + // Treat the value as a 64-bit integer value. + return AddInt64(bit_cast<int64_t, double>(v)); +} + +int ConstantArea::AddFloat(float v) { + // Treat the value as a 32-bit integer value. + return AddInt32(bit_cast<int32_t, float>(v)); +} + } // namespace x86 } // namespace art diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index 0c90f2801a..7d7b3d347b 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -86,7 +86,7 @@ class Operand : public ValueObject { protected: // Operand can be sub classed (e.g: Address). - Operand() : length_(0) { } + Operand() : length_(0), fixup_(nullptr) { } void SetModRM(int mod_in, Register rm_in) { CHECK_EQ(mod_in & ~3, 0); @@ -113,11 +113,23 @@ class Operand : public ValueObject { length_ += disp_size; } + AssemblerFixup* GetFixup() const { + return fixup_; + } + + void SetFixup(AssemblerFixup* fixup) { + fixup_ = fixup; + } + private: uint8_t length_; uint8_t encoding_[6]; - explicit Operand(Register reg) { SetModRM(3, reg); } + // A fixup can be associated with the operand, in order to be applied after the + // code has been generated. This is used for constant area fixups. + AssemblerFixup* fixup_; + + explicit Operand(Register reg) : fixup_(nullptr) { SetModRM(3, reg); } // Get the operand encoding byte at the given index. uint8_t encoding_at(int index_in) const { @@ -136,6 +148,11 @@ class Address : public Operand { Init(base_in, disp); } + Address(Register base_in, int32_t disp, AssemblerFixup *fixup) { + Init(base_in, disp); + SetFixup(fixup); + } + Address(Register base_in, Offset disp) { Init(base_in, disp.Int32Value()); } @@ -226,6 +243,50 @@ class NearLabel : private Label { DISALLOW_COPY_AND_ASSIGN(NearLabel); }; +/** + * Class to handle constant area values. + */ +class ConstantArea { + public: + ConstantArea() {} + + // Add a double to the constant area, returning the offset into + // the constant area where the literal resides. + int AddDouble(double v); + + // Add a float to the constant area, returning the offset into + // the constant area where the literal resides. + int AddFloat(float v); + + // Add an int32_t to the constant area, returning the offset into + // the constant area where the literal resides. + int AddInt32(int32_t v); + + // Add an int64_t to the constant area, returning the offset into + // the constant area where the literal resides. + int AddInt64(int64_t v); + + bool IsEmpty() const { + return buffer_.size() == 0; + } + + const std::vector<int32_t>& GetBuffer() const { + return buffer_; + } + + void AddFixup(AssemblerFixup* fixup) { + fixups_.push_back(fixup); + } + + const std::vector<AssemblerFixup*>& GetFixups() const { + return fixups_; + } + + private: + static constexpr size_t kEntrySize = sizeof(int32_t); + std::vector<int32_t> buffer_; + std::vector<AssemblerFixup*> fixups_; +}; class X86Assembler FINAL : public Assembler { public: @@ -667,6 +728,29 @@ class X86Assembler FINAL : public Assembler { } } + // Add a double to the constant area, returning the offset into + // the constant area where the literal resides. + int AddDouble(double v) { return constant_area_.AddDouble(v); } + + // Add a float to the constant area, returning the offset into + // the constant area where the literal resides. + int AddFloat(float v) { return constant_area_.AddFloat(v); } + + // Add an int32_t to the constant area, returning the offset into + // the constant area where the literal resides. + int AddInt32(int32_t v) { return constant_area_.AddInt32(v); } + + // Add an int64_t to the constant area, returning the offset into + // the constant area where the literal resides. + int AddInt64(int64_t v) { return constant_area_.AddInt64(v); } + + // Add the contents of the constant area to the assembler buffer. + void AddConstantArea(); + + // Is the constant area empty? Return true if there are no literals in the constant area. + bool IsConstantAreaEmpty() const { return constant_area_.IsEmpty(); } + void AddConstantAreaFixup(AssemblerFixup* fixup) { constant_area_.AddFixup(fixup); } + private: inline void EmitUint8(uint8_t value); inline void EmitInt32(int32_t value); @@ -685,6 +769,8 @@ class X86Assembler FINAL : public Assembler { void EmitGenericShift(int rm, const Operand& operand, const Immediate& imm); void EmitGenericShift(int rm, const Operand& operand, Register shifter); + ConstantArea constant_area_; + DISALLOW_COPY_AND_ASSIGN(X86Assembler); }; |