aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CodeGen.cc12
-rw-r--r--lib/CodeGen/ConstantGen.cc4
-rw-r--r--lib/CodeGen/FunctionGen.cc2
-rw-r--r--lib/CodeGen/GlobalGen.cc70
-rw-r--r--lib/CodeGen/StatementGen.cc5
5 files changed, 84 insertions, 9 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index e7116dd..6aa1558 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -166,8 +166,9 @@ void CodeGen::selectUnit(size_t Unit) {
void CodeGen::importSymbols() {
Symbols.clear();
for (size_t I = 0; I < Exports.size(); ++I) {
- if (I != CurrentUnit && isVisible(I))
- Symbols.insert(Exports[I].begin(), Exports[I].end());
+ if (!isVisible(I)) continue;
+ for (const auto &[Name, Info] : Exports[I])
+ if (I != CurrentUnit || Info.IsGlobal) Symbols.emplace(Name, Info);
}
}
@@ -286,6 +287,13 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) {
}
Exports[I] = Symbols;
}
+ for (int Phase = 0; Phase < 2; ++Phase) {
+ for (size_t I = 0; I < Sources.size(); ++I) {
+ selectUnit(I);
+ importSymbols();
+ runGlobalPrePass(Sources[I], Phase);
+ }
+ }
for (size_t I = 0; I < Sources.size(); ++I) {
selectUnit(I);
importSymbols();
diff --git a/lib/CodeGen/ConstantGen.cc b/lib/CodeGen/ConstantGen.cc
index 632502d..6e1ec57 100644
--- a/lib/CodeGen/ConstantGen.cc
+++ b/lib/CodeGen/ConstantGen.cc
@@ -35,11 +35,11 @@ bool CodeGen::prepareSymbolDeclaration(const std::string &Name, bool IsConstant)
auto &Scope = ConstantScopes.back();
auto It = Symbols.find(Name);
if (It != Symbols.end()) {
- if (It->second.ScopeID == Scope.ID) {
+ if (It->second.ScopeID == Scope.ID && !It->second.IsGlobal) {
reportError("Declaration of %s conflicts with an existing declaration in this scope", Name.c_str());
return false;
}
- if (IsConstant || It->second.ConstantValue) Scope.Saved.emplace(Name, It->second);
+ if (IsConstant || It->second.ConstantValue || It->second.IsGlobal) Scope.Saved.emplace(Name, It->second);
} else if (IsConstant) {
Scope.Saved.emplace(Name, std::nullopt);
}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index cc88a78..220a97a 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -220,7 +220,7 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
IdentifierMap<SymbolInfo> OldSymbols = Symbols;
Symbols.clear();
for (const auto &[Name, Info] : OldSymbols) {
- if (Info.ConstantValue && Info.ScopeID == 0) Symbols.emplace(Name, Info);
+ if (Info.IsGlobal || (Info.ConstantValue && Info.ScopeID == 0)) Symbols.emplace(Name, Info);
}
bool IsMethod = !Proto->getOwnerClass().empty();
diff --git a/lib/CodeGen/GlobalGen.cc b/lib/CodeGen/GlobalGen.cc
new file mode 100644
index 0000000..659ae85
--- /dev/null
+++ b/lib/CodeGen/GlobalGen.cc
@@ -0,0 +1,70 @@
+#include "cps/CodeGen.h"
+#include "llvm/IR/GlobalVariable.h"
+
+using namespace cps;
+using namespace llvm;
+
+namespace {
+bool isGlobalLiteral(ExprAST *Expr) {
+ if (dynamic_cast<IntegerExprAST*>(Expr) || dynamic_cast<RealExprAST*>(Expr) ||
+ dynamic_cast<CharExprAST*>(Expr) || dynamic_cast<StringExprAST*>(Expr) ||
+ dynamic_cast<BooleanExprAST*>(Expr)) return true;
+ auto *Unary = dynamic_cast<UnaryExprAST*>(Expr);
+ return Unary && Unary->getOp() == '-' &&
+ (dynamic_cast<IntegerExprAST*>(Unary->getOperand()) ||
+ dynamic_cast<RealExprAST*>(Unary->getOperand()));
+}
+}
+
+void CodeGen::runGlobalPrePass(const SourceUnit &Unit, int Phase) {
+ for (const auto &Stmt : Unit.Statements) {
+ auto *Block = dynamic_cast<GlobalBlockAST*>(Stmt.get());
+ if (!Block) continue;
+ for (const auto &S : Block->getBody()) {
+ SaveAndRestore<int> Location(DiagnosticLine, S->getLine());
+ if (auto *Decl = dynamic_cast<DeclareStmtAST*>(S.get())) {
+ if (Phase != 0) continue;
+ const auto &Name = Decl->getName();
+ const auto &TypeName = Decl->getType();
+ if (Decl->hasParens() ||
+ !(sameIdentifier(TypeName, "INTEGER") || sameIdentifier(TypeName, "REAL") ||
+ sameIdentifier(TypeName, "CHAR") || sameIdentifier(TypeName, "STRING") ||
+ sameIdentifier(TypeName, "BOOLEAN"))) {
+ reportError("GLOBAL declarations require a primitive scalar type without constructor arguments");
+ continue;
+ }
+ if (Exports[CurrentUnit].count(Name) || Types->resolve(Name) ||
+ Types->lookupEnumConstant(Name) || FuncGen->getSignature(Name) ||
+ isBuiltinName(Name)) {
+ reportError("Global %s conflicts with an existing definition", Name.c_str());
+ continue;
+ }
+ auto *Storage = new GlobalVariable(*TheModule, Types->getLLVMType(TypeName), false,
+ GlobalValue::InternalLinkage, Types->getZeroValue(TypeName), "__cps_global." + Name);
+ SymbolInfo Info{Storage, TypeName, false, nullptr, 0, false, true};
+ Exports[CurrentUnit].emplace(Name, Info);
+ } else if (auto *Assign = dynamic_cast<AssignStmtAST*>(S.get())) {
+ if (Phase != 1) continue;
+ const SymbolInfo *Info = getSymbolInfo(Assign->getName());
+ if (!Info || !Info->IsGlobal) {
+ reportError("GLOBAL initializer requires a declared global variable %s",
+ Assign->getName().c_str());
+ continue;
+ }
+ if (!isGlobalLiteral(Assign->getExpr())) {
+ reportError("GLOBAL initializer must be a literal");
+ continue;
+ }
+ auto *Value = dyn_cast_or_null<Constant>(
+ emitCoercedExpr(Assign->getExpr(), resolveType(Info->TypeName)));
+ if (!Value) {
+ reportError("GLOBAL initializer must be a constant scalar literal");
+ continue;
+ }
+ cast<GlobalVariable>(Info->Storage)->setInitializer(Value);
+ } else if (Phase == 0) {
+ reportError("GLOBAL blocks allow only primitive DECLARE statements and literal initializers");
+ }
+ }
+ }
+}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index 5edb303..5b6a13c 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -14,10 +14,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
if (!Stmt) return;
if (dynamic_cast<IncludeStmtAST*>(Stmt)) return;
- if (dynamic_cast<GlobalBlockAST*>(Stmt)) {
- reportError("GLOBAL is not supported yet");
- return;
- }
+ if (dynamic_cast<GlobalBlockAST*>(Stmt)) return;
if (auto *Class = dynamic_cast<ClassTypeDeclAST*>(Stmt)) {
for (const auto &Method : Class->getMethods()) {