aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/GlobalGen.cc
blob: 46b6f0cbf0b622397e66a7aa4ae11872403b0dc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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->hasFunction(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");
            }
        }
    }
}