// 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 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(GetType(bbb)); if (ft == nullptr) return nullptr; return Function::Create(ft, Function::ExternalLinkage, "dart:core::print", bbb.Module()); } }; cl::opt sexpr_file(cl::Positional, cl::desc("The input S-Expression file")); cl::opt 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 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 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 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(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; }