[llvm_codegen] Use exclusively SExpression support from VM and nothing else.

The LLVM code generator should only consume the serialized IR and not use any other VM functionality.
This CL adds a custom zone which can be used for the deserialized IR nodes and removes any
Dart_SetVMFlags/Dart_Initialize/ApiZone/... calls.

This works with the existing example:

    % ninja -C out/ReleaseX64 codegen
    % out/ReleaseX64/codegen runtime/llvm_codegen/test/codegen/Inputs/hello.sex
    ...
    define void @"hello.dart::main"() {

    B1:
      %0 = call i8* @llvm.stacksave()
      %1 = ptrtoint i8* %0 to i64
      %2 = load i64, i64 addrspace(256)* inttoptr (i64 72 to i64 addrspace(256)*)
      %3 = icmp ult i64 %1, %2
      br i1 %3, label %4, label %5
      ...
      ret void
    }
    ...
Change-Id: I1d07ba6bc122d100c73f97cfa961d36240489666
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/120792
Commit-Queue: Martin Kustermann <kustermann@google.com>
Auto-Submit: Martin Kustermann <kustermann@google.com>
Reviewed-by: Teagan Strickland <sstrickl@google.com>
This commit is contained in:
Martin Kustermann 2019-10-30 16:27:04 +00:00 committed by commit-bot@chromium.org
parent cb2f45ea6b
commit 4ea512b4c1
6 changed files with 145 additions and 45 deletions

View file

@ -5,13 +5,9 @@
import("../../vm/compiler/compiler_sources.gni")
config("config") {
include_dirs = [
"../../"
]
include_dirs = [ "../../" ]
cflags = [
"-Wno-unused-private-field"
]
cflags = [ "-Wno-unused-private-field" ]
}
_lib_llvm_so = "../../../third_party/llvm/lib/libLLVM-9svn.so"
@ -22,23 +18,27 @@ config("llvm") {
}
copy("lib_llvm") {
sources = [ _lib_llvm_so ]
outputs = [ "$root_out_dir/libLLVM-9svn.so" ]
sources = [
_lib_llvm_so,
]
outputs = [
"$root_out_dir/libLLVM-9svn.so",
]
public_configs = [ ":llvm" ]
}
executable("codegen") {
sources = [
"main.cc",
"custom_zone.cc",
"custom_zone.h",
"dart.cc",
"dart.h"
"dart.h",
"main.cc",
]
deps = [
":lib_llvm",
"../..:libdart_nosnapshot_with_precompiler",
"../../vm:libdart_vm_nosnapshot_with_precompiler",
"../../platform:libdart_platform_nosnapshot_with_precompiler",
"../../third_party/double-conversion/src:libdouble_conversion",
]
configs += [ ":config" ]

View file

@ -0,0 +1,54 @@
// Copyright (c) 2019, 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.
#include "custom_zone.h"
#include "platform/text_buffer.h"
#include "platform/unicode.h"
#include "platform/utils.h"
#include "vm/double_conversion.h"
#include "vm/os.h"
#include "platform/assert.cc" // NOLINT
#include "platform/syslog_linux.cc" // NOLINT
#include "platform/text_buffer.cc" // NOLINT
#include "platform/unicode.cc" // NOLINT
#include "platform/utils.cc" // NOLINT
#include "platform/utils_linux.cc" // NOLINT
#include "vm/compiler/backend/sexpression.cc" // NOLINT
#include "vm/double_conversion.cc" // NOLINT
#include "vm/flags.cc" // NOLINT
#include "vm/os_linux.cc" // NOLINT
#include "vm/zone_text_buffer.cc" // NOLINT
namespace dart {
void* ZoneAllocated::operator new(uintptr_t size, dart::Zone* zone) {
return reinterpret_cast<void*>(zone->AllocUnsafe(size));
}
Zone::~Zone() {
while (buffers_.size() > 0) {
free(buffers_.back());
buffers_.pop_back();
}
}
void* Zone::AllocUnsafe(intptr_t size) {
void* memory = malloc(size);
buffers_.push_back(memory);
return memory;
}
DART_EXPORT void Dart_PrepareToAbort() {
fprintf(stderr, "Dart_PrepareToAbort() not implemented!\n");
exit(1);
}
DART_EXPORT void Dart_DumpNativeStackTrace(void* context) {
fprintf(stderr, "Dart_DumpNativeStackTrace() not implemented!\n");
exit(1);
}
} // namespace dart

View file

@ -0,0 +1,52 @@
// Copyright (c) 2019, 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.
#ifndef RUNTIME_LLVM_CODEGEN_CODEGEN_CUSTOM_ZONE_H_
#define RUNTIME_LLVM_CODEGEN_CODEGEN_CUSTOM_ZONE_H_
#include <vector>
// We use a custom zone here which doesn't depend on VM internals (e.g. handles,
// thread, ...)
#if defined(RUNTIME_VM_ZONE_H_)
#error "We want our own zone implementation"
#endif
#define RUNTIME_VM_ZONE_H_
namespace dart {
class Zone {
public:
Zone() {}
~Zone();
template <class ElementType>
inline ElementType* Alloc(intptr_t length) {
return static_cast<ElementType*>(
AllocUnsafe(sizeof(ElementType) * length));
}
template <class ElementType>
inline ElementType* Realloc(ElementType* old_array,
intptr_t old_length,
intptr_t new_length) {
void* memory = AllocUnsafe(sizeof(ElementType) * new_length);
memmove(memory, old_array, sizeof(ElementType) * old_length);
return static_cast<ElementType*>(memory);
}
template <class ElementType>
void Free(ElementType* old_array, intptr_t len) {}
void* AllocUnsafe(intptr_t size);
private:
Zone(const Zone&) = delete;
void operator=(const Zone&) = delete;
std::vector<void*> buffers_;
};
} // namespace dart
#endif // RUNTIME_LLVM_CODEGEN_CODEGEN_CUSTOM_ZONE_H_

View file

@ -2,10 +2,11 @@
// 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.
#include <utility>
#include "dart.h"
#include "llvm/ADT/StringSwitch.h"
#include "vm/dart_api_state.h"
using namespace llvm;
@ -128,22 +129,22 @@ Expected<std::unique_ptr<DartInstruction>> InstPushArgument::Construct(
return CreateError("PushArgument should have exactly 1 argument");
}
dart::SExpSymbol* arg = inst->At(1)->AsSymbol();
if (!arg) {
if (arg == nullptr) {
return CreateError("Expected PushArgument's argument to be a symbol");
}
const DartValue* dvalue = bb_builder.GetDef(arg->value());
if (!dvalue) {
if (dvalue == nullptr) {
return CreateError(Twine(arg->value()) + " is not a valid symbol");
}
return llvm::make_unique<InstPushArgument>(dvalue);
}
void InstStaticCall::Build(BasicBlockBuilder& bb_builder) const {
// inst = (StaticCall <function-symbol> <arg> ...)
// inst = (StaticCall <function-symbol> <arg> ...)
SmallVector<Value*, 8> args;
size_t arg_count = args_len_;
while (arg_count) {
while (arg_count > 0) {
arg_count--;
args.push_back(bb_builder.PopArgument());
}
@ -196,15 +197,15 @@ Expected<std::unique_ptr<DartInstruction>> InstReturn::Construct(
return llvm::make_unique<InstReturn>();
}
static Expected<StringMap<DartConstant>> MakeConstants(dart::SExpList* sexpr) {
dart::ApiZone zone;
static Expected<StringMap<DartConstant>> MakeConstants(dart::Zone* zone,
dart::SExpList* sexpr) {
StringMap<DartConstant> out;
for (intptr_t i = 1; i < sexpr->Length(); ++i) {
DartConstant constant;
dart::SExpList* def = sexpr->At(i)->AsList();
if (!def) {
return CreateError(Twine("Stray token in constants at location ") +
Twine(i) + sexpr->At(i)->ToCString(zone.GetZone()));
Twine(i) + sexpr->At(i)->ToCString(zone));
}
if (def->Length() != 3) {
return CreateError("Constant definitions must have exactly 3 lines");
@ -287,10 +288,10 @@ static Expected<DartBlock> MakeBlock(dart::SExpList* sexpr,
return out;
}
Expected<DartFunction> MakeFunction(dart::SExpression* sexpr,
Expected<DartFunction> MakeFunction(dart::Zone* zone,
dart::SExpression* sexpr,
const StringMap<const DartValue*>& env) {
// Basic checking that this s-expression looks like a function
dart::ApiZone zone;
dart::SExpList* flist = sexpr->AsList();
if (!flist) return CreateError("S-Expression was not a function list");
if (flist->Length() < 2)
@ -312,10 +313,10 @@ Expected<DartFunction> MakeFunction(dart::SExpression* sexpr,
for (intptr_t i = 2; i < flist->Length(); ++i) {
dart::SExpList* chunk = flist->At(i)->AsList();
// Everything is a list so far so error out on other options
if (!chunk)
if (!chunk) {
return CreateError(Twine("Stray token in function at location ") +
Twine(i) + ": " +
flist->At(i)->ToCString(zone.GetZone()));
Twine(i) + ": " + flist->At(i)->ToCString(zone));
}
dart::SExpSymbol* chunk_symbol = chunk->At(0)->AsSymbol();
if (!chunk_symbol)
return CreateError(Twine("Expected element ") + Twine(i) +
@ -323,7 +324,7 @@ Expected<DartFunction> MakeFunction(dart::SExpression* sexpr,
StringRef chunk_tag = chunk_symbol->value();
if (chunk_tag == "constants") {
auto constants = MakeConstants(chunk);
auto constants = MakeConstants(zone, chunk);
if (!constants) return constants.takeError();
function.constants = std::move(*constants);
}

View file

@ -7,6 +7,7 @@
#include <memory>
#include <vector>
#include <string>
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/IRBuilder.h"
@ -14,6 +15,9 @@
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/WithColor.h"
// Ensure to use our own zone.
#include "custom_zone.h"
#include "vm/compiler/backend/sexpression.h"
// This file introduces several representations that exist between
@ -229,7 +233,7 @@ class DartInstruction {
// an instance of a CheckStackOverflow instruction.
class InstCheckStackOverflow : public DartInstruction {
public:
explicit InstCheckStackOverflow() {}
InstCheckStackOverflow() {}
~InstCheckStackOverflow() override {}
void Build(BasicBlockBuilder& bb_builder) const override;
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
@ -273,7 +277,7 @@ class InstStaticCall : public DartInstruction {
// instruction.
class InstReturn : public DartInstruction {
public:
explicit InstReturn() {}
InstReturn() {}
~InstReturn() override {}
void Build(BasicBlockBuilder& bb_builder) const override;
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
@ -303,7 +307,8 @@ struct DartFunction {
// of the S-Expression is invalid then the llvm::Expected will hold an
// error explaining the issue.
llvm::Expected<DartFunction> MakeFunction(
dart::Zone* zone,
dart::SExpression* sexpr,
const llvm::StringMap<const DartValue*>& env);
#endif // RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H
#endif // RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H_

View file

@ -13,8 +13,6 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "vm/dart_api_state.h"
using namespace llvm;
namespace {
@ -102,24 +100,14 @@ int main(int argc, const char** argv) {
tool_name = argv[0];
cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
// Init dart
const char* err = Dart_SetVMFlags(0, argv + 2);
if (err != nullptr) error(Twine("Dart_SetVMFlags failed: ") + err);
Dart_InitializeParams init_params;
memset(&init_params, 0, sizeof(init_params));
init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
err = Dart_Initialize(&init_params);
if (err != nullptr) error(Twine("Dart Initialization failed: ") + err);
// Read in the file
auto file_or = MemoryBuffer::getFile(argv[1]);
if (!file_or) reportError(argv[1], file_or.getError());
std::unique_ptr<MemoryBuffer> file = std::move(file_or.get());
// Parse the file
dart::ApiZone zone;
dart::SExpParser parser(zone.GetZone(), file->getBufferStart(),
file->getBufferSize());
dart::Zone zone;
dart::SExpParser parser(&zone, file->getBufferStart(), file->getBufferSize());
dart::SExpression* root = parser.Parse();
if (root == nullptr)
error(Twine("SExpParser failed: ") + parser.error_message());
@ -130,7 +118,7 @@ int main(int argc, const char** argv) {
prelude["dart:core::print"] = &print;
// Convert the function into an error checked format
auto function_or = MakeFunction(root, prelude);
auto function_or = MakeFunction(&zone, root, prelude);
if (!function_or) error(function_or.takeError());
auto dart_function = std::move(*function_or);
if (!dart_function.normal_entry)