diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 12 | ||||
| -rw-r--r-- | lib/CodeGen/ConstantGen.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/GlobalGen.cc | 70 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 5 |
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()) { |
