diff options
author | 2018-09-28 12:09:52 +0000 | |
---|---|---|
committer | 2018-09-28 12:09:52 +0000 | |
commit | 0de9c08aefc2465fd1d2fcedec3d3fa2164056fe (patch) | |
tree | 4c88b795d07b57ebef23accb87523600e8e217fe /compiler/optimizing | |
parent | 91be58aaa16ecf36642d9c274d48885c84f09f9d (diff) | |
parent | 76d4bb0f3d460671982bf40b9a9365e236501d80 (diff) |
Merge "Remove need for intrinsic recognizer to be a pass."
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/inliner.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.cc | 173 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.h | 22 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 73 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 7 | ||||
-rw-r--r-- | compiler/optimizing/optimization.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/optimization.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 |
8 files changed, 83 insertions, 217 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 1be96fbd50..7f94a298eb 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1296,9 +1296,7 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, // If invoke_instruction is devirtualized to a different method, give intrinsics // another chance before we try to inline it. - bool wrong_invoke_type = false; - if (invoke_instruction->GetResolvedMethod() != method && - IntrinsicsRecognizer::Recognize(invoke_instruction, method, &wrong_invoke_type)) { + if (invoke_instruction->GetResolvedMethod() != method && method->IsIntrinsic()) { MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized); if (invoke_instruction->IsInvokeInterface()) { // We don't intrinsify an invoke-interface directly. @@ -1311,6 +1309,7 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, invoke_instruction->GetDexMethodIndex(), // Use interface method's dex method index. method, method->GetMethodIndex()); + DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone); HInputsRef inputs = invoke_instruction->GetInputs(); for (size_t index = 0; index != inputs.size(); ++index) { new_invoke->SetArgumentAt(index, inputs[index]); @@ -1320,14 +1319,11 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, if (invoke_instruction->GetType() == DataType::Type::kReference) { new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo()); } - // Run intrinsic recognizer again to set new_invoke's intrinsic. - IntrinsicsRecognizer::Recognize(new_invoke, method, &wrong_invoke_type); - DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone); return_replacement = new_invoke; // invoke_instruction is replaced with new_invoke. should_remove_invoke_instruction = true; } else { - // invoke_instruction is intrinsified and stays. + invoke_instruction->SetResolvedMethod(method); } } else if (!TryBuildAndInline(invoke_instruction, method, receiver_type, &return_replacement)) { if (invoke_instruction->IsInvokeInterface()) { @@ -2023,10 +2019,8 @@ void HInliner::RunOptimizations(HGraph* callee_graph, HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner"); HConstantFolding fold(callee_graph, "constant_folding$inliner"); InstructionSimplifier simplify(callee_graph, codegen_, inline_stats_); - IntrinsicsRecognizer intrinsics(callee_graph, inline_stats_); HOptimization* optimizations[] = { - &intrinsics, &simplify, &fold, &dce, diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 21efe11f31..619cd8ed41 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -32,179 +32,6 @@ namespace art { -// Check that intrinsic enum values fit within space set aside in ArtMethod modifier flags. -#define CHECK_INTRINSICS_ENUM_VALUES(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \ - static_assert( \ - static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \ - "Instrinsics enumeration space overflow."); -#include "intrinsics_list.h" - INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES) -#undef INTRINSICS_LIST -#undef CHECK_INTRINSICS_ENUM_VALUES - -// Function that returns whether an intrinsic is static/direct or virtual. -static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) { - switch (i) { - case Intrinsics::kNone: - return kInterface; // Non-sensical for intrinsic. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \ - case Intrinsics::k ## Name: \ - return IsStatic; -#include "intrinsics_list.h" - INTRINSICS_LIST(OPTIMIZING_INTRINSICS) -#undef INTRINSICS_LIST -#undef OPTIMIZING_INTRINSICS - } - return kInterface; -} - -// Function that returns whether an intrinsic needs an environment or not. -static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCache(Intrinsics i) { - switch (i) { - case Intrinsics::kNone: - return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \ - case Intrinsics::k ## Name: \ - return NeedsEnvironmentOrCache; -#include "intrinsics_list.h" - INTRINSICS_LIST(OPTIMIZING_INTRINSICS) -#undef INTRINSICS_LIST -#undef OPTIMIZING_INTRINSICS - } - return kNeedsEnvironmentOrCache; -} - -// Function that returns whether an intrinsic has side effects. -static inline IntrinsicSideEffects GetSideEffects(Intrinsics i) { - switch (i) { - case Intrinsics::kNone: - return kAllSideEffects; -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \ - case Intrinsics::k ## Name: \ - return SideEffects; -#include "intrinsics_list.h" - INTRINSICS_LIST(OPTIMIZING_INTRINSICS) -#undef INTRINSICS_LIST -#undef OPTIMIZING_INTRINSICS - } - return kAllSideEffects; -} - -// Function that returns whether an intrinsic can throw exceptions. -static inline IntrinsicExceptions GetExceptions(Intrinsics i) { - switch (i) { - case Intrinsics::kNone: - return kCanThrow; -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \ - case Intrinsics::k ## Name: \ - return Exceptions; -#include "intrinsics_list.h" - INTRINSICS_LIST(OPTIMIZING_INTRINSICS) -#undef INTRINSICS_LIST -#undef OPTIMIZING_INTRINSICS - } - return kCanThrow; -} - -static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) - REQUIRES_SHARED(Locks::mutator_lock_) { - // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual. - // - // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization - // failure occured. We might be in a situation where we have inlined a method that calls an - // intrinsic, but that method is in a different dex file on which we do not have a - // verified_method that would have helped the compiler driver sharpen the call. In that case, - // make sure that the intrinsic is actually for some final method (or in a final class), as - // otherwise the intrinsics setup is broken. - // - // For the last direction, we have intrinsics for virtual functions that will perform a check - // inline. If the precise type is known, however, the instruction will be sharpened to an - // InvokeStaticOrDirect. - InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic); - InvokeType invoke_type = invoke->GetInvokeType(); - - switch (intrinsic_type) { - case kStatic: - return (invoke_type == kStatic); - - case kDirect: - if (invoke_type == kDirect) { - return true; - } - if (invoke_type == kVirtual) { - ArtMethod* art_method = invoke->GetResolvedMethod(); - return (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal()); - } - return false; - - case kVirtual: - // Call might be devirtualized. - return (invoke_type == kVirtual || invoke_type == kDirect || invoke_type == kInterface); - - case kSuper: - case kInterface: - case kPolymorphic: - case kCustom: - return false; - } - LOG(FATAL) << "Unknown intrinsic invoke type: " << intrinsic_type; - UNREACHABLE(); -} - -bool IntrinsicsRecognizer::Recognize(HInvoke* invoke, - ArtMethod* art_method, - /*out*/ bool* wrong_invoke_type) { - if (art_method == nullptr) { - art_method = invoke->GetResolvedMethod(); - } - *wrong_invoke_type = false; - if (art_method == nullptr || !art_method->IsIntrinsic()) { - return false; - } - - // TODO: b/65872996 The intent is that polymorphic signature methods should - // be compiler intrinsics. At present, they are only interpreter intrinsics. - if (art_method->IsPolymorphicSignature()) { - return false; - } - - Intrinsics intrinsic = static_cast<Intrinsics>(art_method->GetIntrinsic()); - if (CheckInvokeType(intrinsic, invoke) == false) { - *wrong_invoke_type = true; - return false; - } - - invoke->SetIntrinsic(intrinsic, - NeedsEnvironmentOrCache(intrinsic), - GetSideEffects(intrinsic), - GetExceptions(intrinsic)); - return true; -} - -bool IntrinsicsRecognizer::Run() { - bool didRecognize = false; - ScopedObjectAccess soa(Thread::Current()); - for (HBasicBlock* block : graph_->GetReversePostOrder()) { - for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done(); - inst_it.Advance()) { - HInstruction* inst = inst_it.Current(); - if (inst->IsInvoke()) { - bool wrong_invoke_type = false; - if (Recognize(inst->AsInvoke(), /* art_method */ nullptr, &wrong_invoke_type)) { - didRecognize = true; - MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized); - } else if (wrong_invoke_type) { - LOG(WARNING) - << "Found an intrinsic with unexpected invoke type: " - << inst->AsInvoke()->GetResolvedMethod()->PrettyMethod() << " " - << inst->DebugName(); - } - } - } - } - return didRecognize; -} - std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) { switch (intrinsic) { case Intrinsics::kNone: diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index 2d93f234be..59012faea7 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -34,28 +34,6 @@ static constexpr uint64_t kPositiveInfinityDouble = UINT64_C(0x7ff0000000000000) static constexpr uint32_t kNanFloat = 0x7fc00000U; static constexpr uint64_t kNanDouble = 0x7ff8000000000000; -// Recognize intrinsics from HInvoke nodes. -class IntrinsicsRecognizer : public HOptimization { - public: - IntrinsicsRecognizer(HGraph* graph, - OptimizingCompilerStats* stats, - const char* name = kIntrinsicsRecognizerPassName) - : HOptimization(graph, name, stats) {} - - bool Run() override; - - // Static helper that recognizes intrinsic call. Returns true on success. - // If it fails due to invoke type mismatch, wrong_invoke_type is set. - // Useful to recognize intrinsics on individual calls outside this full pass. - static bool Recognize(HInvoke* invoke, ArtMethod* method, /*out*/ bool* wrong_invoke_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition"; - - private: - DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer); -}; - class IntrinsicVisitor : public ValueObject { public: virtual ~IntrinsicVisitor() {} diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 79a7e2c858..aad06b91b6 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -3180,4 +3180,77 @@ std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind) { } } +// Check that intrinsic enum values fit within space set aside in ArtMethod modifier flags. +#define CHECK_INTRINSICS_ENUM_VALUES(Name, InvokeType, _, SideEffects, Exceptions, ...) \ + static_assert( \ + static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \ + "Instrinsics enumeration space overflow."); +#include "intrinsics_list.h" + INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES) +#undef INTRINSICS_LIST +#undef CHECK_INTRINSICS_ENUM_VALUES + +// Function that returns whether an intrinsic needs an environment or not. +static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCacheIntrinsic(Intrinsics i) { + switch (i) { + case Intrinsics::kNone: + return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic. +#define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnvOrCache, SideEffects, Exceptions, ...) \ + case Intrinsics::k ## Name: \ + return NeedsEnvOrCache; +#include "intrinsics_list.h" + INTRINSICS_LIST(OPTIMIZING_INTRINSICS) +#undef INTRINSICS_LIST +#undef OPTIMIZING_INTRINSICS + } + return kNeedsEnvironmentOrCache; +} + +// Function that returns whether an intrinsic has side effects. +static inline IntrinsicSideEffects GetSideEffectsIntrinsic(Intrinsics i) { + switch (i) { + case Intrinsics::kNone: + return kAllSideEffects; +#define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnvOrCache, SideEffects, Exceptions, ...) \ + case Intrinsics::k ## Name: \ + return SideEffects; +#include "intrinsics_list.h" + INTRINSICS_LIST(OPTIMIZING_INTRINSICS) +#undef INTRINSICS_LIST +#undef OPTIMIZING_INTRINSICS + } + return kAllSideEffects; +} + +// Function that returns whether an intrinsic can throw exceptions. +static inline IntrinsicExceptions GetExceptionsIntrinsic(Intrinsics i) { + switch (i) { + case Intrinsics::kNone: + return kCanThrow; +#define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnvOrCache, SideEffects, Exceptions, ...) \ + case Intrinsics::k ## Name: \ + return Exceptions; +#include "intrinsics_list.h" + INTRINSICS_LIST(OPTIMIZING_INTRINSICS) +#undef INTRINSICS_LIST +#undef OPTIMIZING_INTRINSICS + } + return kCanThrow; +} + +void HInvoke::SetResolvedMethod(ArtMethod* method) { + // TODO: b/65872996 The intent is that polymorphic signature methods should + // be compiler intrinsics. At present, they are only interpreter intrinsics. + if (method != nullptr && + method->IsIntrinsic() && + !method->IsPolymorphicSignature()) { + Intrinsics intrinsic = static_cast<Intrinsics>(method->GetIntrinsic()); + SetIntrinsic(intrinsic, + NeedsEnvironmentOrCacheIntrinsic(intrinsic), + GetSideEffectsIntrinsic(intrinsic), + GetExceptionsIntrinsic(intrinsic)); + } + resolved_method_ = method; +} + } // namespace art diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 76887f9a5b..daf86fd8f2 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -29,6 +29,7 @@ #include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/transform_array_ref.h" +#include "art_method.h" #include "data_type.h" #include "deoptimization_kind.h" #include "dex/dex_file.h" @@ -4323,7 +4324,7 @@ class HInvoke : public HVariableInputSizeInstruction { bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; } ArtMethod* GetResolvedMethod() const { return resolved_method_; } - void SetResolvedMethod(ArtMethod* method) { resolved_method_ = method; } + void SetResolvedMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); DECLARE_ABSTRACT_INSTRUCTION(Invoke); @@ -4355,12 +4356,14 @@ class HInvoke : public HVariableInputSizeInstruction { number_of_arguments + number_of_other_inputs, kArenaAllocInvokeInputs), number_of_arguments_(number_of_arguments), - resolved_method_(resolved_method), dex_method_index_(dex_method_index), intrinsic_(Intrinsics::kNone), intrinsic_optimizations_(0) { SetPackedField<InvokeTypeField>(invoke_type); SetPackedFlag<kFlagCanThrow>(true); + // Check mutator lock, constructors lack annotalysis support. + Locks::mutator_lock_->AssertNotExclusiveHeld(Thread::Current()); + SetResolvedMethod(resolved_method); } DEFAULT_COPY_CONSTRUCTOR(Invoke); diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 75466a3cba..4b0941b4ff 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -88,8 +88,6 @@ const char* OptimizationPassName(OptimizationPass pass) { return HSelectGenerator::kSelectGeneratorPassName; case OptimizationPass::kInstructionSimplifier: return InstructionSimplifier::kInstructionSimplifierPassName; - case OptimizationPass::kIntrinsicsRecognizer: - return IntrinsicsRecognizer::kIntrinsicsRecognizerPassName; case OptimizationPass::kCHAGuardOptimization: return CHAGuardOptimization::kCHAGuardOptimizationPassName; case OptimizationPass::kCodeSinking: @@ -139,7 +137,6 @@ OptimizationPass OptimizationPassByName(const std::string& pass_name) { X(OptimizationPass::kInductionVarAnalysis); X(OptimizationPass::kInliner); X(OptimizationPass::kInstructionSimplifier); - X(OptimizationPass::kIntrinsicsRecognizer); X(OptimizationPass::kInvariantCodeMotion); X(OptimizationPass::kLoadStoreAnalysis); X(OptimizationPass::kLoadStoreElimination); @@ -267,9 +264,6 @@ ArenaVector<HOptimization*> ConstructOptimizations( case OptimizationPass::kInstructionSimplifier: opt = new (allocator) InstructionSimplifier(graph, codegen, stats, pass_name); break; - case OptimizationPass::kIntrinsicsRecognizer: - opt = new (allocator) IntrinsicsRecognizer(graph, stats, pass_name); - break; case OptimizationPass::kCHAGuardOptimization: opt = new (allocator) CHAGuardOptimization(graph, pass_name); break; diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index c258d516de..ced383fdd6 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -77,7 +77,6 @@ enum class OptimizationPass { kInductionVarAnalysis, kInliner, kInstructionSimplifier, - kIntrinsicsRecognizer, kInvariantCodeMotion, kLoadStoreAnalysis, kLoadStoreElimination, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 3a550efeb8..7d339cd120 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -624,7 +624,6 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph, OptimizationDef optimizations[] = { // Initial optimizations. - OptDef(OptimizationPass::kIntrinsicsRecognizer), OptDef(OptimizationPass::kConstantFolding), OptDef(OptimizationPass::kInstructionSimplifier), OptDef(OptimizationPass::kDeadCodeElimination, @@ -945,9 +944,8 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( } OptimizationDef optimizations[] = { - OptDef(OptimizationPass::kIntrinsicsRecognizer), - // Some intrinsics are converted to HIR by the simplifier and the codegen also - // has a few assumptions that only the instruction simplifier can satisfy. + // The codegen has a few assumptions that only the instruction simplifier + // can satisfy. OptDef(OptimizationPass::kInstructionSimplifier), }; RunOptimizations(graph, |