Remove need for intrinsic recognizer to be a pass.

Instead just recognize the intrinsic when creating an invoke
instruction.

Also remove some old code related to compiler driver sharpening.

Test: test.py
Change-Id: Iecb668f30e95034970fcf57160ca12092c9c610d
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 1be96fb..7f94a29 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1296,9 +1296,7 @@
 
   // 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 @@
           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 @@
       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 @@
   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 21efe11..619cd8e 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 2d93f23..59012fa 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -34,28 +34,6 @@
 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 79a7e2c..aad06b9 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -3180,4 +3180,77 @@
   }
 }
 
+// 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 68f1a24..4ae7915 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"
@@ -4322,7 +4323,7 @@
   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);
 
@@ -4354,12 +4355,14 @@
           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 75466a3..4b0941b 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -88,8 +88,6 @@
       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 @@
   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 @@
       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 c258d51..ced383f 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -77,7 +77,6 @@
   kInductionVarAnalysis,
   kInliner,
   kInstructionSimplifier,
-  kIntrinsicsRecognizer,
   kInvariantCodeMotion,
   kLoadStoreAnalysis,
   kLoadStoreElimination,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 9ae025b..95f2d03 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -623,7 +623,6 @@
 
   OptimizationDef optimizations[] = {
     // Initial optimizations.
-    OptDef(OptimizationPass::kIntrinsicsRecognizer),
     OptDef(OptimizationPass::kConstantFolding),
     OptDef(OptimizationPass::kInstructionSimplifier),
     OptDef(OptimizationPass::kDeadCodeElimination,
@@ -944,9 +943,8 @@
   }
 
   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,