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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
#pragma once
#include "llvm/Support/SaveAndRestore.h"
#include "cps/Identifier.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "cps/AST.h"
#include "cps/SourceUnit.h"
#include "cps/RuntimeCheck.h"
#include "cps/FunctionGen.h"
#include "cps/TypeSystem.h"
#include "cps/ArithmeticHandler.h"
#include <map>
#include <memory>
#include <optional>
#include <string>
namespace cps {
class ArrayHandler;
class FileHandler;
class MemoryHandler;
class ExceptionHandler;
class CastExprAST;
class TemplateDeclAST;
class ClassTypeDeclAST;
class ReadFileStmtAST;
class CodeGen {
std::unique_ptr<llvm::LLVMContext> TheContext;
std::unique_ptr<llvm::Module> TheModule;
std::unique_ptr<llvm::IRBuilder<>> Builder;
int DiagnosticLine = 0;
const std::vector<SourceUnit> *Units = nullptr;
size_t CurrentUnit = 0;
size_t MainUnit = 0;
std::optional<size_t> VisibilityUnit;
IdentifierMap<size_t> TypeOwners;
struct TemplateDefinition { TemplateDeclAST *Decl; size_t OwnerUnit; };
IdentifierMap<std::vector<TemplateDefinition>> Templates;
struct TemplateInstance {
TemplateDeclAST *Decl;
std::string Arguments;
std::unique_ptr<FunctionDefAST> Function;
std::unique_ptr<ClassTypeDeclAST> Class;
const FuncSig *Signature;
size_t OwnerUnit;
size_t RequesterUnit;
unsigned Depth;
};
std::vector<TemplateInstance> TemplateInstances;
std::map<const TemplateDeclAST *, IdentifierMap<SymbolInfo>> TemplateSymbols;
size_t NextTemplateBody = 0;
unsigned TemplateDepth = 0;
bool TypePrePass = false;
bool SpeculativeTemplateResolution = false;
IdentifierSet FailedTemplateTypes;
std::vector<size_t> DeferredClassPrototypes;
bool hasCallable(const std::string &Name) const;
bool hasFunctionTemplate(const std::string &Name) const;
void validateTemplates();
void captureTemplateSymbols();
const FuncSig *instantiateFunction(const TemplateDefinition &Definition,
const IdentifierMap<std::vector<std::string>> &Bindings);
void drainTemplateBodies();
const TypeInfo *instantiateClass(const std::string &Name);
std::optional<std::string> canonicalTemplateArgument(const std::string &Name);
void emitClassPrototypes(ClassTypeDeclAST *Class);
void emitDeferredClassPrototypes();
std::vector<IdentifierMap<SymbolInfo>> Exports;
bool isVisible(size_t Owner) const;
void selectUnit(size_t Unit);
void importSymbols();
void runGlobalPrePass(const SourceUnit &Unit, int Phase);
IdentifierMap<SymbolInfo> Symbols;
IdentifierMap<IdentifierMap<std::vector<FunctionDefAST*>>> ClassMethods;
std::string CurrentClass;
const std::vector<FunctionDefAST *> *findMethod(const std::string &Class, const std::string &Name) const;
bool isRegisteredMethod(const std::string &Class, const PrototypeAST *Method) const;
const FuncSig *resolveMethod(const std::string &Class, const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &Args);
llvm::Value *emitMemberCall(MemberCallExprAST *Call);
llvm::Value *emitMethodCall(const std::string &Class, llvm::Value *Receiver,
const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &Args, int Line);
bool typeNeedsDestruction(const std::string &TypeName) const;
bool emitDestroy(const std::string &TypeName, llvm::Value *Addr, int Line);
bool typeNeedsConstruction(const std::string &TypeName) const;
bool emitConstruct(const std::string &TypeName, llvm::Value *Addr,
const std::vector<std::unique_ptr<ExprAST>> &Args, int Line);
bool emitDefaultConstruct(const std::string &TypeName, llvm::Value *Addr, int Line);
bool emitFieldDefaults(const TypeInfo *Type, llvm::Value *Addr, int Line);
struct StackObject {
llvm::Value *Addr;
std::string TypeName;
llvm::AllocaInst *Alive;
llvm::AllocaInst *Count; // Non-null for an array; Addr then holds its buffer pointer.
int Line;
bool Temporary = false;
};
std::vector<StackObject> StackObjects;
size_t registerStackObject(llvm::Value *Addr, const std::string &TypeName, int Line,
bool IsArray = false);
void activateStackObject(size_t Index, llvm::Value *Count = nullptr);
void emitStackObjectCleanup(const StackObject &Object);
void finishStackObjects(llvm::Function *F);
void cleanupTemporaries(size_t Start = 0);
bool isObjectLValue(ExprAST *Expr) const;
llvm::Value *emitOwnedValue(ExprAST *Expr, const TypeInfo *Type,
std::vector<size_t> &Transfers);
llvm::Value *copyClassValue(const TypeInfo *Type, llvm::Value *Address,
std::vector<size_t> &Transfers);
void transferObjects(const std::vector<size_t> &Objects);
void emitStmtImpl(StmtAST *Stmt);
void emitFunctionDefStmt(FunctionDefAST *FuncDef);
void emitInputStmt(InputStmtAST *In);
void emitOutputStmt(OutputStmtAST *Out);
void emitReadFileStmt(ReadFileStmtAST *Read);
struct ConstantScope {
unsigned ID;
IdentifierMap<std::optional<SymbolInfo>> Saved;
};
std::vector<ConstantScope> ConstantScopes = {{0, {}}};
unsigned NextScopeID = 1;
void emitScopedBlock(const std::vector<std::unique_ptr<StmtAST>> &Body);
void warnMemberShadow(const std::string &Name, int Line) const;
bool prepareSymbolDeclaration(const std::string &Name, bool IsConstant = false);
bool requireWritable(const SymbolInfo &Info, const std::string &Name);
const SymbolInfo *lookupWritableSymbol(const std::string &Name);
void emitConstantStmt(ConstantStmtAST *Stmt);
std::map<const ConstantStmtAST *, SymbolInfo> StringConstants;
const TypeInfo *requireStringType();
llvm::Value *emitStringFromCString(llvm::Value *Text);
llvm::Value *emitStringCString(llvm::Value *Value);
llvm::Value *emitCStringExpr(ExprAST *Expr);
llvm::Value *emitFileNameOperand(ExprAST *E, const char *Keyword);
bool containsString(const TypeInfo *Type) const;
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<FileHandler> Files;
std::unique_ptr<MemoryHandler> Memory;
llvm::FunctionCallee PrintfFunc;
llvm::FunctionCallee ScanfFunc;
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 *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);
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 *emitBinaryOp(int Op, llvm::Value *L, const TypeInfo *LT,
llvm::Value *R, const TypeInfo *RT, int Line);
llvm::Value *emitCBinaryOp(int Op, llvm::Value *L, const TypeInfo *Left,
llvm::Value *R, const TypeInfo *Right, int Line);
void emitCOutput(llvm::Value *Val, const TypeInfo *Info, bool AppendNewline);
void emitCInput(llvm::Value *Addr, const TypeInfo *Info);
// TYPE-system registration (Designator.cc) and operators (TypeCheckGen.cc).
void runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statements, int Phase);
void registerClassMethods(ClassTypeDeclAST *Class);
llvm::Value *emitUserKindBinaryOp(int Op, llvm::Value *L, const TypeInfo *LT,
llvm::Value *R, const TypeInfo *RT, int Line);
// 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);
// Read a value from resolved storage.
llvm::Value *loadFromLValue(const LValueInfo &LV);
llvm::Value *emitAllocationSize(ExprAST *Expr);
llvm::Value *emitIntBuiltin(ExprAST *Arg, int Line);
llvm::Value *emitCall(const std::string &Callee,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line,
const std::vector<std::string> *Explicit = nullptr);
const FuncSig *resolveCall(const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &Args,
const std::vector<std::string> *Explicit = nullptr);
struct OperatorResolution {
const FuncSig *Signature = nullptr;
bool Ambiguous = false;
};
OperatorResolution resolveOperator(int Op, const TypeInfo *Left, const TypeInfo *Right = nullptr);
bool checkOperatorAccess(const FuncSig &Signature);
llvm::Value *materializeOperatorReceiver(llvm::Value *Value, const TypeInfo *Type);
llvm::Value *emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAST *Right = nullptr);
llvm::Value *emitOperatorValues(const FuncSig &Signature, llvm::Value *Left,
const TypeInfo *LeftType, llvm::Value *Right);
llvm::Value *emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position,
const TypeInfo *&Promoted);
// Variadic, if given, receives the promoted type of each variadic argument.
bool marshalCallArgs(const FuncSig &Signature,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
int Line,
std::vector<llvm::Value*> &Out,
std::vector<const TypeInfo *> *Variadic = nullptr);
bool marshalCallArgs(const FuncSig &Signature, const std::vector<ExprAST*> &ArgExprs,
int Line, std::vector<llvm::Value*> &Out,
std::vector<const TypeInfo *> *Variadic = nullptr);
llvm::Value *symbolAddress(const SymbolInfo &Info);
void emitAssignment(const LValueInfo &Target, ExprAST *Expr,
const SymbolInfo *Symbol = nullptr);
void emitDeclareStmt(DeclareStmtAST *Stmt);
void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true);
void emitCaseStmt(CaseStmtAST *Stmt);
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 compile(const std::vector<SourceUnit> &Sources);
size_t getMainUnit() const { return MainUnit; }
void print(llvm::raw_ostream &Output);
const llvm::Module &getModule() const { return *TheModule; }
bool hadError() const { return HadError; }
__attribute__((format(printf, 2, 3))) void reportError(const char *Fmt, ...);
static bool isBuiltinName(const std::string &Name);
llvm::Value *emitExpr(ExprAST *Expr);
void emitStmt(StmtAST *Stmt);
// Normalize a raw C string pointer to "" when explicitly casting it to STRING.
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. (TypeCheckGen.cc)
llvm::Value *emitCoercedExpr(ExprAST *E, const TypeInfo *TargetInfo);
const TypeInfo *resolveType(const std::string &TypeName) const;
friend class ArrayHandler;
};
}
|