aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CTypeGen.cc79
-rw-r--r--lib/CodeGen/CodeGen.cc19
-rw-r--r--lib/CodeGen/Designator.cc3
3 files changed, 100 insertions, 1 deletions
diff --git a/lib/CodeGen/CTypeGen.cc b/lib/CodeGen/CTypeGen.cc
new file mode 100644
index 0000000..03f398f
--- /dev/null
+++ b/lib/CodeGen/CTypeGen.cc
@@ -0,0 +1,79 @@
+#include "cps/CodeGen.h"
+#include "cps/TypeAST.h"
+
+using namespace llvm;
+using namespace cps;
+
+namespace {
+
+bool isScalar(const TypeInfo *Info) {
+ if (!Info || Info->isVoid()) return false;
+ return Info->Kind == TypeKind::CScalar || Info->Kind == TypeKind::Integer ||
+ Info->Kind == TypeKind::Real || Info->Kind == TypeKind::Boolean ||
+ Info->Kind == TypeKind::Char;
+}
+
+bool isSigned(const TypeInfo *Info) {
+ return Info->isC() ? Info->CSigned : Info->Kind == TypeKind::Integer;
+}
+
+} // namespace
+
+// Source type identity is essential: native signed char and pseudocode CHAR
+// can share i8 while requiring different extensions and FP conversions.
+Value *CodeGen::convertNumericValue(Value *Val, const TypeInfo *Source, const TypeInfo *Target) {
+ if (!Val || !isScalar(Source) || !isScalar(Target)) return nullptr;
+ Type *From = Val->getType();
+ Type *To = Target->LLVMType;
+ if (From == To) return Val;
+ if (To->isIntegerTy(1)) {
+ if (From->isIntegerTy())
+ return Builder->CreateICmpNE(Val, Constant::getNullValue(From), "cast_bool");
+ return Builder->CreateFCmpUNE(Val, ConstantFP::get(From, 0.0), "cast_bool");
+ }
+ if (From->isIntegerTy() && To->isIntegerTy())
+ return Builder->CreateIntCast(Val, To, isSigned(Source), "cast_int");
+ if (From->isIntegerTy() && To->isFloatingPointTy())
+ return isSigned(Source) ? Builder->CreateSIToFP(Val, To, "cast_fp")
+ : Builder->CreateUIToFP(Val, To, "cast_fp");
+ if (From->isFloatingPointTy() && To->isIntegerTy())
+ return isSigned(Target) ? Builder->CreateFPToSI(Val, To, "cast_int")
+ : Builder->CreateFPToUI(Val, To, "cast_int");
+ return Builder->CreateFPCast(Val, To, "cast_fp");
+}
+
+Value *CodeGen::emitCast(CastExprAST *Cast) {
+ const TypeInfo *Target = resolveType(Cast->getTypeName());
+ ExprAST *Operand = Cast->getOperand();
+ if (!Target || Target->isVoid()) {
+ reportError("Invalid cast target %s", Cast->getTypeName().c_str());
+ return nullptr;
+ }
+ if (isWholeArrayVar(Operand)) {
+ reportError("Cannot cast a whole array; index it");
+ return nullptr;
+ }
+ if (auto *Address = dynamic_cast<AddrOfExprAST*>(Operand)) {
+ LValueInfo LV;
+ if (!emitLValue(Address->getTarget(), LV)) return nullptr;
+ const TypeInfo *Pointee = resolveType(LV.TypeName);
+ if (Target->Kind == TypeKind::CPointer && Pointee && Pointee->isC()) return LV.Addr;
+ reportError("Address casts require a C pointee and C pointer target");
+ return nullptr;
+ }
+ const TypeInfo *Source = getExprTypeInfo(Operand);
+ if (!Source || Source->isVoid() || Source->isUserKind() || Target->isUserKind()) {
+ reportError("Unsupported operand or target for cast to %s", Target->Name.c_str());
+ return nullptr;
+ }
+ if (isScalar(Source) && isScalar(Target))
+ return convertNumericValue(emitExpr(Operand), Source, Target);
+ if (Source->Kind == TypeKind::CPointer && Target->Kind == TypeKind::CPointer)
+ return emitExpr(Operand);
+ if (Source->isString() && Target->CIdentity == "char*") return emitExpr(Operand);
+ if (Source->CIdentity == "char*" && Target->isString())
+ return emitStringNullGuard(emitExpr(Operand));
+ if (Source->isString() && Target->isString()) return emitExpr(Operand);
+ reportError("Cannot cast %s to %s", Source->Name.c_str(), Target->Name.c_str());
+ return nullptr;
+}
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 8c01972..ce34ebc 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -185,6 +185,8 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
if (dynamic_cast<BooleanExprAST*>(Expr)) return resolveType("BOOLEAN");
if (dynamic_cast<CharExprAST*>(Expr)) return resolveType("CHAR");
if (dynamic_cast<StringExprAST*>(Expr)) return resolveType("STRING");
+ if (auto *Cast = dynamic_cast<CastExprAST*>(Expr))
+ return resolveType(Cast->getTypeName());
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
const SymbolInfo *Info = getSymbolInfo(Var->getName());
@@ -240,7 +242,10 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
if (Unary->getOp() == tok_not) {
return resolveType("BOOLEAN");
}
- return getExprTypeInfo(Unary->getOperand());
+ const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
+ if (Operand && !Operand->isC() && !Operand->isUserKind())
+ return Operand->isReal() ? resolveType("REAL") : resolveType("INTEGER");
+ return nullptr;
}
if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) {
@@ -572,6 +577,7 @@ void CodeGen::print(raw_ostream &Output) {
}
Value *CodeGen::emitExpr(ExprAST *Expr) {
+ if (auto *Cast = dynamic_cast<CastExprAST*>(Expr)) return emitCast(Cast);
if (!Expr) return nullptr;
if (auto *Num = dynamic_cast<IntegerExprAST*>(Expr)) {
@@ -632,6 +638,17 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (!Operand) return nullptr;
return Builder->CreateNot(Operand, "nottmp");
}
+ if (Unary->getOp() == '-') {
+ const TypeInfo *Info = getExprTypeInfo(Unary->getOperand());
+ if (!Info || Info->isC() || Info->isUserKind() || Info->isString() || Info->isVoid()) {
+ reportError("Unary '-' requires a supported numeric operand");
+ return nullptr;
+ }
+ Value *Operand = emitExpr(Unary->getOperand());
+ if (!Operand) return nullptr;
+ return ArithHandler->emitBinaryOp('-', ConstantInt::get(Type::getInt64Ty(*TheContext), 0),
+ Operand, 0);
+ }
return nullptr;
}
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index c7d0796..019c19e 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -231,6 +231,9 @@ Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) {
return nullptr;
}
if (Src && Src->sameType(Target) && !Target->isVoid()) return emitExpr(E);
+ if (Src && Src->Kind == TypeKind::CScalar && Target->Kind == TypeKind::CScalar &&
+ !Src->isVoid() && !Target->isVoid())
+ return convertNumericValue(emitExpr(E), Src, Target);
reportError("Cannot implicitly convert %s to %s; use an explicit cast",
Src ? Src->Name.c_str() : "expression", Target->Name.c_str());
return nullptr;