e4196ce8c6
Second sub-CL of https://dart-review.googlesource.com/c/sdk/+/100644 The first was here https://dart-review.googlesource.com/c/sdk/+/103487 Now that offsets_extractor is checked in, and we have a big header full of hard coded constants, the next step is to make sure everything is using those constants. This is essentially everything in the original CL, except the new simarm_x64 architecture. Bug: https://github.com/dart-lang/sdk/issues/36839 Change-Id: I236e4f30aa1df6d92209891c983b792d1835b608 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104286 Commit-Queue: Liam Appelbe <liama@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
253 lines
8.2 KiB
C++
253 lines
8.2 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
// Class for intrinsifying functions.
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include "vm/compiler/intrinsifier.h"
|
|
|
|
#include "vm/compiler/assembler/assembler.h"
|
|
#include "vm/compiler/backend/flow_graph.h"
|
|
#include "vm/compiler/backend/flow_graph_compiler.h"
|
|
#include "vm/compiler/backend/il_printer.h"
|
|
#include "vm/compiler/backend/linearscan.h"
|
|
#include "vm/compiler/frontend/flow_graph_builder.h"
|
|
#include "vm/compiler/jit/compiler.h"
|
|
#include "vm/cpu.h"
|
|
#include "vm/flags.h"
|
|
#include "vm/object.h"
|
|
#include "vm/parser.h"
|
|
#include "vm/symbols.h"
|
|
|
|
namespace dart {
|
|
|
|
DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible");
|
|
DEFINE_FLAG(bool, trace_intrinsifier, false, "Trace intrinsifier");
|
|
|
|
namespace compiler {
|
|
|
|
bool Intrinsifier::CanIntrinsify(const Function& function) {
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("CanIntrinsify %s ->", function.ToQualifiedCString());
|
|
}
|
|
if (!FLAG_intrinsify) return false;
|
|
// TODO(regis): We do not need to explicitly filter generic functions here,
|
|
// unless there are errors we don't detect at link time. Revisit if necessary.
|
|
if (function.IsClosureFunction()) {
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("No, closure function.\n");
|
|
}
|
|
return false;
|
|
}
|
|
// Can occur because of compile-all flag.
|
|
if (function.is_external()) {
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("No, external function.\n");
|
|
}
|
|
return false;
|
|
}
|
|
if (!function.is_intrinsic()) {
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("No, not intrinsic function.\n");
|
|
}
|
|
return false;
|
|
}
|
|
switch (function.recognized_kind()) {
|
|
case MethodRecognizer::kInt64ArrayGetIndexed:
|
|
case MethodRecognizer::kInt64ArraySetIndexed:
|
|
case MethodRecognizer::kUint64ArrayGetIndexed:
|
|
case MethodRecognizer::kUint64ArraySetIndexed:
|
|
// TODO(ajcbik): consider 32-bit as well.
|
|
if (target::kBitsPerWord == 64 &&
|
|
FlowGraphCompiler::SupportsUnboxedInt64()) {
|
|
break;
|
|
}
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("No, 64-bit int intrinsic on 32-bit platform.\n");
|
|
}
|
|
return false;
|
|
default:
|
|
break;
|
|
}
|
|
if (FLAG_trace_intrinsifier) {
|
|
THR_Print("Yes.\n");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
struct IntrinsicDesc {
|
|
const char* class_name;
|
|
const char* function_name;
|
|
};
|
|
|
|
struct LibraryInstrinsicsDesc {
|
|
Library& library;
|
|
IntrinsicDesc* intrinsics;
|
|
};
|
|
|
|
#define DEFINE_INTRINSIC(class_name, function_name, destination, fp) \
|
|
{#class_name, #function_name},
|
|
|
|
// clang-format off
|
|
static IntrinsicDesc core_intrinsics[] = {
|
|
CORE_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
CORE_INTEGER_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
GRAPH_CORE_INTRINSICS_LIST(DEFINE_INTRINSIC)
|
|
{nullptr, nullptr},
|
|
};
|
|
|
|
static IntrinsicDesc math_intrinsics[] = {
|
|
MATH_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
GRAPH_MATH_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
{nullptr, nullptr},
|
|
};
|
|
|
|
static IntrinsicDesc typed_data_intrinsics[] = {
|
|
TYPED_DATA_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
GRAPH_TYPED_DATA_INTRINSICS_LIST(DEFINE_INTRINSIC)
|
|
{nullptr, nullptr},
|
|
};
|
|
|
|
static IntrinsicDesc developer_intrinsics[] = {
|
|
DEVELOPER_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
|
|
{nullptr, nullptr},
|
|
};
|
|
// clang-format on
|
|
|
|
void Intrinsifier::InitializeState() {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
Library& lib = Library::Handle(zone);
|
|
Class& cls = Class::Handle(zone);
|
|
Function& func = Function::Handle(zone);
|
|
String& str = String::Handle(zone);
|
|
String& str2 = String::Handle(zone);
|
|
Error& error = Error::Handle(zone);
|
|
|
|
static const intptr_t kNumLibs = 4;
|
|
LibraryInstrinsicsDesc intrinsics[kNumLibs] = {
|
|
{Library::Handle(zone, Library::CoreLibrary()), core_intrinsics},
|
|
{Library::Handle(zone, Library::MathLibrary()), math_intrinsics},
|
|
{Library::Handle(zone, Library::TypedDataLibrary()),
|
|
typed_data_intrinsics},
|
|
{Library::Handle(zone, Library::DeveloperLibrary()),
|
|
developer_intrinsics},
|
|
};
|
|
|
|
for (intptr_t i = 0; i < kNumLibs; i++) {
|
|
lib = intrinsics[i].library.raw();
|
|
for (IntrinsicDesc* intrinsic = intrinsics[i].intrinsics;
|
|
intrinsic->class_name != nullptr; intrinsic++) {
|
|
func = Function::null();
|
|
if (strcmp(intrinsic->class_name, "::") == 0) {
|
|
str = String::New(intrinsic->function_name);
|
|
func = lib.LookupFunctionAllowPrivate(str);
|
|
} else {
|
|
str = String::New(intrinsic->class_name);
|
|
cls = lib.LookupClassAllowPrivate(str);
|
|
ASSERT(FLAG_precompiled_mode || !cls.IsNull());
|
|
if (!cls.IsNull()) {
|
|
error = cls.EnsureIsFinalized(thread);
|
|
if (!error.IsNull()) {
|
|
OS::PrintErr("%s\n", error.ToErrorCString());
|
|
}
|
|
ASSERT(error.IsNull());
|
|
str = String::New(intrinsic->function_name);
|
|
if (intrinsic->function_name[0] == '.') {
|
|
str2 = String::New(intrinsic->class_name);
|
|
str = String::Concat(str2, str);
|
|
}
|
|
func = cls.LookupFunctionAllowPrivate(str);
|
|
}
|
|
}
|
|
if (!func.IsNull()) {
|
|
func.set_is_intrinsic(true);
|
|
} else if (!FLAG_precompiled_mode) {
|
|
FATAL2("Intrinsifier failed to find method %s in class %s\n",
|
|
intrinsic->function_name, intrinsic->class_name);
|
|
}
|
|
}
|
|
}
|
|
#undef SETUP_FUNCTION
|
|
}
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
// Returns true if fall-through code can be omitted.
|
|
bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
|
|
FlowGraphCompiler* compiler) {
|
|
const Function& function = parsed_function.function();
|
|
if (!CanIntrinsify(function)) {
|
|
return false;
|
|
}
|
|
|
|
ASSERT(!compiler->flow_graph().IsCompiledForOsr());
|
|
if (GraphIntrinsifier::GraphIntrinsify(parsed_function, compiler)) {
|
|
return compiler->intrinsic_slow_path_label()->IsUnused();
|
|
}
|
|
|
|
#if !defined(TARGET_HASH_IN_OBJECT_HEADER)
|
|
// These two are more complicated on 32 bit platforms, where the
|
|
// identity hash is not stored in the header of the object. We
|
|
// therefore don't intrinsify them, falling back on the native C++
|
|
// implementations.
|
|
if (function.recognized_kind() == MethodRecognizer::kObject_getHash ||
|
|
function.recognized_kind() == MethodRecognizer::kObject_setHash) {
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(PRODUCT) && !defined(TARGET_ARCH_DBC)
|
|
#define EMIT_BREAKPOINT() compiler->assembler()->Breakpoint()
|
|
#else
|
|
#define EMIT_BREAKPOINT()
|
|
#endif
|
|
|
|
#define EMIT_CASE(class_name, function_name, enum_name, fp) \
|
|
case MethodRecognizer::k##enum_name: { \
|
|
compiler->assembler()->Comment("Intrinsic"); \
|
|
Label normal_ir_body; \
|
|
const auto size_before = compiler->assembler()->CodeSize(); \
|
|
AsmIntrinsifier::enum_name(compiler->assembler(), &normal_ir_body); \
|
|
const auto size_after = compiler->assembler()->CodeSize(); \
|
|
if (size_before == size_after) return false; \
|
|
if (!normal_ir_body.IsBound()) { \
|
|
EMIT_BREAKPOINT(); \
|
|
return true; \
|
|
} \
|
|
return false; \
|
|
}
|
|
|
|
switch (function.recognized_kind()) {
|
|
ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE);
|
|
default:
|
|
break;
|
|
}
|
|
switch (function.recognized_kind()) {
|
|
CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE)
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// On DBC all graph intrinsics are handled in the same way as non-graph
|
|
// intrinsics.
|
|
#if defined(TARGET_ARCH_DBC)
|
|
switch (function.recognized_kind()) {
|
|
GRAPH_INTRINSICS_LIST(EMIT_CASE)
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#undef EMIT_BREAKPOINT
|
|
|
|
#undef EMIT_INTRINSIC
|
|
return false;
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace dart
|
|
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|