mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:39:19 +00:00
[vm] Remove traces of LLVM backend
The code has been dead for quite some time. TEST=ci Change-Id: Iddcb63e14e9e4d95230f006ac05da64f444f0712 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190024 Commit-Queue: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
parent
0e12cdb7fa
commit
fa12114202
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -23,11 +23,6 @@
|
|||
/*.vcxproj.user
|
||||
*.stamp
|
||||
|
||||
# LLVM prebuilts
|
||||
/third_party/llvm/include
|
||||
/third_party/llvm/lib
|
||||
/third_party/llvm/.versions
|
||||
|
||||
# Gyp generated files
|
||||
*.xcodeproj
|
||||
*.intermediate
|
||||
|
|
18
BUILD.gn
18
BUILD.gn
|
@ -14,9 +14,6 @@ group("default") {
|
|||
testonly = true
|
||||
}
|
||||
deps = [ ":runtime" ]
|
||||
if (defined(checkout_llvm) && checkout_llvm) {
|
||||
deps += [ ":llvm_codegen" ]
|
||||
}
|
||||
}
|
||||
|
||||
group("most") {
|
||||
|
@ -117,21 +114,6 @@ group("analysis_server") {
|
|||
deps = [ "utils/analysis_server" ]
|
||||
}
|
||||
|
||||
group("check_llvm") {
|
||||
if (defined(checkout_llvm) && checkout_llvm) {
|
||||
deps = [ "runtime/llvm_codegen/test" ]
|
||||
}
|
||||
}
|
||||
|
||||
group("llvm_codegen") {
|
||||
if (defined(checkout_llvm) && checkout_llvm) {
|
||||
deps = [
|
||||
"runtime/llvm_codegen/bit",
|
||||
"runtime/llvm_codegen/codegen",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# This is the target that is built on the dart2js build bots.
|
||||
# It must depend on anything that is required by the dart2js
|
||||
# test suites.
|
||||
|
|
18
DEPS
18
DEPS
|
@ -180,18 +180,10 @@ vars = {
|
|||
"chrome_tag": "84",
|
||||
"download_firefox": False,
|
||||
"firefox_tag": "67",
|
||||
|
||||
# An LLVM backend needs LLVM binaries and headers. To avoid build time
|
||||
# increases we can use prebuilts. We don't want to download this on every
|
||||
# CQ/CI bot nor do we want the average Dart developer to incur that cost.
|
||||
# So by default we will not download prebuilts.
|
||||
"checkout_llvm": False,
|
||||
"llvm_revision": "fe8bd96ebd6c490ea0b5c1fb342db2d7c393a109"
|
||||
}
|
||||
|
||||
gclient_gn_args_file = Var("dart_root") + '/build/config/gclient_args.gni'
|
||||
gclient_gn_args = [
|
||||
'checkout_llvm'
|
||||
]
|
||||
|
||||
deps = {
|
||||
|
@ -615,16 +607,6 @@ deps = {
|
|||
],
|
||||
"dep_type": "cipd",
|
||||
},
|
||||
Var("dart_root") + "/third_party/llvm": {
|
||||
"packages": [
|
||||
{
|
||||
"package": "fuchsia/lib/llvm/${{platform}}",
|
||||
"version": "git_revision:" + Var("llvm_revision"),
|
||||
},
|
||||
],
|
||||
"condition": "checkout_llvm",
|
||||
"dep_type": "cipd",
|
||||
},
|
||||
Var("dart_root") + "/third_party/browsers/chrome": {
|
||||
"packages": [
|
||||
{
|
||||
|
|
|
@ -897,9 +897,6 @@ executable("run_vm_tests") {
|
|||
"..:libdart_precompiler",
|
||||
"//third_party/zlib",
|
||||
]
|
||||
if (defined(checkout_llvm) && checkout_llvm) {
|
||||
deps += [ "//runtime/llvm_codegen/bit:test" ]
|
||||
}
|
||||
include_dirs = [
|
||||
"..",
|
||||
"$target_gen_dir",
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
# 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.
|
||||
|
||||
executable("bit") {
|
||||
sources = [ "main.cc" ]
|
||||
root_dir = rebase_path(root_out_dir)
|
||||
clang_dir = rebase_path("//buildtools/linux-x64/clang/bin")
|
||||
defines = [
|
||||
"BIT_BINARY_DIR=\"$root_dir\"",
|
||||
"BIT_CLANG_DIR=\"$clang_dir\"",
|
||||
]
|
||||
deps = [ "../../../third_party/llvm:LLVMSupport" ]
|
||||
data_deps = [ "../codegen" ]
|
||||
}
|
||||
|
||||
source_set("test") {
|
||||
sources = [ "test.cc" ]
|
||||
|
||||
root_dir = rebase_path(root_out_dir)
|
||||
clang_dir = rebase_path("//buildtools/linux-x64/clang/bin")
|
||||
defines = [
|
||||
"BIT_BINARY_DIR=\"$root_dir\"",
|
||||
"BIT_CLANG_DIR=\"$clang_dir\"",
|
||||
]
|
||||
|
||||
deps = [ "../../../third_party/llvm:LLVMSupport" ]
|
||||
|
||||
include_dirs = [ "//runtime" ]
|
||||
|
||||
defines += [ "TESTING" ]
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// 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 <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
struct Config {
|
||||
StringRef filename;
|
||||
StringRef out_dir;
|
||||
};
|
||||
|
||||
StringMap<std::string> GetSubstitutions(const Config& config) {
|
||||
// Compute all of our strings needed for substitutions.
|
||||
StringRef test_dir = sys::path::parent_path(config.filename);
|
||||
StringRef basename = sys::path::filename(config.filename);
|
||||
SmallString<128> tmp_file;
|
||||
sys::path::append(tmp_file, sys::path::Style::native, config.out_dir,
|
||||
basename + ".tmp");
|
||||
SmallString<128> codegen;
|
||||
sys::path::append(codegen, sys::path::Style::native, BIT_BINARY_DIR,
|
||||
"codegen");
|
||||
SmallString<128> bit;
|
||||
sys::path::append(bit, sys::path::Style::native, BIT_BINARY_DIR, "bit");
|
||||
|
||||
SmallString<128> clang;
|
||||
sys::path::append(clang, sys::path::Style::native, BIT_CLANG_DIR, "clang");
|
||||
|
||||
// Set up our substitutions.
|
||||
StringMap<std::string> subs;
|
||||
subs["s"] = config.filename.str();
|
||||
subs["p"] = test_dir.str();
|
||||
subs["P"] = test_dir.str();
|
||||
subs["t"] = tmp_file.str().str();
|
||||
subs["{codegen}"] = codegen.str().str();
|
||||
subs["{bit}"] = bit.str().str();
|
||||
subs["{clang}"] = clang.str().str();
|
||||
return subs;
|
||||
}
|
||||
|
||||
std::string PerformSubstitutions(const StringMap<std::string>& subs,
|
||||
StringRef string) {
|
||||
std::string out = string.str();
|
||||
for (const auto& sub : subs) {
|
||||
std::string key = (Twine("%") + sub.getKeyData()).str();
|
||||
size_t pos = 0;
|
||||
while ((pos = out.find(key, pos)) != std::string::npos) {
|
||||
if (pos != 0 && out[pos - 1] == '%') {
|
||||
pos += key.size();
|
||||
continue;
|
||||
}
|
||||
out.replace(pos, key.size(), sub.getValue());
|
||||
pos += sub.second.size();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Optional<std::string> GetCommand(StringRef line) {
|
||||
static Regex run_line("^;[ ]*RUN:[ ]*(.*)$");
|
||||
SmallVector<StringRef, 2> cmd;
|
||||
if (!run_line.match(line, &cmd)) return Optional<std::string>{};
|
||||
assert(cmd.size() == 2);
|
||||
return cmd[1].str();
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -1,122 +0,0 @@
|
|||
// 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 <stdio.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
||||
#include "bit.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
StringRef tool_name;
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void Fail(Twine message) {
|
||||
WithColor::error(errs(), tool_name) << message << ".\n";
|
||||
errs().flush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void Fail(Error e) {
|
||||
assert(E);
|
||||
std::string buf;
|
||||
raw_string_ostream os(buf);
|
||||
logAllUnhandledErrors(std::move(e), os);
|
||||
os.flush();
|
||||
WithColor::error(errs(), tool_name) << buf;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void ReportError(StringRef file, std::error_code ec) {
|
||||
assert(ec);
|
||||
Fail(createFileError(file, ec));
|
||||
}
|
||||
|
||||
std::string ReadFile(FILE* file) {
|
||||
std::string output;
|
||||
constexpr size_t buf_size = 256;
|
||||
char buf[buf_size];
|
||||
size_t size;
|
||||
while ((size = fread(buf, buf_size, sizeof(buf[0]), file)))
|
||||
output.append(buf, buf + buf_size);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool IsPosixFullyPortablePath(StringRef path) {
|
||||
const char* extra = "._-/";
|
||||
for (auto c : path)
|
||||
if (!isalnum(c) && !strchr(extra, c)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitLLVM X(argc, argv);
|
||||
|
||||
// Make sure we have both arguments.
|
||||
tool_name = argv[0];
|
||||
if (argc != 3) Fail("expected exactly 2 arguments");
|
||||
|
||||
// Makes sure that stdin/stdout are setup correctly.
|
||||
if (sys::Process::FixupStandardFileDescriptors())
|
||||
Fail("std in/out fixup failed");
|
||||
|
||||
// Set our config.
|
||||
Config config;
|
||||
config.filename = argv[1];
|
||||
config.out_dir = argv[2];
|
||||
|
||||
// Make sure we have valid filepaths.
|
||||
if (!IsPosixFullyPortablePath(config.filename))
|
||||
Fail("'" + config.filename + "' is not a posix fully portable filename");
|
||||
if (!IsPosixFullyPortablePath(config.out_dir))
|
||||
Fail("'" + config.out_dir + "' is not a posix fully portable filename");
|
||||
|
||||
// Compute substitutions.
|
||||
auto subs = GetSubstitutions(config);
|
||||
|
||||
// The lines we execute are allowed to assume that %p will exist.
|
||||
sys::fs::create_directory(subs["p"]);
|
||||
|
||||
// Open the file for reading.
|
||||
auto buf_or = vfs::getRealFileSystem()->getBufferForFile(config.filename);
|
||||
if (!buf_or) ReportError(config.filename, buf_or.getError());
|
||||
auto buf = std::move(*buf_or);
|
||||
|
||||
// Now iterate over the lines in the file.
|
||||
line_iterator it{*buf};
|
||||
int count = 0;
|
||||
for (StringRef line = *it; !it.is_at_end(); line = *++it) {
|
||||
auto cmd = GetCommand(line);
|
||||
if (!cmd) continue;
|
||||
++count;
|
||||
auto subbed = PerformSubstitutions(subs, *cmd);
|
||||
FILE* file = popen(subbed.c_str(), "r");
|
||||
std::string output = ReadFile(file);
|
||||
if (pclose(file) != 0) {
|
||||
errs() << output << "\n";
|
||||
Fail("Failure on line " + Twine(it.line_number()) + "\n\t" + subbed + "");
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
Fail("No commands to run");
|
||||
}
|
||||
outs() << "Commands run: " << count << "\n";
|
||||
return 0;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// 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 <stdio.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include "platform/assert.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
#define LIT_BINARY_DIR "/path/to/bins"
|
||||
#include "bit.h"
|
||||
|
||||
UNIT_TEST_CASE(BasicGetSubstitutions) {
|
||||
Config config;
|
||||
config.filename = "/foo/bar/baz.ll";
|
||||
config.out_dir = "/test/out/dir";
|
||||
|
||||
StringMap<std::string> expected;
|
||||
expected["s"] = "/foo/bar/baz.ll";
|
||||
expected["p"] = "/foo/bar";
|
||||
expected["P"] = "/test/out/dir";
|
||||
expected["t"] = "/test/out/dir/baz.ll.tmp";
|
||||
expected["codegen"] = "/path/to/bins/codegen";
|
||||
expected["bit"] = "/path/to/bins/bit";
|
||||
|
||||
StringMap<std::string> actual = GetSubstitutions(config);
|
||||
|
||||
EXPECT_EQ(actual.size(), expected.size());
|
||||
for (const auto& p : actual)
|
||||
EXPECT_EQ(p.getValue(), expected[p.getKey()]);
|
||||
}
|
||||
|
||||
UNIT_TEST_CASE(BasicPerformSubstitutions) {
|
||||
StringMap<std::string> subs;
|
||||
subs["foo"] = "/foo/path";
|
||||
subs["bar"] = "/bar/path";
|
||||
subs["baz"] = "/baz/path";
|
||||
std::vector<std::pair<std::string, std::string>> cases = {
|
||||
{"%foo", "/foo/path"},
|
||||
{"%bar", "/bar/path"},
|
||||
{"%baz", "/baz/path"},
|
||||
{"this has %foo, and %bar, and %baz2",
|
||||
"this has /foo/path, and /bar/path, and /baz/path2"},
|
||||
{"we don't want %this to expand", "we don't want %this to expand"},
|
||||
{"%", "%"}};
|
||||
for (const auto& test : cases) {
|
||||
auto out = PerformSubstitutions(subs, test.first);
|
||||
EXPECT_EQ(out, test.second);
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST_CASE(BasicGetCommand) {
|
||||
EXPECT(!GetCommand("; this is some test"));
|
||||
EXPECT(!GetCommand("2 + 2"));
|
||||
EXPECT(!GetCommand("echo $VAR > %bit"));
|
||||
|
||||
EXPECT(GetCommand(";RUN: blarg") == Optional<std::string>{"blarg"});
|
||||
EXPECT(GetCommand("; RUN: foo") == Optional<std::string>{"blarg"});
|
||||
EXPECT(
|
||||
GetCommand("; RUN: echo %bit %p/Input/$(%t2) > $(baz \"$BAR->%t\")") ==
|
||||
Optional<std::string>("echo %bit %p/Input/$(%t2) > $(baz \"$BAR->%t\")"));
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import("../../vm/compiler/compiler_sources.gni")
|
||||
|
||||
config("config") {
|
||||
include_dirs = [ "../../" ]
|
||||
|
||||
cflags = [ "-Wno-unused-private-field" ]
|
||||
}
|
||||
|
||||
_lib_llvm_so = "../../../third_party/llvm/lib/libLLVM-9svn.so"
|
||||
|
||||
config("llvm") {
|
||||
include_dirs = [ "../../../third_party/llvm/include" ]
|
||||
libs = [ _lib_llvm_so ]
|
||||
}
|
||||
|
||||
copy("lib_llvm") {
|
||||
sources = [ _lib_llvm_so ]
|
||||
outputs = [ "$root_out_dir/libLLVM-9svn.so" ]
|
||||
public_configs = [ ":llvm" ]
|
||||
}
|
||||
|
||||
executable("codegen") {
|
||||
sources = [
|
||||
"custom_zone.cc",
|
||||
"custom_zone.h",
|
||||
"dart.cc",
|
||||
"dart.h",
|
||||
"main.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":lib_llvm",
|
||||
"../../third_party/double-conversion/src:libdouble_conversion",
|
||||
]
|
||||
|
||||
configs += [ ":config" ]
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
// 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
|
|
@ -1,52 +0,0 @@
|
|||
// 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_
|
|
@ -1,358 +0,0 @@
|
|||
// 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 <utility>
|
||||
|
||||
#include "dart.h"
|
||||
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
Value* DartThreadObject::GetOffset(Type* type, intptr_t offset) const {
|
||||
auto& ctx = bb_builder_.Context();
|
||||
auto& builder = bb_builder_.Builder();
|
||||
auto int64ty = IntegerType::getInt64Ty(ctx);
|
||||
// TODO: This is only correct for x86_64. On x86 we need to use 257,
|
||||
// and only arm targets an entirely different mechanism will be
|
||||
// required since there isn't an unused register. On Arm we can
|
||||
// probably still use the thread register as long as we're careful
|
||||
// to set it back on thread boundaries.
|
||||
// On x86_64 fs (257) is used for TLS but gs (256) is unused
|
||||
// On x86 gs (256) is used for TLS but fs (257) is unused
|
||||
// we use the unused segment so as to not conflict with TLS which
|
||||
// allows linking against native code that uses TLS without needing
|
||||
// to handle any kind of context switching.
|
||||
constexpr unsigned kDartThreadPointerAddressSpace = 256;
|
||||
auto* ptr_tls = PointerType::get(type, kDartThreadPointerAddressSpace);
|
||||
auto* offset_value = ConstantInt::get(int64ty, offset);
|
||||
auto* tls_value = builder.CreateIntToPtr(offset_value, ptr_tls);
|
||||
return builder.CreateLoad(tls_value);
|
||||
}
|
||||
|
||||
Value* DartThreadObject::StackLimit() const {
|
||||
auto& ctx = bb_builder_.Context();
|
||||
return GetOffset(IntegerType::getInt64Ty(ctx), kThreadStackLimitOffset);
|
||||
}
|
||||
|
||||
Value* BasicBlockBuilder::GetValue(const DartValue* v) {
|
||||
auto iter = values_.find(v);
|
||||
if (iter == values_.end()) {
|
||||
auto* out = v->Make(*this);
|
||||
values_[v] = out;
|
||||
return out;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
DartInstruction::~DartInstruction() {}
|
||||
|
||||
static Error CreateError(const Twine& err) {
|
||||
return make_error<StringError>(err, inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
Value* DartConstant::Make(BasicBlockBuilder& bb_builder) const {
|
||||
auto& ctx = bb_builder.Context();
|
||||
switch (type) {
|
||||
case DartConstant::Type::String:
|
||||
auto constant = ConstantDataArray::getString(ctx, str);
|
||||
auto gv =
|
||||
new GlobalVariable(bb_builder.Module(), constant->getType(), true,
|
||||
GlobalVariable::ExternalLinkage, constant);
|
||||
return ConstantExpr::getBitCast(gv, GetType(bb_builder));
|
||||
}
|
||||
}
|
||||
|
||||
Type* DartConstant::GetType(BasicBlockBuilder& bb_builder) const {
|
||||
// TODO: Right now this returns a c-string type but that's not correct.
|
||||
// We should move this to a generic object type (e.g. a tagged pointer).
|
||||
auto& ctx = bb_builder.Context();
|
||||
auto int8ty = IntegerType::getInt8Ty(ctx);
|
||||
return PointerType::get(int8ty, 0);
|
||||
}
|
||||
|
||||
void InstCheckStackOverflow::Build(BasicBlockBuilder& bb_builder) const {
|
||||
auto& builder = bb_builder.Builder();
|
||||
auto& ctx = bb_builder.Context();
|
||||
auto& module = bb_builder.Module();
|
||||
auto& thread_object = bb_builder.ThreadObject();
|
||||
|
||||
// TODO: This is only correct on 64-bit architectures.
|
||||
auto int64ty = IntegerType::getInt64Ty(ctx);
|
||||
|
||||
// Get the stack pointer.
|
||||
auto spi_type = Intrinsic::getType(ctx, Intrinsic::stacksave);
|
||||
auto spi_func = Intrinsic::getDeclaration(&module, Intrinsic::stacksave);
|
||||
auto sp_raw = builder.CreateCall(spi_type, spi_func);
|
||||
auto sp = builder.CreatePtrToInt(sp_raw, int64ty);
|
||||
|
||||
// Get the stack limit from the thread pointer.
|
||||
auto stack_limit = thread_object.StackLimit();
|
||||
|
||||
// Now compare the stack pointer and limit.
|
||||
auto error_bb = bb_builder.AddBasicBlock();
|
||||
auto cont_bb = bb_builder.AddBasicBlock();
|
||||
auto cmp = builder.CreateICmpULT(sp, stack_limit);
|
||||
builder.CreateCondBr(cmp, error_bb, cont_bb);
|
||||
|
||||
// Now build the error path.
|
||||
// TODO: Don't just trap here. For now we just trap rather than
|
||||
// handling the proper exceptional control flow here.
|
||||
builder.SetInsertPoint(error_bb);
|
||||
auto trap_type = Intrinsic::getType(ctx, Intrinsic::trap);
|
||||
auto trap_func = Intrinsic::getDeclaration(&module, Intrinsic::trap);
|
||||
builder.CreateCall(trap_type, trap_func);
|
||||
builder.CreateBr(cont_bb);
|
||||
|
||||
// Now pretend as if this new block is just the end of the block we
|
||||
// started with.
|
||||
builder.SetInsertPoint(cont_bb);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<DartInstruction>> InstCheckStackOverflow::Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder) {
|
||||
// inst = (CheckStackoverflow)
|
||||
return llvm::make_unique<InstCheckStackOverflow>();
|
||||
}
|
||||
|
||||
void InstPushArgument::Build(BasicBlockBuilder& bb_builder) const {
|
||||
bb_builder.PushArgument(bb_builder.GetValue(arg_));
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<DartInstruction>> InstPushArgument::Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder) {
|
||||
// inst = (PushArgument <arg>)
|
||||
if (inst->Length() != 2) {
|
||||
return CreateError("PushArgument should have exactly 1 argument");
|
||||
}
|
||||
dart::SExpSymbol* arg = inst->At(1)->AsSymbol();
|
||||
if (arg == nullptr) {
|
||||
return CreateError("Expected PushArgument's argument to be a symbol");
|
||||
}
|
||||
const DartValue* dvalue = bb_builder.GetDef(arg->value());
|
||||
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> ...)
|
||||
|
||||
SmallVector<Value*, 8> args;
|
||||
size_t arg_count = args_len_;
|
||||
while (arg_count > 0) {
|
||||
arg_count--;
|
||||
args.push_back(bb_builder.PopArgument());
|
||||
}
|
||||
auto& builder = bb_builder.Builder();
|
||||
|
||||
// Hard code the function type for now.
|
||||
auto& ctx = bb_builder.Context();
|
||||
auto int8ty = IntegerType::getInt8Ty(ctx);
|
||||
auto i8ptr = PointerType::get(int8ty, 0);
|
||||
SmallVector<Type*, 8> arg_types;
|
||||
arg_types.push_back(i8ptr);
|
||||
auto print_type = FunctionType::get(Type::getVoidTy(ctx), arg_types, false);
|
||||
|
||||
// Get the function value we need.
|
||||
auto func = bb_builder.GetValue(function_);
|
||||
builder.CreateCall(print_type, func, args);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<DartInstruction>> InstStaticCall::Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder) {
|
||||
// inst = (StaticCall <function_name> { args_len <N> })
|
||||
if (inst->Length() != 2) {
|
||||
return CreateError("StaticCall should have exactly 1 argument");
|
||||
}
|
||||
dart::SExpSymbol* func = inst->At(1)->AsSymbol();
|
||||
if (!func) {
|
||||
return CreateError("Expected StaticCall's argument to be a symbol");
|
||||
}
|
||||
const DartValue* dvalue = bb_builder.GetDef(func->value());
|
||||
dart::SExpression* args_len_expr = inst->ExtraLookupValue("args_len");
|
||||
// If args_len_expr isn't found args_len is assumed to be zero.
|
||||
size_t args_len = 0;
|
||||
if (args_len_expr) {
|
||||
dart::SExpInteger* args_len_expr_int = args_len_expr->AsInteger();
|
||||
if (args_len_expr_int) args_len = args_len_expr_int->value();
|
||||
}
|
||||
return llvm::make_unique<InstStaticCall>(dvalue, 1);
|
||||
}
|
||||
|
||||
void InstReturn::Build(BasicBlockBuilder& bb_builder) const {
|
||||
auto& builder = bb_builder.Builder();
|
||||
builder.CreateRetVoid();
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<DartInstruction>> InstReturn::Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder) {
|
||||
// inst = (Return)
|
||||
return llvm::make_unique<InstReturn>();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
if (def->Length() != 3) {
|
||||
return CreateError("Constant definitions must have exactly 3 lines");
|
||||
}
|
||||
dart::SExpSymbol* def_symbol = def->At(0)->AsSymbol();
|
||||
if (def_symbol->value() != StringRef("def")) {
|
||||
return CreateError(
|
||||
"first element in a constant definition expected to be `def`");
|
||||
}
|
||||
dart::SExpSymbol* def_name = def->At(1)->AsSymbol();
|
||||
if (!def_name) {
|
||||
return CreateError("element after `def` in constant expected to be name");
|
||||
}
|
||||
dart::SExpression* def_value = def->At(2);
|
||||
if (def_value->IsString()) {
|
||||
constant.str = def_value->AsString()->value();
|
||||
constant.type = DartConstant::Type::String;
|
||||
} else {
|
||||
return CreateError("We can't yet handle that element type");
|
||||
}
|
||||
out[def_name->value()] = constant;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#define FOREACH_INSTRUCTION(M) \
|
||||
M(CheckStackOverflow) \
|
||||
M(PushArgument) \
|
||||
M(StaticCall) \
|
||||
M(Return)
|
||||
|
||||
static Expected<std::unique_ptr<DartInstruction>> MakeInstruction(
|
||||
dart::SExpList* sexpr,
|
||||
DartBasicBlockBuilder& bb_builder) {
|
||||
if (sexpr->Length() < 1)
|
||||
return CreateError("An empty list can't be an instruction");
|
||||
dart::SExpSymbol* inst_sym = sexpr->At(0)->AsSymbol();
|
||||
if (!inst_sym)
|
||||
return CreateError(
|
||||
"Expected first element of list in instruction to be a symbol");
|
||||
using CtorFunc = std::function<Expected<std::unique_ptr<DartInstruction>>(
|
||||
dart::SExpList*, DartBasicBlockBuilder&)>;
|
||||
CtorFunc ctor = StringSwitch<CtorFunc>(inst_sym->value())
|
||||
#define HANDLE_INSTRUCTION_CASE(INST) .Case(#INST, Inst##INST::Construct)
|
||||
FOREACH_INSTRUCTION(HANDLE_INSTRUCTION_CASE);
|
||||
#undef HANDLE_INSTRUCTION_CASE
|
||||
return ctor(sexpr, bb_builder);
|
||||
}
|
||||
|
||||
static Expected<DartBlock> MakeBlock(dart::SExpList* sexpr,
|
||||
DartFunction& function,
|
||||
const StringMap<const DartValue*>& env) {
|
||||
// Construct the basic block builder
|
||||
DartBasicBlockBuilder bb_builder;
|
||||
for (const auto& c : function.constants)
|
||||
bb_builder.AddDef(c.getKey(), &c.getValue());
|
||||
for (const auto& c : env)
|
||||
bb_builder.AddDef(c.getKey(), c.getValue());
|
||||
|
||||
DartBlock out;
|
||||
|
||||
// Make sure we have a basic block and get the name
|
||||
if (sexpr->Length() <= 2)
|
||||
return CreateError("too few elements in basic block");
|
||||
dart::SExpSymbol* block_name = sexpr->At(1)->AsSymbol();
|
||||
if (!block_name)
|
||||
return CreateError("expected block name after `block` symbol");
|
||||
out.name = block_name->value();
|
||||
|
||||
// Now construct each instruction and add it to the basic block
|
||||
for (intptr_t i = 2; i < sexpr->Length(); ++i) {
|
||||
dart::SExpList* inst = sexpr->At(i)->AsList();
|
||||
if (!inst)
|
||||
return CreateError("stray token at element " + Twine(i) +
|
||||
" in basic block " + out.name);
|
||||
auto inst_or = MakeInstruction(inst, bb_builder);
|
||||
if (!inst_or) return inst_or.takeError();
|
||||
out.instructions.emplace_back(std::move(*inst_or));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
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::SExpList* flist = sexpr->AsList();
|
||||
if (!flist) return CreateError("S-Expression was not a function list");
|
||||
if (flist->Length() < 2)
|
||||
return CreateError("S-Expression list was too short to be a function");
|
||||
dart::SExpSymbol* function_symbol = flist->At(0)->AsSymbol();
|
||||
if (function_symbol == nullptr ||
|
||||
function_symbol->value() != StringRef("function"))
|
||||
return CreateError(
|
||||
"S-Expression cannot be a function as it does not start with "
|
||||
"`function`");
|
||||
dart::SExpSymbol* function_name = flist->At(1)->AsSymbol();
|
||||
if (function_name == nullptr)
|
||||
return CreateError("Expected symbol name after `function` symbol");
|
||||
|
||||
// Now we fill in all the details
|
||||
DartFunction function;
|
||||
function.name = function_name->value();
|
||||
Optional<StringRef> normal_entry;
|
||||
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) {
|
||||
return CreateError(Twine("Stray token in function at location ") +
|
||||
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) +
|
||||
" of function to start with a symbol");
|
||||
StringRef chunk_tag = chunk_symbol->value();
|
||||
|
||||
if (chunk_tag == "constants") {
|
||||
auto constants = MakeConstants(zone, chunk);
|
||||
if (!constants) return constants.takeError();
|
||||
function.constants = std::move(*constants);
|
||||
}
|
||||
|
||||
if (chunk_tag == "block") {
|
||||
auto block = MakeBlock(chunk, function, env);
|
||||
if (!block) return block.takeError();
|
||||
StringRef name = block->name;
|
||||
function.blocks[name] = std::move(*block);
|
||||
}
|
||||
|
||||
if (chunk_tag == "normal-entry") {
|
||||
if (chunk->Length() != 2)
|
||||
return CreateError("Expected 1 argument to normal-entry");
|
||||
dart::SExpSymbol* block_name = chunk->At(1)->AsSymbol();
|
||||
if (!block_name)
|
||||
return CreateError("expected block name after normal-entry symbol");
|
||||
normal_entry = block_name->value();
|
||||
}
|
||||
}
|
||||
|
||||
if (normal_entry) {
|
||||
auto iter = function.blocks.find(*normal_entry);
|
||||
if (iter != function.blocks.end())
|
||||
function.normal_entry = &iter->getValue();
|
||||
} else {
|
||||
function.normal_entry = nullptr;
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
|
@ -1,314 +0,0 @@
|
|||
// 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_DART_H_
|
||||
#define RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#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
|
||||
// S-Expressions and llvm IR. To explain how each part is intended
|
||||
// to be roughly translated using these I'll provide a mapping
|
||||
// showing how each part is translated.
|
||||
|
||||
// At a high level two translations are very seamless:
|
||||
//
|
||||
// (function foo ...) -> DartFunction -> llvm::Function*
|
||||
// (block B ...) -> DartBlock -> (sort of) llvm::BasicBlock*
|
||||
//
|
||||
// Internally within a function constants are given names and are then used in
|
||||
// blocks. Each block additionally defines more names. Each of these names
|
||||
// needs to be mapped to a DartValue (more on that later) so a context to help
|
||||
// keep track of these name to DartValue mappings called a
|
||||
// DartBasicBlockBuilder exists. It is only used for to aid in the
|
||||
// (block B ...) -> DartBlock translation which is in turn used in the
|
||||
// (function foo ...) -> DartFunction translation. DartFunctions and DartBlocks
|
||||
// can be seen as validated representations of their S-Expression forms.
|
||||
|
||||
// Within a DartBlock we have DartInstructions. Each DartInstruction either
|
||||
// has some effect (like calling a function or updating a value) or defines
|
||||
// a new name mapping it to a DartValue later. DartValues are referenced as
|
||||
// arguments to DartInstructions and map to llvm::Value*s. DartInstructions
|
||||
// have no analogue which they're directly translated to in code but they
|
||||
// do closely correspond mentally to llvm::Instruction*. The challenge is that
|
||||
// a DartInstruction might map to a near arbitrary number of llvm Instructions
|
||||
// and that mapping is very dependent on context. So instead of mapping them
|
||||
// to objects DartInstructions just know how to add their llvm Instructions to
|
||||
// an llvm::BasicBlock. These instructions might reference a verity of context
|
||||
// and so BasicBlockBuilder is passed in to provide them with this context.
|
||||
// Each DartInstruction is expected to already hold each DartValue that it
|
||||
// needs as previously supplied by the DartBasicBlockBuilder on construction.
|
||||
|
||||
// An additional issue arises when translating DartInstructions into llvm IR.
|
||||
// Many require introducing control flow when lowered to the level of llvm IR
|
||||
// but this requires using multiple llvm::BasicBlock for a single DartBlock.
|
||||
// Luckily each DartInstruction that is not a terminator is expected to make it
|
||||
// possible for all non-exceptional control flow paths to wind up at a single
|
||||
// basic block. Since BasicBlockBuilder keeps track of a "current" basic block
|
||||
// via llvm::IRBuilder we simply ensure that after generating many blocks we
|
||||
// end each instruction which requires new basic blocks on this final basic
|
||||
// block that all generated blocks flow into. A picture better explains this:
|
||||
|
||||
// Say you have a DartBlock B_1 it would then be mapped to llvm blocks that
|
||||
// look like this:
|
||||
//
|
||||
// B_1
|
||||
// / \
|
||||
// / \
|
||||
// B_1_left B_1_right
|
||||
// \ /
|
||||
// \ /
|
||||
// B_1_0
|
||||
//
|
||||
// And then we go on adding to B_1_0 as if it were the end of B_1 from before.
|
||||
|
||||
// Each DartValue knows how to map itself to an llvm::Value. In llvm a Value
|
||||
// is really just anything you can give a name to in the IR but a DartValue
|
||||
// is intended to be more specific, it's a compile time representation of a
|
||||
// object, be it an integer, a tagged SMI, a pointer to a Dart Object, etc...
|
||||
// its intended to correspond to some actual object that we're computing on.
|
||||
|
||||
// Class FunctionBuilder provides functionality for building
|
||||
// and LLVM function object including the ability to add a
|
||||
// named basic block, find an existing block, get the current
|
||||
// context/module and additionally retrieve llvm Values valid
|
||||
// in the current function.
|
||||
class FunctionBuilder {
|
||||
public:
|
||||
FunctionBuilder(llvm::LLVMContext& ctx,
|
||||
llvm::Module& mod,
|
||||
llvm::Function& func)
|
||||
: ctx_(ctx), mod_(mod), func_(func) {}
|
||||
llvm::LLVMContext& Context() { return ctx_; }
|
||||
llvm::Module& Module() { return mod_; }
|
||||
llvm::Value* GetSymbolValue(llvm::StringRef name) {
|
||||
auto* symtab = func_.getValueSymbolTable();
|
||||
return symtab->lookup(name);
|
||||
}
|
||||
llvm::BasicBlock* AddBasicBlock() {
|
||||
return llvm::BasicBlock::Create(ctx_, "", &func_);
|
||||
}
|
||||
llvm::BasicBlock* AddBasicBlock(llvm::StringRef name) {
|
||||
auto* bb = llvm::BasicBlock::Create(ctx_, name, &func_);
|
||||
basic_blocks_[name] = bb;
|
||||
return bb;
|
||||
}
|
||||
llvm::BasicBlock* GetBasicBlock(llvm::StringRef name) const {
|
||||
auto iter = basic_blocks_.find(name);
|
||||
if (iter != basic_blocks_.end()) return iter->getValue();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::LLVMContext& ctx_;
|
||||
llvm::Module& mod_;
|
||||
llvm::Function& func_;
|
||||
llvm::StringMap<llvm::BasicBlock*> basic_blocks_;
|
||||
};
|
||||
|
||||
class BasicBlockBuilder;
|
||||
|
||||
// TODO(jakehehrlich): Make this architecture dependent
|
||||
// Class DartThreadObject is used as a high level object for generating
|
||||
// code that reads fields from the thread object.
|
||||
class DartThreadObject {
|
||||
public:
|
||||
explicit DartThreadObject(BasicBlockBuilder& bb_builder)
|
||||
: bb_builder_(bb_builder) {}
|
||||
|
||||
// StackLimit returns an llvm::Value representing the stack limit
|
||||
// of the thread object.
|
||||
llvm::Value* StackLimit() const;
|
||||
|
||||
private:
|
||||
static constexpr intptr_t kThreadStackLimitOffset = 72;
|
||||
|
||||
BasicBlockBuilder& bb_builder_;
|
||||
|
||||
// GetOffset returns an llvm::Value* representing a pointer to a particular
|
||||
// field of the thread object. It adds the specified offset to the thread
|
||||
// pointer, and then casts to the specified type.
|
||||
llvm::Value* GetOffset(llvm::Type* type, intptr_t offset) const;
|
||||
};
|
||||
|
||||
class DartValue;
|
||||
|
||||
// A class for keeping track of the basic block state and SSA values.
|
||||
// This is similar to IRBuilder but also keeps track of the argument stack and
|
||||
// basic block names.
|
||||
class BasicBlockBuilder {
|
||||
public:
|
||||
BasicBlockBuilder(llvm::BasicBlock* bb, FunctionBuilder& fb)
|
||||
: fb_(fb), top_(bb), builder_(bb), thread_object_(*this) {}
|
||||
llvm::LLVMContext& Context() { return fb_.Context(); }
|
||||
llvm::Module& Module() { return fb_.Module(); }
|
||||
llvm::IRBuilder<>& Builder() { return builder_; }
|
||||
const DartThreadObject& ThreadObject() { return thread_object_; }
|
||||
llvm::BasicBlock* AddBasicBlock() { return fb_.AddBasicBlock(); }
|
||||
llvm::BasicBlock* GetBasicBlock(llvm::StringRef Name) const {
|
||||
return fb_.GetBasicBlock(Name);
|
||||
}
|
||||
llvm::Value* GetSymbolValue(llvm::StringRef name) const {
|
||||
return fb_.GetBasicBlock(name);
|
||||
}
|
||||
llvm::Value* GetValue(const DartValue* v);
|
||||
void PushArgument(llvm::Value* v) { stack_.push_back(v); }
|
||||
llvm::Value* PopArgument() {
|
||||
llvm::Value* out = stack_.back();
|
||||
stack_.pop_back();
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionBuilder& fb_;
|
||||
llvm::BasicBlock* top_;
|
||||
llvm::SmallVector<llvm::Value*, 16> stack_;
|
||||
llvm::IRBuilder<> builder_;
|
||||
llvm::DenseMap<const DartValue*, llvm::Value*> values_;
|
||||
DartThreadObject thread_object_;
|
||||
};
|
||||
|
||||
// Class DartValue represents an SSA value from the Dart SSA
|
||||
// such that it can be converted into an llvm::Value*.
|
||||
class DartValue {
|
||||
public:
|
||||
virtual ~DartValue() {}
|
||||
virtual llvm::Value* Make(BasicBlockBuilder& bb_builder) const = 0;
|
||||
virtual llvm::Type* GetType(BasicBlockBuilder& bb_builder) const = 0;
|
||||
};
|
||||
|
||||
// Class DartBasicBlockBuilder provides helpful context for going
|
||||
// from an S-Expression basic block to a DartBlock. It just lets
|
||||
// one lookup DartValue's by name at this time.
|
||||
class DartBasicBlockBuilder {
|
||||
public:
|
||||
void AddDef(llvm::StringRef name, const DartValue* v) { defs_[name] = v; }
|
||||
const DartValue* GetDef(llvm::StringRef name) const {
|
||||
auto iter = defs_.find(name);
|
||||
if (iter != defs_.end()) return iter->getValue();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringMap<const DartValue*> defs_;
|
||||
};
|
||||
|
||||
// A DartConstant is a DartValue for a constant.
|
||||
class DartConstant : public DartValue {
|
||||
public:
|
||||
std::string str;
|
||||
enum class Type { String };
|
||||
Type type;
|
||||
|
||||
llvm::Value* Make(BasicBlockBuilder& bb_builder) const override;
|
||||
llvm::Type* GetType(BasicBlockBuilder& bb_builder) const override;
|
||||
};
|
||||
|
||||
// Class DartInstruction represents a step within a DartBasicBlock.
|
||||
// CheckStackOverflow or PushArgument are instructions. They contain
|
||||
// DartValues as arguments typically. SSA definitions are also
|
||||
// DartInstructions which assign DartValues to names in the function's
|
||||
// context.
|
||||
class DartInstruction {
|
||||
public:
|
||||
virtual ~DartInstruction();
|
||||
virtual void Build(BasicBlockBuilder& bb_builder) const = 0;
|
||||
};
|
||||
|
||||
// Class InstCheckStackOverflow is a DartInstruction that represents
|
||||
// an instance of a CheckStackOverflow instruction.
|
||||
class InstCheckStackOverflow : public DartInstruction {
|
||||
public:
|
||||
InstCheckStackOverflow() {}
|
||||
~InstCheckStackOverflow() override {}
|
||||
void Build(BasicBlockBuilder& bb_builder) const override;
|
||||
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder);
|
||||
};
|
||||
|
||||
// Class InstPushArgument is a DartInstruction that represents
|
||||
// and instance of a PushArgument Instruction.
|
||||
class InstPushArgument : public DartInstruction {
|
||||
public:
|
||||
explicit InstPushArgument(const DartValue* arg) : arg_(arg) {}
|
||||
~InstPushArgument() override {}
|
||||
void Build(BasicBlockBuilder& bb_builder) const override;
|
||||
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder);
|
||||
|
||||
private:
|
||||
const DartValue* arg_;
|
||||
};
|
||||
|
||||
// Class InstStaticCall is a DartInstruction that represents a
|
||||
// StaticCall instruction.
|
||||
class InstStaticCall : public DartInstruction {
|
||||
public:
|
||||
InstStaticCall(const DartValue* func, size_t args_len)
|
||||
: function_(func), args_len_(args_len) {}
|
||||
~InstStaticCall() override {}
|
||||
void Build(BasicBlockBuilder& bb_builder) const override;
|
||||
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder);
|
||||
|
||||
private:
|
||||
const DartValue* function_;
|
||||
size_t args_len_;
|
||||
};
|
||||
|
||||
// Class InstReturn is a DartInstruction that represents a Return
|
||||
// instruction.
|
||||
class InstReturn : public DartInstruction {
|
||||
public:
|
||||
InstReturn() {}
|
||||
~InstReturn() override {}
|
||||
void Build(BasicBlockBuilder& bb_builder) const override;
|
||||
static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
|
||||
dart::SExpList* inst,
|
||||
DartBasicBlockBuilder& bb_builder);
|
||||
};
|
||||
|
||||
// Class DartBlock represents a validated basic block as parsed from
|
||||
// a (block ...) S-Expression.
|
||||
struct DartBlock {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<DartInstruction>> instructions;
|
||||
};
|
||||
|
||||
// Class DartFunction represents a validated function parsed from a
|
||||
// (function ...) S-Expression.
|
||||
struct DartFunction {
|
||||
std::string name;
|
||||
DartBlock* normal_entry;
|
||||
llvm::StringMap<DartConstant> constants;
|
||||
llvm::StringMap<DartBlock> blocks;
|
||||
};
|
||||
|
||||
// MakeFunction takes an S-Expression and an environment of externally
|
||||
// defined DartValues and produces a DartFunction corresponding to the
|
||||
// S-Expression if everything is valid. If something about the syntax
|
||||
// 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_
|
|
@ -1,150 +0,0 @@
|
|||
// 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 "dart.h"
|
||||
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
StringRef tool_name;
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void error(Twine message) {
|
||||
WithColor::error(errs(), "llvm-codegen") << message << ".\n";
|
||||
errs().flush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void error(Error e) {
|
||||
assert(e);
|
||||
std::string buf;
|
||||
raw_string_ostream os(buf);
|
||||
logAllUnhandledErrors(std::move(e), os);
|
||||
os.flush();
|
||||
WithColor::error(errs(), tool_name) << buf;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
|
||||
assert(EC);
|
||||
error(createFileError(File, EC));
|
||||
}
|
||||
|
||||
// We need a prelude function for printing to help get something functional
|
||||
// up off the ground.
|
||||
class DartPrint : public DartValue {
|
||||
public:
|
||||
Type* GetType(BasicBlockBuilder& bbb) const override {
|
||||
auto& ctx = bbb.Context();
|
||||
auto int8ty = IntegerType::getInt8Ty(ctx);
|
||||
auto i8ptr = PointerType::get(int8ty, 0);
|
||||
SmallVector<Type*, 1> arg_types;
|
||||
arg_types.push_back(i8ptr);
|
||||
return FunctionType::get(Type::getVoidTy(ctx), arg_types, false);
|
||||
}
|
||||
Value* Make(BasicBlockBuilder& bbb) const override {
|
||||
auto ft = dyn_cast<FunctionType>(GetType(bbb));
|
||||
if (ft == nullptr) return nullptr;
|
||||
return Function::Create(ft, Function::ExternalLinkage, "dart:core::print",
|
||||
bbb.Module());
|
||||
}
|
||||
};
|
||||
|
||||
cl::opt<std::string> sexpr_file(cl::Positional,
|
||||
cl::desc("The input S-Expression file"));
|
||||
cl::opt<std::string> dump_obj(
|
||||
"dump-obj",
|
||||
cl::desc("Specifies where to output the .o file"));
|
||||
|
||||
void Dump(Module* module, StringRef file, TargetMachine::CodeGenFileType type) {
|
||||
legacy::PassManager pm;
|
||||
std::error_code ec;
|
||||
raw_fd_ostream out(file, ec);
|
||||
if (ec) reportError(file, ec);
|
||||
Triple target_triple{sys::getDefaultTargetTriple()};
|
||||
TargetOptions options;
|
||||
std::string err;
|
||||
const Target* the_target =
|
||||
TargetRegistry::lookupTarget(target_triple.getTriple(), err);
|
||||
if (the_target == nullptr) error(err);
|
||||
std::unique_ptr<TargetMachine> target(the_target->createTargetMachine(
|
||||
target_triple.getTriple(), "generic", "", options, Reloc::PIC_));
|
||||
|
||||
if (target->addPassesToEmitFile(pm, out, nullptr, type, false))
|
||||
error("couldn't add pass to emit file");
|
||||
pm.run(*module);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
// Init llvm
|
||||
InitLLVM X(argc, argv);
|
||||
InitializeAllTargetInfos();
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmParsers();
|
||||
InitializeAllAsmPrinters();
|
||||
|
||||
// Basic init
|
||||
tool_name = argv[0];
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
|
||||
|
||||
// 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::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());
|
||||
|
||||
// Setup our basic prelude
|
||||
StringMap<const DartValue*> prelude;
|
||||
DartPrint print;
|
||||
prelude["dart:core::print"] = &print;
|
||||
|
||||
// Convert the function into an error checked format
|
||||
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)
|
||||
error(Twine("function ") + dart_function.name + " has no normal-entry");
|
||||
|
||||
// Setup state for output an LLVMModule
|
||||
LLVMContext context;
|
||||
auto module = llvm::make_unique<Module>(argv[1], context);
|
||||
auto function_type = FunctionType::get(Type::getVoidTy(context), {}, false);
|
||||
auto function = Function::Create(function_type, Function::ExternalLinkage,
|
||||
dart_function.name, module.get());
|
||||
FunctionBuilder fb{context, *module, *function};
|
||||
for (auto& bbkey : dart_function.blocks) {
|
||||
auto& bb = bbkey.getValue();
|
||||
auto llvmbb = fb.AddBasicBlock(bb.name);
|
||||
BasicBlockBuilder bbb{llvmbb, fb};
|
||||
for (auto& inst : bb.instructions) {
|
||||
inst->Build(bbb);
|
||||
}
|
||||
}
|
||||
|
||||
// Dump and print the file
|
||||
if (!dump_obj.empty())
|
||||
Dump(module.get(), dump_obj, LLVMTargetMachine::CGFT_ObjectFile);
|
||||
|
||||
module->print(llvm::outs(), nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# 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.
|
||||
|
||||
group("test") {
|
||||
deps = [
|
||||
"bit",
|
||||
"codegen",
|
||||
]
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import("../bit_test.gni")
|
||||
|
||||
bit_test("bit") {
|
||||
tests = [ "basic.test" ]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
; RUN: %{codegen} %p/../../codegen/Inputs/hello.sexp
|
|
@ -1 +0,0 @@
|
|||
this is a percent sign: %
|
|
@ -1,8 +0,0 @@
|
|||
; RUN: echo this is a test > %t1
|
||||
; RUN: echo this is a test > %t2
|
||||
; RUN: cmp %t1 %t2
|
||||
; RUN: echo this is a percent sign: % > %t3
|
||||
; RUN: cmp %t3 %p/Inputs/percent.test
|
||||
; RUN: %{bit} %p/Inputs/basic_input.test %P > %t.test
|
||||
; RUN: echo Commands run: 1 > %t.test2
|
||||
; RUN: cmp %t.test %t.test2
|
|
@ -1,38 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import("../../../build/executable_suffix.gni")
|
||||
|
||||
# This file defines a template for running bit tests.
|
||||
#
|
||||
# - bit_test()
|
||||
# Runs bit on the specified file.
|
||||
|
||||
# A template for running bit. This lets bit commands be run as ninja commands.
|
||||
#
|
||||
# Parameters:
|
||||
# tests:
|
||||
# The list of files to input into bit
|
||||
template("bit_test") {
|
||||
assert(defined(invoker.tests), "tests must be defined for $target_name")
|
||||
|
||||
action_foreach(target_name) {
|
||||
script = "//runtime/llvm_codegen/test/run_bit.py"
|
||||
sources = invoker.tests
|
||||
|
||||
deps = [ "../../bit" ]
|
||||
inputs = [ "${root_out_dir}/bit$executable_suffix" ]
|
||||
|
||||
# This output is always dirty so ninja will always run this step when asked to.
|
||||
outputs = [ "$target_gen_dir/{{source_name_part}}}" ]
|
||||
args = [
|
||||
"--bit",
|
||||
rebase_path("${root_out_dir}/bit"),
|
||||
"--test",
|
||||
"{{source}}",
|
||||
"--out",
|
||||
rebase_path(target_gen_dir),
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import("../bit_test.gni")
|
||||
|
||||
bit_test("codegen") {
|
||||
tests = [ "hello.test" ]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Hello, World!
|
|
@ -1,35 +0,0 @@
|
|||
; ModuleID = '../../runtime/llvm_codegen/test/codegen/Inputs/hello.sexp'
|
||||
source_filename = "../../runtime/llvm_codegen/test/codegen/Inputs/hello.sexp"
|
||||
|
||||
@0 = constant [14 x i8] c"Hello, World!\00"
|
||||
|
||||
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
|
||||
|
||||
4: ; preds = %B1
|
||||
call void @llvm.trap()
|
||||
br label %5
|
||||
|
||||
5: ; preds = %4, %B1
|
||||
call void @"dart:core::print"(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare i8* @llvm.stacksave() #0
|
||||
|
||||
; Function Attrs: cold noreturn nounwind
|
||||
declare void @llvm.trap() #1
|
||||
|
||||
declare void @"dart:core::print"(i8*)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #0
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { cold noreturn nounwind }
|
|
@ -1,9 +0,0 @@
|
|||
(function hello.dart::main
|
||||
(constants
|
||||
(def v2 "Hello, World!"))
|
||||
(normal-entry B1)
|
||||
(block B1
|
||||
(CheckStackOverflow)
|
||||
(PushArgument v2)
|
||||
(StaticCall dart:core::print { args_len 1, env (v0 arg[0]), })
|
||||
(Return v0)))
|
|
@ -1,38 +0,0 @@
|
|||
// 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.
|
||||
|
||||
.data
|
||||
|
||||
.type _threadObject,@object
|
||||
.size _threadObject,1400
|
||||
_threadObject:
|
||||
.fill 1400
|
||||
|
||||
.text
|
||||
.file "runtime.S"
|
||||
|
||||
.globl main
|
||||
.type main,@function
|
||||
|
||||
.globl "dart:core::print"
|
||||
.type "dart:core::print",@function
|
||||
|
||||
.globl arch_prctl
|
||||
.type arch_prctl,@function
|
||||
|
||||
main:
|
||||
movq %rsp, %rax
|
||||
subq $0x1000, %rax
|
||||
movq %rax, [_threadObject + 72]
|
||||
# Pass ARCH_SET_GS
|
||||
movq $0x1001, %rdi
|
||||
# Pass $_threadObject
|
||||
movq $_threadObject, %rsi
|
||||
callq arch_prctl
|
||||
callq "hello.dart::main"
|
||||
ret
|
||||
|
||||
"dart:core::print":
|
||||
callq puts
|
||||
ret
|
|
@ -1,6 +0,0 @@
|
|||
; RUN: %{codegen} %p/Inputs/hello.sexp --dump-obj %t.o > %t.ll
|
||||
; RUN: diff %t.ll %p/Inputs/hello.ll.expected
|
||||
; RUN: %{clang} -g -c %p/Inputs/runtime.S -o %t.runtime.o
|
||||
; RUN: %{clang} %t.o %t.runtime.o -o %t.hello.exe
|
||||
; RUN: %t.hello.exe > %t.hello.exe.stdout
|
||||
; RUN: diff %t.hello.exe.stdout %p/Inputs/hello.expected
|
|
@ -1,15 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="A tool to run the bit integration tester")
|
||||
parser.add_argument("--bit", help="Sets the path to bit")
|
||||
parser.add_argument("--test", help="Path to test to be run")
|
||||
parser.add_argument("--out", help="Path to out directory")
|
||||
args = parser.parse_args()
|
||||
|
||||
subprocess.check_call([args.bit, args.test, args.out])
|
||||
|
|
@ -108,12 +108,6 @@ final Set<String> excludedFiles = Set<String>.from([
|
|||
'runtime/vm/stack_frame_ia32.h',
|
||||
'runtime/vm/stack_frame_x64.h',
|
||||
|
||||
// By default the gclient checkout doesn't have llvm pulled in.
|
||||
'runtime/llvm_codegen/bit/bit.h',
|
||||
'runtime/llvm_codegen/bit/main.cc',
|
||||
'runtime/llvm_codegen/bit/test.cc',
|
||||
'runtime/llvm_codegen/codegen/main.cc',
|
||||
|
||||
// Only available in special builds
|
||||
'runtime/bin/io_service_no_ssl.h',
|
||||
'runtime/bin/utils_win.h',
|
||||
|
|
1520
third_party/llvm/BUILD.gn
vendored
1520
third_party/llvm/BUILD.gn
vendored
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue