diff options
author | 2016-01-25 14:47:50 +0000 | |
---|---|---|
committer | 2016-02-04 12:59:22 -0500 | |
commit | 2f10a5fb8c236a6786928f0323bd312c3ee9a4cc (patch) | |
tree | 0dc51717b1f5d9b2c20898c5283467d4feb220e2 | |
parent | a20748aceb63396c5e09366968bbc71308f745df (diff) |
Revert "Revert "X86: Use the constant area for more operations.""
This reverts commit cf8d1bb97e193e02b430d707d3b669565fababb4.
Handle the case of an intrinsic where CurrentMethod is still an input.
This will be the case when there are unresolved classes in the
hierarchy.
Add a test case to confirm that we don't crash when handling Math.abs,
which wants to add a pointer to the constant area for the bitmask to be
used to remove the sign bit.
Enhance 565-checker-condition-liveness to check for the case of deeply
nested EmitAtUseSite chains.
Change-Id: I022e8b96a32f5bf464331d0c318c56b9d0ac3c9a
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 88 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 116 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/nodes_x86.h | 19 | ||||
-rw-r--r-- | compiler/optimizing/pc_relative_fixups_x86.cc | 77 | ||||
-rw-r--r-- | test/458-checker-instruction-simplification/src/Main.java | 4 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/build | 46 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/expected.txt | 0 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/info.txt | 2 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/run | 18 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/src/Main.java | 41 | ||||
-rw-r--r-- | test/555-checker-regression-x86const/src/Unresolved.java | 18 | ||||
-rw-r--r-- | test/565-checker-condition-liveness/src/Main.java | 18 |
14 files changed, 403 insertions, 47 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index da054baa1c..6304fb503d 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1389,6 +1389,40 @@ void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, __ j(final_condition, true_label); } +void InstructionCodeGeneratorX86::GenerateFPCompare(Location lhs, + Location rhs, + HInstruction* insn, + bool is_double) { + HX86LoadFromConstantTable* const_area = insn->InputAt(1)->AsX86LoadFromConstantTable(); + if (is_double) { + if (rhs.IsFpuRegister()) { + __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); + } else if (const_area != nullptr) { + DCHECK(const_area->IsEmittedAtUseSite()); + __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), + codegen_->LiteralDoubleAddress( + const_area->GetConstant()->AsDoubleConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(rhs.IsDoubleStackSlot()); + __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex())); + } + } else { + if (rhs.IsFpuRegister()) { + __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); + } else if (const_area != nullptr) { + DCHECK(const_area->IsEmittedAtUseSite()); + __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), + codegen_->LiteralFloatAddress( + const_area->GetConstant()->AsFloatConstant()->GetValue(), + const_area->GetLocations()->InAt(0).AsRegister<Register>())); + } else { + DCHECK(rhs.IsStackSlot()); + __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex())); + } + } +} + template<class LabelType> void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condition, LabelType* true_target_in, @@ -1409,11 +1443,11 @@ void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condi GenerateLongComparesAndJumps(condition, true_target, false_target); break; case Primitive::kPrimFloat: - __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(left, right, condition, false); GenerateFPJumps(condition, true_target, false_target); break; case Primitive::kPrimDouble: - __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(left, right, condition, true); GenerateFPJumps(condition, true_target, false_target); break; default: @@ -1665,7 +1699,13 @@ void LocationsBuilderX86::HandleCondition(HCondition* cond) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + if (cond->InputAt(1)->IsX86LoadFromConstantTable()) { + DCHECK(cond->InputAt(1)->IsEmittedAtUseSite()); + } else if (cond->InputAt(1)->IsConstant()) { + locations->SetInAt(1, Location::RequiresFpuRegister()); + } else { + locations->SetInAt(1, Location::Any()); + } if (!cond->IsEmittedAtUseSite()) { locations->SetOut(Location::RequiresRegister()); } @@ -1719,11 +1759,11 @@ void InstructionCodeGeneratorX86::HandleCondition(HCondition* cond) { GenerateLongComparesAndJumps(cond, &true_label, &false_label); break; case Primitive::kPrimFloat: - __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(lhs, rhs, cond, false); GenerateFPJumps(cond, &true_label, &false_label); break; case Primitive::kPrimDouble: - __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(lhs, rhs, cond, true); GenerateFPJumps(cond, &true_label, &false_label); break; } @@ -2159,6 +2199,32 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { } } +void LocationsBuilderX86::VisitX86FPNeg(HX86FPNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + DCHECK(Primitive::IsFloatingPointType(neg->GetType())); + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresFpuRegister()); +} + +void InstructionCodeGeneratorX86::VisitX86FPNeg(HX86FPNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + DCHECK(locations->InAt(0).Equals(out)); + + Register constant_area = locations->InAt(1).AsRegister<Register>(); + XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + if (neg->GetType() == Primitive::kPrimFloat) { + __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x80000000), constant_area)); + __ xorps(out.AsFpuRegister<XmmRegister>(), mask); + } else { + __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000), constant_area)); + __ xorpd(out.AsFpuRegister<XmmRegister>(), mask); + } +} + void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { Primitive::Type result_type = conversion->GetResultType(); Primitive::Type input_type = conversion->GetInputType(); @@ -4086,7 +4152,13 @@ void LocationsBuilderX86::VisitCompare(HCompare* compare) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: { locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); + if (compare->InputAt(1)->IsX86LoadFromConstantTable()) { + DCHECK(compare->InputAt(1)->IsEmittedAtUseSite()); + } else if (compare->InputAt(1)->IsConstant()) { + locations->SetInAt(1, Location::RequiresFpuRegister()); + } else { + locations->SetInAt(1, Location::Any()); + } locations->SetOut(Location::RequiresRegister()); break; } @@ -4147,12 +4219,12 @@ void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) { break; } case Primitive::kPrimFloat: { - __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(left, right, compare, false); __ j(kUnordered, compare->IsGtBias() ? &greater : &less); break; } case Primitive::kPrimDouble: { - __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); + GenerateFPCompare(left, right, compare, true); __ j(kUnordered, compare->IsGtBias() ? &greater : &less); break; } diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 0aef478569..d51b96f85f 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -296,6 +296,8 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { HBasicBlock* switch_block, HBasicBlock* default_block); + void GenerateFPCompare(Location lhs, Location rhs, HInstruction* insn, bool is_double); + X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index acc40bc998..529f678761 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -37,10 +37,12 @@ namespace x86 { static constexpr int kDoubleNaNHigh = 0x7FF80000; static constexpr int kDoubleNaNLow = 0x00000000; -static constexpr int kFloatNaN = 0x7FC00000; +static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000); +static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000); IntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen) - : arena_(codegen->GetGraph()->GetArena()), codegen_(codegen) { + : arena_(codegen->GetGraph()->GetArena()), + codegen_(codegen) { } @@ -256,15 +258,37 @@ static void CreateFloatToFloat(ArenaAllocator* arena, HInvoke* invoke) { LocationSummary::kNoCall, kIntrinsified); locations->SetInAt(0, Location::RequiresFpuRegister()); - // TODO: Allow x86 to work with memory. This requires assembler support, see below. - // locations->SetInAt(0, Location::Any()); // X86 can work on memory directly. locations->SetOut(Location::SameAsFirstInput()); + HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect(); + DCHECK(static_or_direct != nullptr); + if (invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) { + // We need addressibility for the constant area. + locations->SetInAt(1, Location::RequiresRegister()); + // We need a temporary to hold the constant. + locations->AddTemp(Location::RequiresFpuRegister()); + } } -static void MathAbsFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) { +static void MathAbsFP(LocationSummary* locations, + bool is64bit, + X86Assembler* assembler, + CodeGeneratorX86* codegen) { Location output = locations->Out(); - if (output.IsFpuRegister()) { + DCHECK(output.IsFpuRegister()); + if (locations->InAt(1).IsValid()) { + DCHECK(locations->InAt(1).IsRegister()); + // We also have a constant area pointer. + Register constant_area = locations->InAt(1).AsRegister<Register>(); + XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); + if (is64bit) { + __ movsd(temp, codegen->LiteralInt64Address(INT64_C(0x7FFFFFFFFFFFFFFF), constant_area)); + __ andpd(output.AsFpuRegister<XmmRegister>(), temp); + } else { + __ movss(temp, codegen->LiteralInt32Address(INT32_C(0x7FFFFFFF), constant_area)); + __ andps(output.AsFpuRegister<XmmRegister>(), temp); + } + } else { // Create the right constant on an aligned stack. if (is64bit) { __ subl(ESP, Immediate(8)); @@ -277,19 +301,6 @@ static void MathAbsFP(LocationSummary* locations, bool is64bit, X86Assembler* as __ andps(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); } __ addl(ESP, Immediate(16)); - } else { - // TODO: update when assember support is available. - UNIMPLEMENTED(FATAL) << "Needs assembler support."; -// Once assembler support is available, in-memory operations look like this: -// if (is64bit) { -// DCHECK(output.IsDoubleStackSlot()); -// __ andl(Address(Register(RSP), output.GetHighStackIndex(kX86WordSize)), -// Immediate(0x7FFFFFFF)); -// } else { -// DCHECK(output.IsStackSlot()); -// // Can use and with a literal directly. -// __ andl(Address(Register(RSP), output.GetStackIndex()), Immediate(0x7FFFFFFF)); -// } } } @@ -298,7 +309,7 @@ void IntrinsicLocationsBuilderX86::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler(), codegen_); } void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) { @@ -306,7 +317,7 @@ void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler(), codegen_); } static void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) { @@ -388,8 +399,11 @@ void IntrinsicCodeGeneratorX86::VisitMathAbsLong(HInvoke* invoke) { GenAbsLong(invoke->GetLocations(), GetAssembler()); } -static void GenMinMaxFP(LocationSummary* locations, bool is_min, bool is_double, - X86Assembler* assembler) { +static void GenMinMaxFP(LocationSummary* locations, + bool is_min, + bool is_double, + X86Assembler* assembler, + CodeGeneratorX86* codegen) { Location op1_loc = locations->InAt(0); Location op2_loc = locations->InAt(1); Location out_loc = locations->Out(); @@ -450,15 +464,26 @@ static void GenMinMaxFP(LocationSummary* locations, bool is_min, bool is_double, // NaN handling. __ Bind(&nan); - if (is_double) { - __ pushl(Immediate(kDoubleNaNHigh)); - __ pushl(Immediate(kDoubleNaNLow)); - __ movsd(out, Address(ESP, 0)); - __ addl(ESP, Immediate(8)); + // Do we have a constant area pointer? + if (locations->InAt(2).IsValid()) { + DCHECK(locations->InAt(2).IsRegister()); + Register constant_area = locations->InAt(2).AsRegister<Register>(); + if (is_double) { + __ movsd(out, codegen->LiteralInt64Address(kDoubleNaN, constant_area)); + } else { + __ movss(out, codegen->LiteralInt32Address(kFloatNaN, constant_area)); + } } else { - __ pushl(Immediate(kFloatNaN)); - __ movss(out, Address(ESP, 0)); - __ addl(ESP, Immediate(4)); + if (is_double) { + __ pushl(Immediate(kDoubleNaNHigh)); + __ pushl(Immediate(kDoubleNaNLow)); + __ movsd(out, Address(ESP, 0)); + __ addl(ESP, Immediate(8)); + } else { + __ pushl(Immediate(kFloatNaN)); + __ movss(out, Address(ESP, 0)); + __ addl(ESP, Immediate(4)); + } } __ jmp(&done); @@ -483,6 +508,11 @@ static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { // The following is sub-optimal, but all we can do for now. It would be fine to also accept // the second input to be the output (we can simply swap inputs). locations->SetOut(Location::SameAsFirstInput()); + HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect(); + DCHECK(static_or_direct != nullptr); + if (invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) { + locations->SetInAt(2, Location::RequiresRegister()); + } } void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) { @@ -490,7 +520,11 @@ void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), + /* is_min */ true, + /* is_double */ true, + GetAssembler(), + codegen_); } void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) { @@ -498,7 +532,11 @@ void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), + /* is_min */ true, + /* is_double */ false, + GetAssembler(), + codegen_); } void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { @@ -506,7 +544,11 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), + /* is_min */ false, + /* is_double */ true, + GetAssembler(), + codegen_); } void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) { @@ -514,7 +556,11 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), + /* is_min */ false, + /* is_double */ false, + GetAssembler(), + codegen_); } static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long, diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index b8083477cf..6c63af71a3 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1259,6 +1259,7 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \ M(X86ComputeBaseMethodAddress, Instruction) \ M(X86LoadFromConstantTable, Instruction) \ + M(X86FPNeg, Instruction) \ M(X86PackedSwitch, Instruction) #endif diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h index b1bf939b36..0b3a84d3d3 100644 --- a/compiler/optimizing/nodes_x86.h +++ b/compiler/optimizing/nodes_x86.h @@ -56,6 +56,25 @@ class HX86LoadFromConstantTable : public HExpression<2> { DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable); }; +// Version of HNeg with access to the constant table for FP types. +class HX86FPNeg : public HExpression<2> { + public: + HX86FPNeg(Primitive::Type result_type, + HInstruction* input, + HX86ComputeBaseMethodAddress* method_base, + uint32_t dex_pc) + : HExpression(result_type, SideEffects::None(), dex_pc) { + DCHECK(Primitive::IsFloatingPointType(result_type)); + SetRawInputAt(0, input); + SetRawInputAt(1, method_base); + } + + DECLARE_INSTRUCTION(X86FPNeg); + + private: + DISALLOW_COPY_AND_ASSIGN(HX86FPNeg); +}; + // X86 version of HPackedSwitch that holds a pointer to the base method address. class HX86PackedSwitch : public HTemplateInstruction<2> { public: diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc index a2180bc9d7..a6f14616bf 100644 --- a/compiler/optimizing/pc_relative_fixups_x86.cc +++ b/compiler/optimizing/pc_relative_fixups_x86.cc @@ -53,6 +53,10 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { BinaryFP(div); } + void VisitCompare(HCompare* compare) OVERRIDE { + BinaryFP(compare); + } + void VisitReturn(HReturn* ret) OVERRIDE { HConstant* value = ret->InputAt(0)->AsConstant(); if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) { @@ -74,11 +78,50 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { void BinaryFP(HBinaryOperation* bin) { HConstant* rhs = bin->InputAt(1)->AsConstant(); - if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) { + if (rhs != nullptr && Primitive::IsFloatingPointType(rhs->GetType())) { ReplaceInput(bin, rhs, 1, false); } } + void VisitEqual(HEqual* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitNotEqual(HNotEqual* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitLessThan(HLessThan* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitLessThanOrEqual(HLessThanOrEqual* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitGreaterThan(HGreaterThan* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitGreaterThanOrEqual(HGreaterThanOrEqual* cond) OVERRIDE { + BinaryFP(cond); + } + + void VisitNeg(HNeg* neg) OVERRIDE { + if (Primitive::IsFloatingPointType(neg->GetType())) { + // We need to replace the HNeg with a HX86FPNeg in order to address the constant area. + InitializePCRelativeBasePointer(); + HGraph* graph = GetGraph(); + HBasicBlock* block = neg->GetBlock(); + HX86FPNeg* x86_fp_neg = new (graph->GetArena()) HX86FPNeg( + neg->GetType(), + neg->InputAt(0), + base_, + neg->GetDexPc()); + block->ReplaceAndRemoveInstructionWith(neg, x86_fp_neg); + } + } + void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE { if (switch_insn->GetNumEntries() <= InstructionCodeGeneratorX86::kPackedSwitchJumpTableThreshold) { @@ -127,12 +170,23 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { // If this is an invoke-static/-direct with PC-relative dex cache array // addressing, we need the PC-relative address base. HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect(); + // We can't add a pointer to the constant area if we already have a current + // method pointer. This may arise when sharpening doesn't remove the current + // method pointer from the invoke. + if (invoke_static_or_direct != nullptr && + invoke_static_or_direct->HasCurrentMethodInput()) { + DCHECK(!invoke_static_or_direct->HasPcRelativeDexCache()); + return; + } + + bool base_added = false; if (invoke_static_or_direct != nullptr && invoke_static_or_direct->HasPcRelativeDexCache()) { InitializePCRelativeBasePointer(); // Add the extra parameter base_. - DCHECK(!invoke_static_or_direct->HasCurrentMethodInput()); invoke_static_or_direct->AddSpecialInput(base_); + base_added = true; } + // 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(); @@ -140,6 +194,25 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { ReplaceInput(invoke, input, i, true); } } + + // These intrinsics need the constant area. + switch (invoke->GetIntrinsic()) { + case Intrinsics::kMathAbsDouble: + case Intrinsics::kMathAbsFloat: + case Intrinsics::kMathMaxDoubleDouble: + case Intrinsics::kMathMaxFloatFloat: + case Intrinsics::kMathMinDoubleDouble: + case Intrinsics::kMathMinFloatFloat: + if (!base_added) { + DCHECK(invoke_static_or_direct != nullptr); + DCHECK(!invoke_static_or_direct->HasCurrentMethodInput()); + InitializePCRelativeBasePointer(); + invoke_static_or_direct->AddSpecialInput(base_); + } + break; + default: + break; + } } // The generated HX86ComputeBaseMethodAddress in the entry block needed as an diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java index 3c8abeb841..2f80470cb3 100644 --- a/test/458-checker-instruction-simplification/src/Main.java +++ b/test/458-checker-instruction-simplification/src/Main.java @@ -1404,7 +1404,7 @@ public class Main { /// CHECK-START: int Main.floatConditionNotEqualOne(float) ssa_builder (after) /// CHECK: LessThanOrEqual - /// CHECK-START: int Main.floatConditionNotEqualOne(float) register (before) + /// CHECK-START: int Main.floatConditionNotEqualOne(float) instruction_simplifier_before_codegen (after) /// CHECK-DAG: <<Arg:f\d+>> ParameterValue /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 /// CHECK-DAG: <<Const54:i\d+>> IntConstant 54 @@ -1420,7 +1420,7 @@ public class Main { /// CHECK-START: int Main.doubleConditionEqualZero(double) ssa_builder (after) /// CHECK: LessThanOrEqual - /// CHECK-START: int Main.doubleConditionEqualZero(double) register (before) + /// CHECK-START: int Main.doubleConditionEqualZero(double) instruction_simplifier_before_codegen (after) /// CHECK-DAG: <<Arg:d\d+>> ParameterValue /// CHECK-DAG: <<Const13:i\d+>> IntConstant 13 /// CHECK-DAG: <<Const54:i\d+>> IntConstant 54 diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build new file mode 100644 index 0000000000..09dcc363dd --- /dev/null +++ b/test/555-checker-regression-x86const/build @@ -0,0 +1,46 @@ +#!/bin/bash +# +# 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. + +# Stop if something fails. +set -e + +# We can't use src-ex testing infrastructure because src and src-ex are compiled +# with javac independetely and can't share code (without reflection). + +mkdir classes +${JAVAC} -d classes `find src -name '*.java'` + +mkdir classes-ex +mv classes/UnresolvedClass.class classes-ex + +if [ ${USE_JACK} = "true" ]; then + # Create .jack files from classes generated with javac. + ${JILL} classes --output classes.jack + ${JILL} classes-ex --output classes-ex.jack + + # Create DEX files from .jack files. + ${JACK} --import classes.jack --output-dex . + zip $TEST_NAME.jar classes.dex + ${JACK} --import classes-ex.jack --output-dex . + zip ${TEST_NAME}-ex.jar classes.dex +else + if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes + zip $TEST_NAME.jar classes.dex + ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex + zip ${TEST_NAME}-ex.jar classes.dex + fi +fi diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/555-checker-regression-x86const/expected.txt diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt new file mode 100644 index 0000000000..c4037fa88f --- /dev/null +++ b/test/555-checker-regression-x86const/info.txt @@ -0,0 +1,2 @@ +Check that X86 FP constant-area handling handles intrinsics with CurrentMethod +on the call. diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run new file mode 100644 index 0000000000..63fdb8c749 --- /dev/null +++ b/test/555-checker-regression-x86const/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# 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. + +# Use secondary switch to add secondary dex file to class path. +exec ${RUN} "${@}" --secondary diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java new file mode 100644 index 0000000000..914cfde74f --- /dev/null +++ b/test/555-checker-regression-x86const/src/Main.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main extends UnresolvedClass { + + /// CHECK-START: float Main.callAbs(float) register (before) + /// CHECK: <<CurrentMethod:[ij]\d+>> CurrentMethod + /// CHECK: <<ParamValue:f\d+>> ParameterValue + /// CHECK: InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs + static public float callAbs(float f) { + // An intrinsic invoke in a method that has unresolved references will still + // have a CurrentMethod as an argument. The X86 pc_relative_fixups_x86 pass + // must be able to handle Math.abs invokes that have a CurrentMethod, as both + // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask) + // expect to be in the 'SpecialInputIndex' input index. + return Math.abs(f); + } + + static public void main(String[] args) { + expectEquals(callAbs(-6.5f), 6.5f); + } + + public static void expectEquals(float expected, float result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java new file mode 100644 index 0000000000..e98bdbf8fb --- /dev/null +++ b/test/555-checker-regression-x86const/src/Unresolved.java @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2016 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. + */ + +class UnresolvedClass { +} diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java index a811e5bb16..dc4cb76258 100644 --- a/test/565-checker-condition-liveness/src/Main.java +++ b/test/565-checker-condition-liveness/src/Main.java @@ -16,6 +16,24 @@ public class Main { + /// CHECK-START-X86: int Main.p(float) liveness (after) + /// CHECK: <<Arg:f\d+>> ParameterValue uses:[<<UseInput:\d+>>] + /// CHECK-DAG: <<Five:f\d+>> FloatConstant 5 uses:[<<UseInput>>] + /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 + /// CHECK-DAG: <<MinusOne:i\d+>> IntConstant -1 uses:[<<UseInput>>] + /// CHECK: <<Base:i\d+>> X86ComputeBaseMethodAddress uses:[<<UseInput>>] + /// CHECK-NEXT: <<Load:f\d+>> X86LoadFromConstantTable [<<Base>>,<<Five>>] + /// CHECK-NEXT: <<Cond:z\d+>> LessThanOrEqual [<<Arg>>,<<Load>>] + /// CHECK-NEXT: Select [<<Zero>>,<<MinusOne>>,<<Cond>>] liveness:<<LivSel:\d+>> + /// CHECK-EVAL: <<UseInput>> == <<LivSel>> + 1 + + public static int p(float arg) { + if (arg > 5.0f) { + return 0; + } + return -1; + } + /// CHECK-START: void Main.main(java.lang.String[]) liveness (after) /// CHECK: <<X:i\d+>> ArrayLength uses:[<<UseInput:\d+>>] /// CHECK: <<Y:i\d+>> StaticFieldGet uses:[<<UseInput>>] |