diff options
| author | Nagi5Yeq <wu@x-nagi.com> | 2020-06-01 11:02:24 +0800 |
|---|---|---|
| committer | Nagi5Yeq <wu@x-nagi.com> | 2020-06-01 11:02:24 +0800 |
| commit | 241f27a653330af1227694947626f409c3b128e2 (patch) | |
| tree | 02f2eb98a78e7de6b8ccb9af1016688b009ecb63 | |
| parent | f3729aee72a60578738f0c2fddcca2831019f546 (diff) | |
message formatting, assembly and object support
| -rw-r--r-- | Driver.cc | 2 | ||||
| -rw-r--r-- | Lexer.l | 2 | ||||
| -rw-r--r-- | Log.cc | 35 | ||||
| -rw-r--r-- | Log.hh | 31 | ||||
| -rw-r--r-- | Type.cc | 2 | ||||
| -rw-r--r-- | TypeManager.cc | 14 | ||||
| -rw-r--r-- | VariableList.cc | 4 | ||||
| -rw-r--r-- | Version.cc | 22 | ||||
| -rw-r--r-- | main.cc | 64 | ||||
| -rw-r--r-- | node/ExprNode.cc | 22 | ||||
| -rw-r--r-- | node/FunctionNode.cc | 6 | ||||
| -rw-r--r-- | node/Node.hh | 2 | ||||
| -rw-r--r-- | node/StatementNode.cc | 6 |
13 files changed, 132 insertions, 80 deletions
@@ -14,7 +14,7 @@ std::shared_ptr<ProgramNode> Driver::Parse(std::string& filename) { return nullptr; } Parser parser(*this, &context_); - if (CurrentLogLevel == pcc::PCC_DEBUG) { + if (GetLogLevel() == pcc::PCC_DEBUG) { parser.set_debug_level(1); } parser.parse(); @@ -176,7 +176,7 @@ comment {comment1}|{comment2} namespace pcc { int Driver::StartLexer(std::string& filename) { - yy_flex_debug = (CurrentLogLevel==LogLevel::PCC_DEBUG); + yy_flex_debug = (GetLogLevel()==LogLevel::PCC_DEBUG); yyin = std::fopen(filename.c_str(), "r"); if (yyin == NULL) { Log(LogLevel::PCC_ERROR, "Failed to open file %s", filename.c_str()); @@ -1,31 +1,16 @@ +#include <string> +#include <utility> + #include "Log.hh" namespace pcc { -void Log(LogLevel level, const char* format, ...) { - va_list va; - va_start(va, format); - if (CurrentLogLevel <= level) { - switch (level) { - case PCC_ERROR: - std::fprintf(stderr, "[ERROR] "); - break; - case PCC_WARNING: - std::fprintf(stderr, "[WARNING] "); - break; - case PCC_INFO: - std::fprintf(stderr, "[INFO] "); - break; - case PCC_DEBUG: - std::fprintf(stderr, "[DEBUG] "); - break; - } - std::vfprintf(stderr, format, va); - std::fputc('\n', stderr); - } - va_end(va); -} - -LogLevel CurrentLogLevel = PCC_ERROR; +static LogLevel CurrentLogLevel = PCC_ERROR; void SetLogLevel(LogLevel level) { CurrentLogLevel = level; } +LogLevel GetLogLevel() { return CurrentLogLevel; } + +static std::string Executable("pcc"); + +void SetExecutableName(const char* name) { Executable = name; } +const char* GetExecutableName() { return Executable.c_str(); } } // namespace pcc @@ -4,14 +4,39 @@ #include <cstdarg> #include <cstdio> +#include <llvm/Support/FormatVariadic.h> +#include <llvm/Support/WithColor.h> + namespace pcc { enum LogLevel { PCC_DEBUG, PCC_INFO, PCC_WARNING, PCC_ERROR }; -extern LogLevel CurrentLogLevel; - void SetLogLevel(LogLevel level); +LogLevel GetLogLevel(); + +void SetExecutableName(const char* name); +const char* GetExecutableName(); -void Log(LogLevel level, const char* format, ...); +template <typename... Args> +void Log(LogLevel level, const char* format, Args&&... args) { + auto msg = llvm::formatv(format, std::forward<Args>(args)...); + const char* name = GetExecutableName(); + switch (level) { + case PCC_DEBUG: + llvm::WithColor::remark(llvm::errs(), name) << msg << '\n'; + break; + case PCC_INFO: + llvm::WithColor::note(llvm::errs(), name) << msg << '\n'; + break; + case PCC_WARNING: + llvm::WithColor::warning(llvm::errs(), name) << msg << '\n'; + break; + case PCC_ERROR: + llvm::WithColor::error(llvm::errs(), name) << msg << '\n'; + break; + default: + break; + } +} } // namespace pcc #endif @@ -375,7 +375,7 @@ std::pair<int, std::shared_ptr<Type>> RecordType::GetMember(const std::string& name) { decltype(members_.end()) result = members_.find(name); if (result == members_.end()) { - Log(LogLevel::PCC_ERROR, "the member %s doesn't exist", name.c_str()); + Log(LogLevel::PCC_ERROR, "the member {0} doesn't exist", name.c_str()); return {0, nullptr}; } return std::get<1>(*result); diff --git a/TypeManager.cc b/TypeManager.cc index 7402875..b790dd4 100644 --- a/TypeManager.cc +++ b/TypeManager.cc @@ -44,14 +44,14 @@ std::pair<std::shared_ptr<Type>, Value> // add/sub a pointer with a integer if (LeftPointerType != nullptr && RightPointerType == nullptr) { if (op != BinaryOperator::ADD && op != BinaryOperator::SUB) { - Log(LogLevel::PCC_ERROR, "unsupported operation %s on %s and %s", + Log(LogLevel::PCC_ERROR, "unsupported operation {0} on %s and {1}", GetOperatorName(op), LeftType->GetCommonName(), RightType->GetCommonName()); return {nullptr, nullptr}; } if (RightIntegerBaseType == nullptr) { Log(LogLevel::PCC_ERROR, - "can not add pointer with non-integer type %s", + "can not add pointer with non-integer type {0}", RightType->GetCommonName()); return {nullptr, nullptr}; } @@ -101,7 +101,7 @@ std::pair<std::shared_ptr<Type>, Value> : RightType); } else { Log(LogLevel::PCC_ERROR, - "can not apply binary operator on two different type %s and %s", + "can not apply binary operator on two different type {0} and {1}", LeftType->GetCommonName(), RightType->GetCommonName()); return {nullptr, nullptr}; } @@ -114,7 +114,7 @@ std::pair<std::shared_ptr<Type>, Value> ConvertedRight, context); if (result == nullptr) { Log(LogLevel::PCC_ERROR, - "binary operator %s is not supported on type %s", + "binary operator {0} is not supported on type {1}", GetOperatorName(op), CommonType->GetCommonName()); } // logical operators return boolean type @@ -130,7 +130,7 @@ Value TypeManager::CreateOperation(UnaryOperator op, std::shared_ptr<Type> type, Value result = type->CreateUnaryOperation(op, v, context); if (result == nullptr) { Log(LogLevel::PCC_ERROR, - "unary operator %s is not supported on type %s", + "unary operator {0} is not supported on type {1}", GetOperatorName(op), type->GetCommonName()); } return result; @@ -179,7 +179,7 @@ Value TypeManager::CreateCast(std::shared_ptr<Type> DstType, return builder->CreateInBoundsGEP(v, indices); } } - Log(LogLevel::PCC_ERROR, "unsupported type casting from %s to %s", + Log(LogLevel::PCC_ERROR, "unsupported type casting from {0} to {1}", SrcType->GetCommonName(), DstType->GetCommonName()); return nullptr; } @@ -209,7 +209,7 @@ std::shared_ptr<ArrayType> if (IndexType != end->GetType()) { Log(LogLevel::PCC_ERROR, "the start and end indices of an array type must be same " - "(start=%s, end=%s)", + "(start={0}, end={1})", IndexType->GetCommonName(), end->GetType()->GetCommonName()); return nullptr; } diff --git a/VariableList.cc b/VariableList.cc index eef1205..e112bac 100644 --- a/VariableList.cc +++ b/VariableList.cc @@ -19,7 +19,7 @@ Variable VariableList::FindVariable(const std::string& name) { } } if (found == false) { - Log(LogLevel::PCC_ERROR, "unknown identifier %s", name.c_str()); + Log(LogLevel::PCC_ERROR, "unknown identifier {0}", name); return {nullptr, nullptr}; } return std::get<1>(*result); @@ -43,7 +43,7 @@ std::shared_ptr<Type> VariableList::FindTypeAlias(const std::string& name) { } } if (found == false) { - Log(LogLevel::PCC_ERROR, "unknown type alias %s", name.c_str()); + Log(LogLevel::PCC_ERROR, "unknown type alias {0}", name); return nullptr; } return std::get<1>(*result); @@ -25,16 +25,18 @@ PCC_NORETURN void ShowVersion() { PCC_NORETURN void ShowHelp() { std::cerr << PCC_NAME " version " PCC_VERSION_STRING "\n" - << "Usage: " PCC_NAME " [-vVhiSc] file...\n" - << " -v Verbose mode.\n" - << " -vv Very verbose mode.\n" - << " -V Show version and exit.\n" - << " -h Show this help and exit.\n" - << " -i Generate LLVM IR (default behavior).\n" - << " -S Compile to assembly.\n" - << " -c Compile to object file.\n" - << " -o <file> Specify output file name." - << std::endl; + << "Usage: " PCC_NAME + " [-vVhiSc] [-O <0,1,2,3>] [-o <output>] file...\n" + << " -v Verbose mode.\n" + << " -vv Very verbose mode.\n" + << " -V Show version and exit.\n" + << " -h Show this help and exit.\n" + << "\n" + << " -i Generate LLVM IR (default behavior).\n" + << " -S Compile to assembly file.\n" + << " -c Compile to object file.\n" + << " -o <output> Specify output file name.\n" + << " -O <0,1,2,3> Specify optimization level." << std::endl; std::exit(0); } @@ -6,21 +6,28 @@ #include <unistd.h> #endif +#include <llvm/IR/LegacyPassManager.h> +#include <llvm/IR/Verifier.h> #include <llvm/Support/TargetRegistry.h> #include <llvm/Support/TargetSelect.h> -#include <llvm/Support/raw_ostream.h> #include <llvm/Target/TargetMachine.h> #include "Driver.hh" #include "Log.hh" #include "Version.hh" +void compile(llvm::Module* module, llvm::raw_pwrite_stream& output, + llvm::CodeGenFileType type, llvm::TargetMachine* machine); + int main(int argc, char* argv[]) { int rv; int level = pcc::ToUnderlying(pcc::PCC_WARNING); std::string OutputFileName; enum { IR, ASSEMBLY, OBJECT } CompileType = IR; - while ((rv = getopt(argc, argv, "vVhiSco:")) != -1) { + int OptLevel = 2; + + pcc::SetExecutableName(argv[0]); + while ((rv = getopt(argc, argv, "vVhiSco:O:")) != -1) { switch (rv) { case 'v': level = (level == 0 ? 0 : level - 1); @@ -41,11 +48,20 @@ int main(int argc, char* argv[]) { case 'o': OutputFileName = optarg; break; + case 'O': + OptLevel = optarg[0] - '0'; + if (OptLevel > 3 || OptLevel < 0) { + pcc::Log(pcc::PCC_ERROR, + "{0} is not a valid optimization level", optarg[0]); + pcc::ShowHelp(); + } + break; default: - pcc::Log(pcc::PCC_ERROR, "Unknown option \"%c\".", rv); + pcc::Log(pcc::PCC_ERROR, "Unknown option"); pcc::ShowHelp(); } } + pcc::SetLogLevel(static_cast<pcc::LogLevel>(level)); llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmParser(); @@ -56,24 +72,30 @@ int main(int argc, char* argv[]) { llvm::TargetRegistry::lookupTarget(triple, error); if (!error.empty()) { pcc::Log(pcc::PCC_ERROR, - "failed to find target with triple %s, reason %s", + "failed to find target with triple {0}, reason {1}", triple.c_str(), error.c_str()); return -1; } + const llvm::CodeGenOpt::Level optimization[] = { + llvm::CodeGenOpt::None, llvm::CodeGenOpt::Less, + llvm::CodeGenOpt::Default, llvm::CodeGenOpt::Aggressive}; std::string cpu = "generic"; std::string features = ""; llvm::TargetOptions options; llvm::TargetMachine* machine = - target->createTargetMachine(triple, cpu, features, options, llvm::None); + target->createTargetMachine(triple, cpu, features, options, llvm::None, + llvm::None, optimization[OptLevel]); llvm::DataLayout layout = machine->createDataLayout(); + if (optind >= argc) { pcc::Log(pcc::PCC_ERROR, "No input file specified"); return -1; } if (!OutputFileName.empty() && optind != argc - 1) { - pcc::Log(pcc::LogLevel::PCC_WARNING, + pcc::Log(pcc::PCC_WARNING, "more than one source file specified, the output file name " "will be ignored"); + OutputFileName.clear(); } for (int i = optind; i < argc; i++) { pcc::Driver driver(argv[i]); @@ -84,33 +106,51 @@ int main(int argc, char* argv[]) { std::shared_ptr<pcc::ProgramNode> root = driver.Parse(filename); if (root != nullptr) { root->CodeGen(); + std::string msg; + llvm::raw_string_ostream MsgStream(msg); + llvm::verifyModule(*module, &MsgStream); + MsgStream.flush(); + if (!msg.empty()) { + pcc::Log(pcc::PCC_WARNING, "{0}", msg.c_str()); + } + } else { + continue; } if (OutputFileName.empty()) { - const char* postfixs[] = {".ll", ".s", ".o"}; + const char* postfix[] = {".ll", ".s", ".o"}; size_t PostfixPos = filename.rfind(".pas"); if (PostfixPos == std::string::npos) { - OutputFileName = filename + postfixs[CompileType]; + OutputFileName = filename + postfix[CompileType]; } else { OutputFileName = - filename.substr(0, PostfixPos) + postfixs[CompileType]; + filename.substr(0, PostfixPos) + postfix[CompileType]; } } std::error_code ErrorCode; - llvm::raw_fd_ostream Output(OutputFileName, ErrorCode); + llvm::raw_fd_ostream output(OutputFileName, ErrorCode); switch (CompileType) { case IR: - module->print(Output, nullptr); + module->print(output, nullptr); break; case ASSEMBLY: + compile(module, output, llvm::CGFT_AssemblyFile, machine); break; case OBJECT: + compile(module, output, llvm::CGFT_ObjectFile, machine); break; default: break; } - pcc::Log(pcc::LogLevel::PCC_INFO, "%s compiled to %s", argv[i], + pcc::Log(pcc::PCC_INFO, "{0} compiled to {1}", argv[i], OutputFileName.c_str()); OutputFileName.clear(); } return 0; } + +void compile(llvm::Module* module, llvm::raw_pwrite_stream& output, + llvm::CodeGenFileType type, llvm::TargetMachine* machine) { + llvm::legacy::PassManager manager; + machine->addPassesToEmitFile(manager, output, nullptr, type); + manager.run(*module); +} diff --git a/node/ExprNode.cc b/node/ExprNode.cc index e75eda5..d785534 100644 --- a/node/ExprNode.cc +++ b/node/ExprNode.cc @@ -66,7 +66,7 @@ Value L2RCastingNode::CodeGen() { std::dynamic_pointer_cast<PointerType>(lvalue_->GetType()); if (type == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid pointer type, this lvalue can't be loaded", + "type {0} is not a valid pointer type, this lvalue can't be loaded", lvalue_->GetType()->GetCommonName()); } type_ = type->GetElementType(); @@ -87,7 +87,7 @@ Value PointerAccessNode::CodeGen() { std::dynamic_pointer_cast<PointerType>(lhs_->GetType()); if (pointer == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid type for pointer access operator[]", + "type {0} is not a valid type for pointer access operator[]", lhs_->GetType()->GetCommonName()); return nullptr; } @@ -114,7 +114,7 @@ Value ArrayAccessNode::CodeGen() { std::shared_ptr<Type> RightType = rhs_->GetType(); if (LeftType == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid type for array access operator[]", + "type {0} is not a valid type for array access operator[]", lhs_->GetType()->GetCommonName()); return nullptr; } @@ -147,7 +147,7 @@ Value ArrayAccessNode::CodeGen() { return builder->CreateInBoundsGEP(PointerValue, CastedRight); } Log(LogLevel::PCC_ERROR, - "type %s is not a valid lvalue type for array access operator[]", + "type {0} is not a valid lvalue type for array access operator[]", lhs_->GetType()->GetCommonName()); return nullptr; } @@ -162,7 +162,7 @@ Value DereferenceNode::CodeGen() { std::shared_ptr<PointerType> pointer = std::dynamic_pointer_cast<PointerType>(lhs_->GetType()); if (pointer == nullptr) { - Log(LogLevel::PCC_ERROR, "type %s is not a valid type for dereference", + Log(LogLevel::PCC_ERROR, "type {0} is not a valid type for dereference", lhs_->GetType()->GetCommonName()); return nullptr; } @@ -187,14 +187,14 @@ Value MemberAccessNode::CodeGen() { std::dynamic_pointer_cast<PointerType>(lhs_->GetType()); if (LeftType == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid type for member access", + "type {0} is not a valid type for member access", lhs_->GetType()->GetCommonName()); return nullptr; } std::shared_ptr<RecordType> LeftInner = std::dynamic_pointer_cast<RecordType>(LeftType->GetElementType()); if (LeftInner == nullptr) { - Log(LogLevel::PCC_ERROR, "type %s is not a record type", + Log(LogLevel::PCC_ERROR, "type {0} is not a record type", LeftType->GetElementType()->GetCommonName()); return nullptr; } @@ -229,14 +229,14 @@ Value FunctionCallNode::CodeGen() { Function function = context_->FindFunction(name_); std::shared_ptr<FunctionType> type = std::get<0>(function); if (type == nullptr) { - Log(LogLevel::PCC_ERROR, "call to undefined function %s", + Log(LogLevel::PCC_ERROR, "call to undefined function {0}", name_.c_str()); return nullptr; } const std::vector<std::shared_ptr<Type>>& ArgTypes = type->GetArgTypes(); if (type->IsVariadic() == false && ArgTypes.size() != args_.size()) { Log(LogLevel ::PCC_ERROR, - "argument number mismatch, %d wanted, %d given", ArgTypes.size(), + "argument number mismatch, {0} wanted, {1} given", ArgTypes.size(), args_.size()); return nullptr; } @@ -249,8 +249,8 @@ Value FunctionCallNode::CodeGen() { manager->CreateCast(ArgType, (*ArgIt)->GetType(), argv, context_); if (ConvertedArgv == nullptr) { Log(LogLevel ::PCC_ERROR, - "argument type mismatch, the function type is %s, an argument " - "of type %s needed", + "argument type mismatch, the function type is {0}, an argument " + "of type {1} needed", type->GetCommonName(), ArgType->GetCommonName()); } *ArgValueIt = ConvertedArgv; diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc index 4fb5138..e2ab18f 100644 --- a/node/FunctionNode.cc +++ b/node/FunctionNode.cc @@ -47,7 +47,7 @@ Value FunctionNode::CodeGen() { context_->AddFunction(name_, {type, function}); llvm::BasicBlock* block = llvm::BasicBlock::Create(GlobalLLVMContext, name_, function); - Log(LogLevel::PCC_INFO, "generating function %s of type %s", name_.c_str(), + Log(LogLevel::PCC_INFO, "generating function {0} of type {0}", name_, type->GetCommonName()); builder->SetInsertPoint(block); context_->PushScope(&locals_); @@ -86,7 +86,7 @@ Value FunctionNode::CodeGen() { llvm::verifyFunction(*function, &MsgStream); MsgStream.flush(); if (!msg.empty()) { - Log(LogLevel::PCC_INFO, "%s", msg.c_str()); + Log(LogLevel::PCC_WARNING, "{0}", msg); } return nullptr; } @@ -117,7 +117,7 @@ Value ExternNode::CodeGen() { llvm::Function* function = llvm::cast<llvm::Function>(callee.getCallee()); function->setCallingConv(llvm::CallingConv::C); context_->AddFunction(name_, {type, function}); - Log(LogLevel::PCC_INFO, "extern function %s of type %s", name_.c_str(), + Log(LogLevel::PCC_INFO, "extern function {0} of type {1}", name_, type->GetCommonName()); return nullptr; } diff --git a/node/Node.hh b/node/Node.hh index c75126c..343f763 100644 --- a/node/Node.hh +++ b/node/Node.hh @@ -4,8 +4,8 @@ #include "BaseNode.hh" #include "DeclNode.hh" #include "ExprNode.hh" +#include "FunctionNode.hh" #include "LiteralNode.hh" #include "StatementNode.hh" -#include "FunctionNode.hh" #endif // !PCC_NODE_H diff --git a/node/StatementNode.cc b/node/StatementNode.cc index 07babe2..40c07af 100644 --- a/node/StatementNode.cc +++ b/node/StatementNode.cc @@ -36,7 +36,7 @@ Value AssignStatementNode::CodeGen() { std::dynamic_pointer_cast<PointerType>(lhs_->GetType()); if (LeftType == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid pointer type, can't store anything into " + "type {0} is not a valid pointer type, can't store anything into " "this lvalue", lhs_->GetType()->GetCommonName()); return nullptr; @@ -212,7 +212,7 @@ Value ForStatementNode::CodeGen() { std::dynamic_pointer_cast<PointerType>(variable_->GetType()); if (LoopPointer == nullptr) { Log(LogLevel::PCC_ERROR, - "type %s is not a valid pointer type, can't store anything into " + "type {0} is not a valid pointer type, can't store anything into " "this lvalue", variable_->GetType()->GetCommonName()); return nullptr; @@ -222,7 +222,7 @@ Value ForStatementNode::CodeGen() { LoopPointer->GetElementType()); if (LoopType == nullptr) { Log(LogLevel::PCC_ERROR, - "loop variable should have a integer-like type, not %s", + "loop variable should have a integer-like type, not {0}", LoopPointer->GetElementType()->GetCommonName()); return nullptr; } |
