aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CTypeGen.cc20
-rw-r--r--lib/CodeGen/ControlFlowGen.cc58
-rw-r--r--lib/CodeGen/ExpressionGen.cc59
-rw-r--r--lib/CodeGen/StatementGen.cc4
-rw-r--r--lib/CodeGen/TypeCheckGen.cc15
5 files changed, 101 insertions, 55 deletions
diff --git a/lib/CodeGen/CTypeGen.cc b/lib/CodeGen/CTypeGen.cc
index 22ecb9f..a20306e 100644
--- a/lib/CodeGen/CTypeGen.cc
+++ b/lib/CodeGen/CTypeGen.cc
@@ -78,10 +78,10 @@ Value *CodeGen::emitCast(CastExprAST *Cast) {
return nullptr;
}
-Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const TypeInfo *Right) {
- int Op = Bin->getOp();
+Value *CodeGen::emitCBinaryOp(int Op, Value *L, const TypeInfo *Left,
+ Value *R, const TypeInfo *Right, int Line) {
if (!Left || !Right || !Left->isC() || !Right->isC()) {
- reportError("C and pseudocode operands require an explicit cast (line %d)", Bin->getLine());
+ reportError("C and pseudocode operands require an explicit cast (line %d)", Line);
return nullptr;
}
if (Left->isPointer() || Right->isPointer()) {
@@ -90,9 +90,6 @@ Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const Ty
reportError("C pointers support only = and <> between the same C pointer type");
return nullptr;
}
- Value *L = emitExpr(Bin->getLHS());
- Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
return Op == tok_eq ? Builder->CreateICmpEQ(L, R, "c_ptr_eq")
: Builder->CreateICmpNE(L, R, "c_ptr_ne");
}
@@ -102,12 +99,9 @@ Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const Ty
return nullptr;
}
if (Op == '&' || ((Op == tok_div || Op == tok_mod) && !Common->isIntegral())) {
- reportError("Operator is not supported for these C operand types (line %d)", Bin->getLine());
+ reportError("Operator is not supported for these C operand types (line %d)", Line);
return nullptr;
}
- Value *L = emitExpr(Bin->getLHS());
- Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
if (Op == tok_and || Op == tok_or) {
L = convertNumericValue(L, Left, resolveType("BOOLEAN"));
R = convertNumericValue(R, Right, resolveType("BOOLEAN"));
@@ -119,7 +113,7 @@ Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const Ty
if (Op == '/') {
L = convertNumericValue(L, Left, resolveType("REAL"));
R = convertNumericValue(R, Right, resolveType("REAL"));
- RuntimeChecker->emitDivZeroCheck(R, Bin->getLine());
+ RuntimeChecker->emitDivZeroCheck(R, Line);
return Builder->CreateFDiv(L, R, "c_real_div");
}
L = convertNumericValue(L, Left, Common);
@@ -142,7 +136,7 @@ Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const Ty
case '-': return Builder->CreateSub(L, R, "c_sub");
case '*': return Builder->CreateMul(L, R, "c_mul");
case tok_div: case tok_mod:
- RuntimeChecker->emitDivZeroCheck(R, Bin->getLine());
+ RuntimeChecker->emitDivZeroCheck(R, Line);
if (Op == tok_div)
return Common->CSigned ? Builder->CreateSDiv(L, R, "c_div")
: Builder->CreateUDiv(L, R, "c_div");
@@ -160,7 +154,7 @@ Value *CodeGen::emitCBinaryOp(BinaryExprAST *Bin, const TypeInfo *Left, const Ty
: Builder->CreateICmpUGE(L, R, "c_ge");
}
}
- reportError("Unsupported operator for C operands (line %d)", Bin->getLine());
+ reportError("Unsupported operator for C operands (line %d)", Line);
return nullptr;
}
diff --git a/lib/CodeGen/ControlFlowGen.cc b/lib/CodeGen/ControlFlowGen.cc
index ebd5d3c..f9300dd 100644
--- a/lib/CodeGen/ControlFlowGen.cc
+++ b/lib/CodeGen/ControlFlowGen.cc
@@ -173,3 +173,61 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->SetInsertPoint(AfterBB);
}
+
+void CodeGen::emitCaseStmt(CaseStmtAST *Stmt) {
+ VariableExprAST Selector(Stmt->getSelector());
+ if (isWholeArrayVar(&Selector)) {
+ reportError("CASE selector cannot be a whole array");
+ return;
+ }
+ const TypeInfo *SelectorType = getExprTypeInfo(&Selector);
+ Value *Selected = emitExpr(&Selector);
+ if (!Selected || !SelectorType) return;
+
+ auto *F = Builder->GetInsertBlock()->getParent();
+ F->addFnAttr("no-jump-tables", "true");
+ auto *After = BasicBlock::Create(*TheContext, "case_cont", F);
+ auto SavedArrays = Arrays->snapshotTable();
+ for (const auto &Branch : Stmt->getBranches()) {
+ auto *Body = BasicBlock::Create(*TheContext, "case_body", F);
+ auto *Next = BasicBlock::Create(*TheContext, "case_next", F);
+ auto Compare = [&](int Op, ExprAST *Label) -> Value * {
+ if (isWholeArrayVar(Label)) {
+ reportError("CASE label cannot be a whole array");
+ return nullptr;
+ }
+ const TypeInfo *LabelType = getExprTypeInfo(Label);
+ if (!LabelType) {
+ reportError("Cannot determine CASE label type at line %d", Branch.Line);
+ return nullptr;
+ }
+ Value *LabelValue = emitExpr(Label);
+ return emitBinaryOp(Op, Selected, SelectorType, LabelValue, LabelType, Branch.Line);
+ };
+ if (!Branch.Lower) {
+ Builder->CreateBr(Body);
+ } else {
+ Value *Match = Compare(Branch.Upper ? tok_ge : tok_eq, Branch.Lower.get());
+ if (!Match) {
+ // Finish the CFG even after a diagnostic; the driver discards it.
+ Builder->CreateBr(Next);
+ } else if (Branch.Upper) {
+ auto *Upper = BasicBlock::Create(*TheContext, "case_upper", F);
+ Builder->CreateCondBr(Match, Upper, Next);
+ Builder->SetInsertPoint(Upper);
+ Match = Compare(tok_le, Branch.Upper.get());
+ if (Match) Builder->CreateCondBr(Match, Body, Next);
+ else Builder->CreateBr(Next);
+ } else {
+ Builder->CreateCondBr(Match, Body, Next);
+ }
+ }
+ Builder->SetInsertPoint(Body);
+ for (const auto &S : Branch.Body) emitStmt(S.get());
+ if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(After);
+ Arrays->exchangeTable(SavedArrays);
+ Builder->SetInsertPoint(Next);
+ }
+ Builder->CreateBr(After);
+ Builder->SetInsertPoint(After);
+}
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 0d69408..9135d6c 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -117,38 +117,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
// '&' path: their admissible operations are decided by name here.
const TypeInfo *LT = getExprTypeInfo(Bin->getLHS());
const TypeInfo *RT = getExprTypeInfo(Bin->getRHS());
- if ((LT && LT->isC()) || (RT && RT->isC())) {
- return emitCBinaryOp(Bin, LT, RT);
- }
- if ((LT && LT->isUserKind()) || (RT && RT->isUserKind())) {
- return emitUserKindBinaryOp(Bin, LT, RT);
- }
-
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
- if (Bin->getOp() == '&') {
- L = coerceValueToType(L, resolveType("STRING"));
- R = coerceValueToType(R, resolveType("STRING"));
- if (!L || !R) return nullptr;
- return StrHandler->emitConcat(L, R);
- }
- // STRING and explicit pointers share LLVM's ptr representation;
- // string comparisons must dispatch on the pseudocode type.
- switch (Bin->getOp()) {
- case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge:
- if ((LT && LT->isString()) || (RT && RT->isString())) {
- if (!(LT && LT->isString() && RT && RT->isString())) {
- reportError("STRING comparison requires two STRING operands (line %d)", Bin->getLine());
- return nullptr;
- }
- return StrHandler->emitCompare(Bin->getOp(), L, R);
- }
- break;
- default:
- break;
- }
- return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine());
+ return emitBinaryOp(Bin->getOp(), L, LT, R, RT, Bin->getLine());
}
if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) {
@@ -271,3 +242,31 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return nullptr;
}
+
+// Ordinary binary expressions and CASE use the same typed operations.
+Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT,
+ Value *R, const TypeInfo *RT, int Line) {
+ if (!L || !R) return nullptr;
+ if ((LT && LT->isC()) || (RT && RT->isC()))
+ return emitCBinaryOp(Op, L, LT, R, RT, Line);
+ if ((LT && LT->isUserKind()) || (RT && RT->isUserKind()))
+ return emitUserKindBinaryOp(Op, L, LT, R, RT, Line);
+ if (Op == '&') {
+ L = coerceValueToType(L, resolveType("STRING"));
+ R = coerceValueToType(R, resolveType("STRING"));
+ return L && R ? StrHandler->emitConcat(L, R) : nullptr;
+ }
+ switch (Op) {
+ case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge:
+ if ((LT && LT->isString()) || (RT && RT->isString())) {
+ if (!(LT && LT->isString() && RT && RT->isString())) {
+ reportError("STRING comparison requires two STRING operands (line %d)", Line);
+ return nullptr;
+ }
+ return StrHandler->emitCompare(Op, L, R);
+ }
+ break;
+ default: break;
+ }
+ return ArithHandler->emitBinaryOp(Op, L, R, Line);
+}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index f10d78b..8f8711b 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -248,6 +248,10 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
+ if (auto *Case = dynamic_cast<CaseStmtAST*>(Stmt)) {
+ emitCaseStmt(Case);
+ return;
+ }
if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
emitIfStmt(IfStmt);
return;
diff --git a/lib/CodeGen/TypeCheckGen.cc b/lib/CodeGen/TypeCheckGen.cc
index a86fdb1..654afc8 100644
--- a/lib/CodeGen/TypeCheckGen.cc
+++ b/lib/CodeGen/TypeCheckGen.cc
@@ -121,8 +121,8 @@ Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) {
// Binary operators with at least one Enum/Record/Pointer operand. Decides
// admissibility by type name and emits directly; ArithmeticHandler stays
// ignorant of user kinds.
-Value *CodeGen::emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, const TypeInfo *RT) {
- int Op = Bin->getOp();
+Value *CodeGen::emitUserKindBinaryOp(int Op, Value *L, const TypeInfo *LT,
+ Value *R, const TypeInfo *RT, int Line) {
const char *LName = LT ? LT->Name.c_str() : "?";
const char *RName = RT ? RT->Name.c_str() : "?";
@@ -135,9 +135,6 @@ Value *CodeGen::emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, con
if ((LT && LT->isPointer()) || (RT && RT->isPointer())) {
bool SameName = LT && RT && LT->isPointer() && RT->isPointer() && LT->Name == RT->Name;
if (SameName && (Op == tok_eq || Op == tok_ne)) {
- Value *L = emitExpr(Bin->getLHS());
- Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
return Op == tok_eq ? Builder->CreateICmpEQ(L, R, "ptr_eq")
: Builder->CreateICmpNE(L, R, "ptr_ne");
}
@@ -152,9 +149,6 @@ Value *CodeGen::emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, con
switch (Op) {
case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge: {
if (!BothSameEnum) break;
- Value *L = emitExpr(Bin->getLHS());
- Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
switch (Op) {
case tok_eq: return Builder->CreateICmpEQ(L, R, "enum_eq");
case tok_ne: return Builder->CreateICmpNE(L, R, "enum_ne");
@@ -170,13 +164,10 @@ Value *CodeGen::emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, con
// The one legal arithmetic shape (guide ยง4.2): enum on the left,
// INTEGER on the right, result checked against the enum's range.
if (!(LT && LT->isEnum() && RT && RT->Kind == TypeKind::Integer)) break;
- Value *L = emitExpr(Bin->getLHS());
- Value *R = emitExpr(Bin->getRHS());
- if (!L || !R) return nullptr;
Value *Res = Op == '+' ? Builder->CreateAdd(L, R, "enum_step")
: Builder->CreateSub(L, R, "enum_step");
RuntimeChecker->emitEnumRangeCheck(Res, LT->asEnum()->ValueNames.size(),
- LT->Name, Bin->getLine());
+ LT->Name, Line);
return Res;
}