aboutsummaryrefslogtreecommitdiff
path: root/include/cps/CodeGen.h
blob: 4363126aefda9785c48a999bea4729fffe5c2f05 (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

#pragma once
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "cps/AST.h"
#include "cps/RuntimeCheck.h"
#include "cps/FunctionGen.h"
#include "cps/TypeSystem.h"

#include "cps/ArithmeticHandler.h"
#include "cps/StringHandler.h"
#include "cps/StringConversionHandler.h"

#include <map>
#include <memory>
#include <string>

namespace cps {

class ArrayHandler;
class FileHandler;
class ExceptionHandler;
class CastExprAST;

class CodeGen {
    std::unique_ptr<llvm::LLVMContext> TheContext;
    std::unique_ptr<llvm::Module> TheModule;
    std::unique_ptr<llvm::IRBuilder<>> Builder;
    std::map<std::string, SymbolInfo> Symbols;
    std::unique_ptr<TypeSystem> Types;

    std::unique_ptr<ArrayHandler> Arrays;
    std::unique_ptr<ExceptionHandler> Exceptions;
    std::unique_ptr<RuntimeCheck> RuntimeChecker;
    std::unique_ptr<FunctionGen> FuncGen;

    std::unique_ptr<ArithmeticHandler> ArithHandler;
    std::unique_ptr<StringHandler> StrHandler;
    std::unique_ptr<StringConversionHandler> StrConvHandler;
    std::unique_ptr<FileHandler> Files;

    llvm::FunctionCallee PrintfFunc;
    llvm::FunctionCallee ScanfFunc;
    llvm::FunctionCallee MallocFunc;
    
    llvm::Value *PrintfFormatStr;       // %lld\n
    llvm::Value *PrintfFloatFormatStr;  // %f\n
    llvm::Value *PrintfStringFormatStr; // %s\n
    llvm::Value *PrintfCharFormatStr;   // %c\n
    
    llvm::Value *ScanfFormatStr;        // %lld
    llvm::Value *ScanfFloatFormatStr;   // %lf
    llvm::Value *ScanfStringFormatStr;  // %s
    
    llvm::Value *TrueStr;               // "TRUE"
    llvm::Value *FalseStr;              // "FALSE"
    llvm::Value *EmptyStringStr;        // ""

    bool HadError = false;

    void SetupExternalFunctions();
    llvm::AllocaInst *CreateEntryBlockAlloca(llvm::Function *TheFunction, const std::string &VarName);
    llvm::AllocaInst *CreateEntryBlockAlloca(llvm::Function *TheFunction, llvm::Type *AllocType, const std::string &VarName);

    void registerSymbol(const std::string &Name, llvm::Value *Storage, const std::string &TypeName, bool IsArray = false);
    const SymbolInfo *getSymbolInfo(const std::string &Name) const;
    bool isWholeArrayVar(ExprAST *Expr) const;
    const TypeInfo *getExprTypeInfo(ExprAST *Expr) const;
    llvm::Value *coerceValueToType(llvm::Value *Val, const TypeInfo *TargetInfo);
    llvm::Value *convertNumericValue(llvm::Value *Val, const TypeInfo *Source,
                                     const TypeInfo *Target);
    llvm::Value *emitCast(CastExprAST *Cast);
    llvm::Value *emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const TypeInfo *Right);
    void emitCOutput(llvm::Value *Val, const TypeInfo *Info, bool AppendNewline);
    void emitCInput(const SymbolInfo *Symbol, const TypeInfo *Info);

    // TYPE-system helpers (Designator.cc).
    void runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statements);
    llvm::Value *emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, const TypeInfo *RT);

    // An addressable location and the pseudocode type stored there.
    struct LValueInfo {
        llvm::Value *Addr = nullptr;
        std::string TypeName;
    };
    // Resolves a variable / array element / field chain / deref to an address
    // (emitting index and null-pointer checks along the way).
    bool emitLValue(ExprAST *E, LValueInfo &Out);
    // The rvalue read: load + the STRING null->"" guard.
    llvm::Value *loadFromLValue(const LValueInfo &LV);
    bool marshalCallArgs(const std::string &Callee,
                         const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
                         int Line,
                         std::vector<llvm::Value*> &Out);
    void emitDeclareStmt(DeclareStmtAST *Stmt);
    void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true);

    void emitIfStmt(IfStmtAST *Stmt);
    void emitTryStmt(TryStmtAST *Stmt);
    void emitWhileStmt(WhileStmtAST *Stmt);
    void emitRepeatStmt(RepeatStmtAST *Stmt);
    void emitForStmt(ForStmtAST *Stmt);

public:
    CodeGen();
    ~CodeGen();
    void compile(const std::vector<std::unique_ptr<StmtAST>> &Statements);
    void print(llvm::raw_ostream &Output);
    const llvm::Module &getModule() const { return *TheModule; }
    bool hadError() const { return HadError; }
    void reportError(const char *Fmt, ...);
    static bool isBuiltinName(const std::string &Name);
    
    llvm::Value *emitExpr(ExprAST *Expr);
    void emitStmt(StmtAST *Stmt);

    // STRING slots zero-init to null; normalize null to "" at load/print sites.
    llvm::Value *emitStringNullGuard(llvm::Value *StrVal);

    // Name-level admission gate for Enum/Record/Pointer plus the existing
    // representation coercion for builtin targets. The ONLY door through
    // which assignments, BYVAL args, RETURN values and file/builtin operands
    // may produce a typed value. (Designator.cc)
    llvm::Value *emitCoercedExpr(ExprAST *E, const TypeInfo *TargetInfo);

    const TypeInfo *resolveType(const std::string &TypeName) const;

    friend class ArrayHandler;
};

}