aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CodeGen.cc12
-rw-r--r--lib/CodeGen/ExpressionGen.cc22
-rw-r--r--lib/CodeGen/OperatorGen.cc71
-rw-r--r--lib/CodeGen/ValueTypeGen.cc6
4 files changed, 103 insertions, 8 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 61fd837..f7c4de6 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -369,6 +369,14 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
int Line,
std::vector<Value*> &Out) {
+ std::vector<ExprAST*> Args;
+ for (const auto &Arg : ArgExprs) Args.push_back(Arg.get());
+ return marshalCallArgs(Signature, Args, Line, Out);
+}
+
+bool CodeGen::marshalCallArgs(const FuncSig &Signature,
+ const std::vector<ExprAST*> &ArgExprs,
+ int Line, std::vector<Value*> &Out) {
SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
const FuncSig *Sig = &Signature;
const std::string &Callee = Sig->Name;
@@ -379,7 +387,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
for (size_t i = 0; i < ArgExprs.size(); ++i) {
if (i >= Sig->Params.size()) {
- Value *V = emitVariadicArgument(ArgExprs[i].get(), Callee, i + 1);
+ Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1);
if (!V) return false;
Out.push_back(V);
continue;
@@ -387,7 +395,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
const ParamSig &P = Sig->Params[i];
const std::string &TypeName = P.TypeName;
bool IsByRef = P.IsByRef;
- ExprAST *ArgExpr = ArgExprs[i].get();
+ ExprAST *ArgExpr = ArgExprs[i];
if (P.IsArray) {
if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds,
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 8fb13c9..a01cab2 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -73,6 +73,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (isWholeArrayVar(Unary->getOperand())) {
+ reportError("A whole array cannot be used as an operand; index it");
+ return nullptr;
+ }
+ auto Overload = resolveOperator(Unary->getOp(), getExprTypeInfo(Unary->getOperand()));
+ if (Overload.Ambiguous) {
+ reportError("Ambiguous overload for %s", operatorName(Unary->getOp()).c_str());
+ return nullptr;
+ }
+ if (Overload.Signature) return emitOperatorCall(*Overload.Signature, Unary->getOperand());
if (Unary->getOp() == tok_not) {
const TypeInfo *Info = getExprTypeInfo(Unary->getOperand());
Value *Operand = Info && Info->isC()
@@ -123,6 +133,16 @@ 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 && RT) {
+ auto Overload = resolveOperator(Bin->getOp(), LT, RT);
+ if (Overload.Ambiguous) {
+ reportError("Ambiguous overload for %s(%s, %s)", operatorName(Bin->getOp()).c_str(),
+ LT->Name.c_str(), RT->Name.c_str());
+ return nullptr;
+ }
+ if (Overload.Signature)
+ return emitOperatorCall(*Overload.Signature, Bin->getLHS(), Bin->getRHS());
+ }
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
return emitBinaryOp(Bin->getOp(), L, LT, R, RT, Bin->getLine());
@@ -165,7 +185,7 @@ Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT,
reportError("Ambiguous overload for %s(%s, %s)", operatorName(Op).c_str(), LT->Name.c_str(), RT->Name.c_str());
return nullptr;
}
- if (Overload.Signature) return FuncGen->emitCall(*Overload.Signature, {L, R});
+ if (Overload.Signature) return emitOperatorValues(*Overload.Signature, L, LT, R);
if ((LT && LT->isC()) || (RT && RT->isC()))
return emitCBinaryOp(Op, L, LT, R, RT, Line);
if ((LT && LT->isUserKind()) || (RT && RT->isUserKind()))
diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc
index 83c515b..d340ed7 100644
--- a/lib/CodeGen/OperatorGen.cc
+++ b/lib/CodeGen/OperatorGen.cc
@@ -1,7 +1,9 @@
#include "cps/CodeGen.h"
#include "cps/Operator.h"
+#include "cps/TypeAST.h"
using namespace cps;
+using namespace llvm;
// Probing candidates must not evaluate operands or diagnose absent overloads:
// both static typing and emission use this same selection.
@@ -9,12 +11,73 @@ CodeGen::OperatorResolution CodeGen::resolveOperator(
int Op, const TypeInfo *Left, const TypeInfo *Right) {
OperatorResolution Result;
if (!Left) return Result;
- for (const FuncSig *Sig : FuncGen->getOverloads(operatorName(Op))) {
- if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u)) continue;
- if (!Left->sameType(resolveType(Sig->Params[0].TypeName))) continue;
- if (Right && !Right->sameType(resolveType(Sig->Params[1].TypeName))) continue;
+ auto Candidates = FuncGen->getOverloads(operatorName(Op));
+ if (Left->IsClass) {
+ auto Members = FuncGen->getOverloads(Left->Name + "." + operatorName(Op));
+ Candidates.insert(Candidates.end(), Members.begin(), Members.end());
+ }
+ for (const FuncSig *Sig : Candidates) {
+ bool Member = !Sig->Prototype->getOwnerClass().empty();
+ if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue;
+ if (!Member && !Left->sameType(resolveType(Sig->Params[0].TypeName))) continue;
+ if (Right && !Right->sameType(resolveType(Sig->Params[Member ? 0 : 1].TypeName))) continue;
if (Result.Signature) Result.Ambiguous = true;
else Result.Signature = Sig;
}
return Result;
}
+
+bool CodeGen::checkOperatorAccess(const FuncSig &Signature) {
+ const PrototypeAST *Proto = Signature.Prototype;
+ if (!Proto->getOwnerClass().empty() && !Proto->isPublic() &&
+ !sameIdentifier(CurrentClass, Proto->getOwnerClass())) {
+ reportError("Cannot access private method %s of type %s",
+ Proto->getName().c_str(), Proto->getOwnerClass().c_str());
+ return false;
+ }
+ return true;
+}
+
+Value *CodeGen::materializeOperatorReceiver(Value *Val, const TypeInfo *Type) {
+ if (!Val || !Type) return nullptr;
+ auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
+ Type->LLVMType, "operator_receiver");
+ size_t Object = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true);
+ Builder->CreateStore(Val, Storage);
+ activateStackObject(Object);
+ return Storage;
+}
+
+Value *CodeGen::emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAST *Right) {
+ if (!checkOperatorAccess(Signature)) return nullptr;
+ std::vector<Value*> Args;
+ std::vector<ExprAST*> Explicit;
+ if (Signature.Prototype->getOwnerClass().empty()) {
+ Explicit.push_back(Left);
+ } else {
+ Value *Receiver = nullptr;
+ if (dynamic_cast<VariableExprAST*>(Left) || dynamic_cast<ArrayAccessExprAST*>(Left) ||
+ dynamic_cast<DesignatorExprAST*>(Left)) {
+ LValueInfo LV;
+ if (!emitLValue(Left, LV)) return nullptr;
+ Receiver = LV.Addr;
+ } else {
+ Receiver = materializeOperatorReceiver(emitExpr(Left), getExprTypeInfo(Left));
+ }
+ if (!Receiver) return nullptr;
+ Args.push_back(Receiver);
+ }
+ if (Right) Explicit.push_back(Right);
+ if (!marshalCallArgs(Signature, Explicit, DiagnosticLine, Args)) return nullptr;
+ return FuncGen->emitCall(Signature, Args);
+}
+
+// CASE has already evaluated and captured its selector and label values.
+Value *CodeGen::emitOperatorValues(const FuncSig &Signature, Value *Left,
+ const TypeInfo *LeftType, Value *Right) {
+ if (!checkOperatorAccess(Signature)) return nullptr;
+ if (!Signature.Prototype->getOwnerClass().empty())
+ Left = materializeOperatorReceiver(Left, LeftType);
+ if (!Left) return nullptr;
+ return FuncGen->emitCall(Signature, {Left, Right});
+}
diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc
index b09a5d9..e7a3f77 100644
--- a/lib/CodeGen/ValueTypeGen.cc
+++ b/lib/CodeGen/ValueTypeGen.cc
@@ -70,10 +70,14 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) {
if (dynamic_cast<AddrOfExprAST*>(Expr)) return nullptr;
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (isWholeArrayVar(Unary->getOperand())) return nullptr;
+ const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
+ auto Overload = resolveOperator(Unary->getOp(), Operand);
+ if (Overload.Ambiguous) return nullptr;
+ if (Overload.Signature) return resolveType(Overload.Signature->ReturnTypeName);
if (Unary->getOp() == tok_not) {
return resolveType("BOOLEAN");
}
- const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
if (Operand && Operand->isC()) return Types->promoteCScalar(Operand);
if (Operand && !Operand->isC() && !Operand->isUserKind())
return Operand->isReal() ? resolveType("REAL") : resolveType("INTEGER");