summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
author Brian Carlstrom <bdc@google.com> 2014-02-25 04:42:53 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2014-02-25 04:42:54 +0000
commitfffb0b7e23796e5470f4fab4611f2fcc4a16979c (patch)
tree3c2fd045f635a0511149272af9ff55a01a31b83c /compiler
parenta0c9b085d4ecf90ca3aa1252e81e65072b377ca4 (diff)
parent6449c62e40ef3a9bb75f664f922555affb532ee4 (diff)
Merge "Create CompilerOptions"
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/frontend.cc2
-rw-r--r--compiler/dex/mir_analysis.cc39
-rw-r--r--compiler/dex/mir_graph.h2
-rw-r--r--compiler/dex/verification_results.cc20
-rw-r--r--compiler/dex/verification_results.h12
-rw-r--r--compiler/driver/compiler_callbacks_impl.h59
-rw-r--r--compiler/driver/compiler_driver.cc11
-rw-r--r--compiler/driver/compiler_driver.h10
-rw-r--r--compiler/driver/compiler_options.h136
-rw-r--r--compiler/oat_test.cc9
10 files changed, 262 insertions, 38 deletions
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 591d92a73d..6800f7b2a4 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -211,7 +211,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler,
class_loader, dex_file);
cu.NewTimingSplit("MIROpt:CheckFilters");
- if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
+ if (cu.mir_graph->SkipCompilation()) {
return NULL;
}
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index ab55333fa7..7ce8f696be 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -18,6 +18,7 @@
#include "dataflow_iterator-inl.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "driver/compiler_options.h"
namespace art {
@@ -958,7 +959,7 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) {
}
// Complex, logic-intensive?
- if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) &&
+ if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) &&
stats->branch_ratio > 0.3) {
return false;
}
@@ -984,7 +985,7 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) {
}
// If significant in size and high proportion of expensive operations, skip.
- if ((GetNumDalvikInsns() > Runtime::Current()->GetSmallMethodThreshold()) &&
+ if (cu_->compiler_driver->GetCompilerOptions().IsSmallMethod(GetNumDalvikInsns()) &&
(stats->heavyweight_ratio > 0.3)) {
return true;
}
@@ -996,12 +997,14 @@ bool MIRGraph::ComputeSkipCompilation(MethodStats* stats, bool skip_default) {
* Will eventually want this to be a bit more sophisticated and happen at verification time.
* Ultimate goal is to drive with profile data.
*/
-bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) {
- if (compiler_filter == Runtime::kEverything) {
+bool MIRGraph::SkipCompilation() {
+ const CompilerOptions& compiler_options = cu_->compiler_driver->GetCompilerOptions();
+ CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
+ if (compiler_filter == CompilerOptions::kEverything) {
return false;
}
- if (compiler_filter == Runtime::kInterpretOnly) {
+ if (compiler_filter == CompilerOptions::kInterpretOnly) {
LOG(WARNING) << "InterpretOnly should ideally be filtered out prior to parsing.";
return true;
}
@@ -1010,17 +1013,17 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) {
size_t small_cutoff = 0;
size_t default_cutoff = 0;
switch (compiler_filter) {
- case Runtime::kBalanced:
- small_cutoff = Runtime::Current()->GetSmallMethodThreshold();
- default_cutoff = Runtime::Current()->GetLargeMethodThreshold();
+ case CompilerOptions::kBalanced:
+ small_cutoff = compiler_options.GetSmallMethodThreshold();
+ default_cutoff = compiler_options.GetLargeMethodThreshold();
break;
- case Runtime::kSpace:
- small_cutoff = Runtime::Current()->GetTinyMethodThreshold();
- default_cutoff = Runtime::Current()->GetSmallMethodThreshold();
+ case CompilerOptions::kSpace:
+ small_cutoff = compiler_options.GetTinyMethodThreshold();
+ default_cutoff = compiler_options.GetSmallMethodThreshold();
break;
- case Runtime::kSpeed:
- small_cutoff = Runtime::Current()->GetHugeMethodThreshold();
- default_cutoff = Runtime::Current()->GetHugeMethodThreshold();
+ case CompilerOptions::kSpeed:
+ small_cutoff = compiler_options.GetHugeMethodThreshold();
+ default_cutoff = compiler_options.GetHugeMethodThreshold();
break;
default:
LOG(FATAL) << "Unexpected compiler_filter_: " << compiler_filter;
@@ -1033,17 +1036,17 @@ bool MIRGraph::SkipCompilation(Runtime::CompilerFilter compiler_filter) {
* Filter 1: Huge methods are likely to be machine generated, but some aren't.
* If huge, assume we won't compile, but allow futher analysis to turn it back on.
*/
- if (GetNumDalvikInsns() > Runtime::Current()->GetHugeMethodThreshold()) {
+ if (compiler_options.IsHugeMethod(GetNumDalvikInsns())) {
skip_compilation = true;
// If we're got a huge number of basic blocks, don't bother with further analysis.
- if (static_cast<size_t>(num_blocks_) > (Runtime::Current()->GetHugeMethodThreshold() / 2)) {
+ if (static_cast<size_t>(num_blocks_) > (compiler_options.GetHugeMethodThreshold() / 2)) {
return true;
}
- } else if (GetNumDalvikInsns() > Runtime::Current()->GetLargeMethodThreshold() &&
+ } else if (compiler_options.IsLargeMethod(GetNumDalvikInsns()) &&
/* If it's large and contains no branches, it's likely to be machine generated initialization */
(GetBranchCount() == 0)) {
return true;
- } else if (compiler_filter == Runtime::kSpeed) {
+ } else if (compiler_filter == CompilerOptions::kSpeed) {
// If not huge, compile.
return false;
}
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index d844aac10b..2174f679bf 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -372,7 +372,7 @@ class MIRGraph {
* Examine the graph to determine whether it's worthwile to spend the time compiling
* this method.
*/
- bool SkipCompilation(Runtime::CompilerFilter compiler_filter);
+ bool SkipCompilation();
/*
* Parse dex method and add MIR at current insert point. Returns id (which is
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index edccec55ba..947c22d668 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -19,6 +19,8 @@
#include "base/stl_util.h"
#include "base/mutex.h"
#include "base/mutex-inl.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
#include "thread.h"
#include "thread-inl.h"
#include "verified_method.h"
@@ -27,8 +29,9 @@
namespace art {
-VerificationResults::VerificationResults()
- : verified_methods_lock_("compiler verified methods lock"),
+VerificationResults::VerificationResults(const CompilerOptions* compiler_options)
+ : compiler_options_(compiler_options),
+ verified_methods_lock_("compiler verified methods lock"),
verified_methods_(),
rejected_classes_lock_("compiler rejected classes lock"),
rejected_classes_() {
@@ -43,6 +46,7 @@ VerificationResults::~VerificationResults() {
}
bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
+ DCHECK(method_verifier != NULL);
MethodReference ref = method_verifier->GetMethodReference();
bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
// TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization.
@@ -95,16 +99,18 @@ bool VerificationResults::IsClassRejected(ClassReference ref) {
bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
const uint32_t access_flags) {
#ifdef ART_SEA_IR_MODE
- bool use_sea = Runtime::Current()->IsSeaIRMode();
- use_sea = use_sea && (std::string::npos != PrettyMethod(
- method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
- if (use_sea) return true;
+ bool use_sea = compiler_options_->GetSeaIrMode();
+ use_sea = use_sea && (std::string::npos != PrettyMethod(
+ method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
+ if (use_sea) {
+ return true;
+ }
#endif
// Don't compile class initializers, ever.
if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
return false;
}
- return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
+ return (compiler_options_->GetCompilerFilter() != CompilerOptions::kInterpretOnly);
}
} // namespace art
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 2eb07131ce..278182f2aa 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -33,11 +33,13 @@ namespace verifier {
class MethodVerifier;
} // namespace verifier
+class CompilerOptions;
class VerifiedMethod;
+// Used by CompilerCallbacks to track verification information from the Runtime.
class VerificationResults {
public:
- VerificationResults();
+ explicit VerificationResults(const CompilerOptions* compiler_options);
~VerificationResults();
bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
@@ -50,15 +52,17 @@ class VerificationResults {
void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
- static bool IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags);
+ bool IsCandidateForCompilation(MethodReference& method_ref,
+ const uint32_t access_flags);
private:
+ const CompilerOptions* compiler_options_;
+
// Verified methods.
typedef SafeMap<MethodReference, const VerifiedMethod*,
MethodReferenceComparator> VerifiedMethodMap;
ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- VerifiedMethodMap verified_methods_;
+ VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_);
// Rejected classes.
ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/compiler/driver/compiler_callbacks_impl.h b/compiler/driver/compiler_callbacks_impl.h
new file mode 100644
index 0000000000..ab57832961
--- /dev/null
+++ b/compiler/driver/compiler_callbacks_impl.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 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_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+#define ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+
+#include "compiler_callbacks.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "verifier/method_verifier-inl.h"
+
+namespace art {
+
+class CompilerCallbacksImpl : public CompilerCallbacks {
+ public:
+ CompilerCallbacksImpl(VerificationResults* verification_results,
+ DexFileToMethodInlinerMap* method_inliner_map)
+ : verification_results_(verification_results),
+ method_inliner_map_(method_inliner_map) {
+ CHECK(verification_results != nullptr);
+ CHECK(method_inliner_map != nullptr);
+ }
+
+ virtual ~CompilerCallbacksImpl() { }
+
+ virtual bool MethodVerified(verifier::MethodVerifier* verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ bool result = verification_results_->ProcessVerifiedMethod(verifier);
+ if (result) {
+ MethodReference ref = verifier->GetMethodReference();
+ method_inliner_map_->GetMethodInliner(ref.dex_file)
+ ->AnalyseMethodCode(verifier);
+ }
+ return result;
+ }
+ virtual void ClassRejected(ClassReference ref) {
+ verification_results_->AddRejectedClass(ref);
+ }
+
+ private:
+ VerificationResults* verification_results_;
+ DexFileToMethodInlinerMap* method_inliner_map_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 54397f5e31..1b284de9cc 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -293,14 +293,16 @@ extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler,
jobject class_loader,
const art::DexFile& dex_file);
-CompilerDriver::CompilerDriver(VerificationResults* verification_results,
+CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
+ VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend::Kind compiler_backend_kind,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
bool dump_stats, bool dump_passes, CumulativeLogger* timer)
- : verification_results_(verification_results),
+ : compiler_options_(compiler_options),
+ verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
compiler_backend_(CompilerBackend::Create(compiler_backend_kind)),
instruction_set_(instruction_set),
@@ -325,6 +327,9 @@ CompilerDriver::CompilerDriver(VerificationResults* verification_results,
dedupe_mapping_table_("dedupe mapping table"),
dedupe_vmap_table_("dedupe vmap table"),
dedupe_gc_map_("dedupe gc map") {
+ DCHECK(compiler_options_ != nullptr);
+ DCHECK(verification_results_ != nullptr);
+ DCHECK(method_inliner_map_ != nullptr);
CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
@@ -1932,7 +1937,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
} else {
MethodReference method_ref(&dex_file, method_idx);
- bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
+ bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
// NOTE: if compiler declines to compile this method, it will return NULL.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 092fe52b24..5009779bed 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -45,6 +45,7 @@ class MethodVerifier;
} // namespace verifier
class AOTCompilationStats;
+class CompilerOptions;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
class InlineIGetIPutData;
@@ -94,7 +95,8 @@ class CompilerDriver {
// enabled. "image_classes" lets the compiler know what classes it
// can assume will be in the image, with NULL implying all available
// classes.
- explicit CompilerDriver(VerificationResults* verification_results,
+ explicit CompilerDriver(const CompilerOptions* compiler_options,
+ VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend::Kind compiler_backend_kind,
InstructionSet instruction_set,
@@ -129,6 +131,11 @@ class CompilerDriver {
return instruction_set_features_;
}
+ const CompilerOptions& GetCompilerOptions() const {
+ DCHECK(compiler_options_ != nullptr);
+ return *compiler_options_;
+ }
+
CompilerBackend* GetCompilerBackend() const {
return compiler_backend_.get();
}
@@ -551,6 +558,7 @@ class CompilerDriver {
std::vector<const CallPatchInformation*> methods_to_patch_;
std::vector<const TypePatchInformation*> classes_to_patch_;
+ const CompilerOptions* compiler_options_;
VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
new file mode 100644
index 0000000000..9f6745b015
--- /dev/null
+++ b/compiler/driver/compiler_options.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 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_DRIVER_COMPILER_OPTIONS_H_
+#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
+
+namespace art {
+
+class CompilerOptions {
+ public:
+ enum CompilerFilter {
+ kInterpretOnly, // Compile nothing.
+ kSpace, // Maximize space savings.
+ kBalanced, // Try to get the best performance return on compilation investment.
+ kSpeed, // Maximize runtime performance.
+ kEverything // Force compilation (Note: excludes compilaton of class initializers).
+ };
+
+ // Guide heuristics to determine whether to compile method if profile data not available.
+ static const CompilerFilter kDefaultCompilerFilter = kSpeed;
+ static const size_t kDefaultHugeMethodThreshold = 10000;
+ static const size_t kDefaultLargeMethodThreshold = 600;
+ static const size_t kDefaultSmallMethodThreshold = 60;
+ static const size_t kDefaultTinyMethodThreshold = 20;
+ static const size_t kDefaultNumDexMethodsThreshold = 900;
+
+ CompilerOptions() :
+ compiler_filter_(kDefaultCompilerFilter),
+ huge_method_threshold_(kDefaultHugeMethodThreshold),
+ large_method_threshold_(kDefaultLargeMethodThreshold),
+ small_method_threshold_(kDefaultSmallMethodThreshold),
+ tiny_method_threshold_(kDefaultTinyMethodThreshold),
+ num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+#ifdef ART_SEA_IR_MODE
+ , sea_ir_mode_(false)
+#endif
+ {}
+
+ CompilerOptions(CompilerFilter compiler_filter,
+ size_t huge_method_threshold,
+ size_t large_method_threshold,
+ size_t small_method_threshold,
+ size_t tiny_method_threshold,
+ size_t num_dex_methods_threshold
+#ifdef ART_SEA_IR_MODE
+ , bool sea_ir_mode
+#endif
+ ) : // NOLINT(whitespace/parens)
+ compiler_filter_(compiler_filter),
+ huge_method_threshold_(huge_method_threshold),
+ large_method_threshold_(large_method_threshold),
+ small_method_threshold_(small_method_threshold),
+ tiny_method_threshold_(tiny_method_threshold),
+ num_dex_methods_threshold_(num_dex_methods_threshold)
+#ifdef ART_SEA_IR_MODE
+ , sea_ir_mode_(sea_ir_mode)
+#endif
+ {}
+
+ CompilerFilter GetCompilerFilter() const {
+ return compiler_filter_;
+ }
+
+ void SetCompilerFilter(CompilerFilter compiler_filter) {
+ compiler_filter_ = compiler_filter;
+ }
+
+ size_t GetHugeMethodThreshold() const {
+ return huge_method_threshold_;
+ }
+
+ size_t GetLargeMethodThreshold() const {
+ return large_method_threshold_;
+ }
+
+ size_t GetSmallMethodThreshold() const {
+ return small_method_threshold_;
+ }
+
+ size_t GetTinyMethodThreshold() const {
+ return tiny_method_threshold_;
+ }
+
+ bool IsHugeMethod(size_t num_dalvik_instructions) const {
+ return num_dalvik_instructions > huge_method_threshold_;
+ }
+
+ bool IsLargeMethod(size_t num_dalvik_instructions) const {
+ return num_dalvik_instructions > large_method_threshold_;
+ }
+
+ bool IsSmallMethod(size_t num_dalvik_instructions) const {
+ return num_dalvik_instructions > small_method_threshold_;
+ }
+
+ bool IsTinyMethod(size_t num_dalvik_instructions) const {
+ return num_dalvik_instructions > tiny_method_threshold_;
+ }
+
+ size_t GetNumDexMethodsThreshold() const {
+ return num_dex_methods_threshold_;
+ }
+
+#ifdef ART_SEA_IR_MODE
+ bool GetSeaIrMode();
+#endif
+
+ private:
+ CompilerFilter compiler_filter_;
+ size_t huge_method_threshold_;
+ size_t large_method_threshold_;
+ size_t small_method_threshold_;
+ size_t tiny_method_threshold_;
+ size_t num_dex_methods_threshold_;
+
+#ifdef ART_SEA_IR_MODE
+ bool sea_ir_mode_;
+#endif
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index e9c77d1a02..e91ffcb519 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -91,11 +91,14 @@ TEST_F(OatTest, WriteRead) {
InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
InstructionSetFeatures insn_features;
- verification_results_.reset(new VerificationResults);
+ compiler_options_.reset(new CompilerOptions);
+ verification_results_.reset(new VerificationResults(compiler_options_.get()));
method_inliner_map_.reset(new DexFileToMethodInlinerMap);
- callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+ callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(),
+ method_inliner_map_.get()));
timer_.reset(new CumulativeLogger("Compilation times"));
- compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
+ compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
+ verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, insn_set,
insn_features, false, NULL, 2, true, true,