4ea512b4c1
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>
151 lines
4.7 KiB
C++
151 lines
4.7 KiB
C++
// 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;
|
|
}
|