diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 12 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 22 | ||||
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 71 | ||||
| -rw-r--r-- | lib/CodeGen/ValueTypeGen.cc | 6 |
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"); |
