| // 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; | |
| } |