summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNagi5Yeq <wu@x-nagi.com>2020-06-01 11:02:24 +0800
committerNagi5Yeq <wu@x-nagi.com>2020-06-01 11:02:24 +0800
commit241f27a653330af1227694947626f409c3b128e2 (patch)
tree02f2eb98a78e7de6b8ccb9af1016688b009ecb63
parentf3729aee72a60578738f0c2fddcca2831019f546 (diff)
message formatting, assembly and object support
-rw-r--r--Driver.cc2
-rw-r--r--Lexer.l2
-rw-r--r--Log.cc35
-rw-r--r--Log.hh31
-rw-r--r--Type.cc2
-rw-r--r--TypeManager.cc14
-rw-r--r--VariableList.cc4
-rw-r--r--Version.cc22
-rw-r--r--main.cc64
-rw-r--r--node/ExprNode.cc22
-rw-r--r--node/FunctionNode.cc6
-rw-r--r--node/Node.hh2
-rw-r--r--node/StatementNode.cc6
13 files changed, 132 insertions, 80 deletions
diff --git a/Driver.cc b/Driver.cc
index af04805..2d7441d 100644
--- a/Driver.cc
+++ b/Driver.cc
@@ -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();
diff --git a/Lexer.l b/Lexer.l
index 6679b75..390e1ad 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -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());
diff --git a/Log.cc b/Log.cc
index a6b0657..2a8ab41 100644
--- a/Log.cc
+++ b/Log.cc
@@ -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
diff --git a/Log.hh b/Log.hh
index f18500c..561ccf2 100644
--- a/Log.hh
+++ b/Log.hh
@@ -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
diff --git a/Type.cc b/Type.cc
index 6167175..03a6d23 100644
--- a/Type.cc
+++ b/Type.cc
@@ -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);
diff --git a/Version.cc b/Version.cc
index 7bc9532..13a9b53 100644
--- a/Version.cc
+++ b/Version.cc
@@ -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);
}
diff --git a/main.cc b/main.cc
index 2ee9699..da938a8 100644
--- a/main.cc
+++ b/main.cc
@@ -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;
}