diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 30 | ||||
| -rw-r--r-- | lib/CodeGen/Designator.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 101 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 1 |
5 files changed, 132 insertions, 4 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 92a52e8..7abdad7 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -215,6 +215,9 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) { !sameIdentifier(F->getProto()->getReturnType(), "INTEGER")) reportError("MAIN must be a FUNCTION with no parameters returning INTEGER"); } + } else if (auto *X = dynamic_cast<ExternDeclAST*>(S.get())) { + Reserve(X->getProto()->getName(), true); + } else if (dynamic_cast<IncludeObjStmtAST*>(S.get())) { } else if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) { TypeName = E->getName(); for (const auto &V : E->getValueNames()) Reserve(V); @@ -285,6 +288,8 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) { SaveAndRestore<int> Location(DiagnosticLine, Stmt->getLine()); if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt.get())) FuncGen->emitPrototype(FuncDef->getProto()); + if (auto *Extern = dynamic_cast<ExternDeclAST*>(Stmt.get())) + FuncGen->emitExternPrototype(Extern->getProto()); if (auto *Class = dynamic_cast<ClassTypeDeclAST*>(Stmt.get())) { for (const auto &Method : Class->getMethods()) { SaveAndRestore<int> MethodLocation(DiagnosticLine, Method->getLine()); @@ -365,12 +370,18 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine); const FuncSig *Sig = &Signature; const std::string &Callee = Sig->Name; - if (ArgExprs.size() != Sig->Params.size()) { + if (Sig->IsVariadic ? ArgExprs.size() < Sig->Params.size() : ArgExprs.size() != Sig->Params.size()) { reportError("Incorrect # arguments passed to %s", Callee.c_str()); return false; } for (size_t i = 0; i < ArgExprs.size(); ++i) { + if (i >= Sig->Params.size()) { + Value *V = emitVariadicArgument(ArgExprs[i].get(), Callee, i + 1); + if (!V) return false; + Out.push_back(V); + continue; + } const ParamSig &P = Sig->Params[i]; const std::string &TypeName = P.TypeName; bool IsByRef = P.IsByRef; @@ -424,6 +435,23 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, return true; } +// C default argument promotions for the variadic part of an EXTERN call; only +// C values are accepted, matching the explicit-cast rule for C/pseudocode. +Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) { + const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr); + if (!Info || !Info->isC() || Info->isVoid()) { + reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str()); + return nullptr; + } + Value *V = emitExpr(Expr); + if (!V || Info->Kind != TypeKind::CScalar) return V; + if (Info->isReal()) { + const TypeInfo *Double = resolveType("C_DOUBLE"); + return Info->CRank < Double->CRank ? convertNumericValue(V, Info, Double) : V; + } + return convertNumericValue(V, Info, Types->promoteCScalar(Info)); +} + // Resolve using static source types only; argument evaluation belongs to marshalling. const FuncSig *CodeGen::resolveCall(const std::string &Name, const std::vector<std::unique_ptr<ExprAST>> &Args) { diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc index 467f788..5fb0ed3 100644 --- a/lib/CodeGen/Designator.cc +++ b/lib/CodeGen/Designator.cc @@ -116,7 +116,7 @@ Value *CodeGen::emitMethodCall(const std::string &Class, Value *Receiver, } std::vector<Value*> Args = {Receiver}; if (!marshalCallArgs(*Sig, ArgExprs, Line, Args)) return nullptr; - return FuncGen->emitCall(Sig->LinkName, Args); + return FuncGen->emitCall(*Sig, Args); } // Resolves a designator (or legacy variable/array-access node) to the address diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index b667e6a..79c5fb0 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -301,7 +301,7 @@ Value *CodeGen::emitCall(const std::string &Callee, std::vector<Value*> Args; const FuncSig *Sig = resolveCall(Name, ArgExprs); if (!Sig || !marshalCallArgs(*Sig, ArgExprs, Line, Args)) return nullptr; - return FuncGen->emitCall(Sig->LinkName, Args); + return FuncGen->emitCall(*Sig, Args); } Value *CodeGen::emitAllocationSize(ExprAST *Expr) { diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index b4b37d3..3937e01 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -127,7 +127,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { return nullptr; } if (Proto->getOwnerClass().empty()) { - if (isReservedRuntimeName(Proto->getName())) { + if (!Proto->isExternal() && isReservedRuntimeName(Proto->getName())) { reportError("'%s' is a reserved runtime symbol and cannot be a FUNCTION/PROCEDURE name", Proto->getName().c_str()); return nullptr; @@ -231,6 +231,96 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { return F; } +// The prototype names the exact C symbol; parameters and the result must be C +// types. Narrow integers carry the C ABI's sign/zero extension attributes. +bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { + if (PrototypeLinks.count(Proto)) return true; + const std::string &Name = Proto->getName(); + if (sameIdentifier(Name, "MAIN")) { + reportError("MAIN cannot be declared EXTERN"); + return false; + } + if (CodeGen::isBuiltinName(Name)) { + reportError("'%s' is a built-in function and cannot be redefined", Name.c_str()); + return false; + } + if (Types.lookupEnumConstant(Name) || Types.resolve(Name)) { + reportError("'%s' is already a type or enum value name", Name.c_str()); + return false; + } + + auto Extension = [](const TypeInfo *Info) { + if (Info->Kind != TypeKind::CScalar || !Info->LLVMType->isIntegerTy() || + Info->LLVMType->getIntegerBitWidth() >= 32) + return Attribute::None; + return Info->CSigned ? Attribute::SExt : Attribute::ZExt; + }; + + FuncSig Sig; + Sig.OwnerUnit = CurrentUnit; + Sig.Name = Name; + Sig.LinkName = Name; + Sig.Prototype = Proto; + Sig.ReturnTypeName = Proto->getReturnType(); + Sig.IsExternal = true; + Sig.IsVariadic = Proto->isVariadic(); + + std::vector<Type *> ArgTypes; + AttrBuilder RetAttrs(Context); + std::vector<AttributeSet> ParamAttrs; + for (size_t I = 0; I < Proto->getParams().size(); ++I) { + const ParamDecl &P = Proto->getParams()[I]; + const TypeInfo *Info = Types.resolve(P.TypeName); + if (!Info) { + reportError("Unknown type %s", P.TypeName.c_str()); + return false; + } + if (!Info->isC() || Info->isVoid()) { + reportError("EXTERN parameter %zu of %s must be a non-void C type (got %s)", + I + 1, Name.c_str(), P.TypeName.c_str()); + return false; + } + ArgTypes.push_back(Info->LLVMType); + AttrBuilder B(Context); + if (Attribute::AttrKind K = Extension(Info); K != Attribute::None) B.addAttribute(K); + ParamAttrs.push_back(AttributeSet::get(Context, B)); + ParamSig PS; + PS.TypeName = P.TypeName; + Sig.Params.push_back(std::move(PS)); + } + Type *RetType = Type::getVoidTy(Context); + if (!sameIdentifier(Proto->getReturnType(), "VOID")) { + const TypeInfo *Info = Types.resolve(Proto->getReturnType()); + if (!Info) { + reportError("Unknown type %s", Proto->getReturnType().c_str()); + return false; + } + if (!Info->isC() || Info->isVoid()) { + reportError("EXTERN_FUNCTION %s must return a non-void C type (got %s)", + Name.c_str(), Proto->getReturnType().c_str()); + return false; + } + RetType = Info->LLVMType; + if (Attribute::AttrKind K = Extension(Info); K != Attribute::None) RetAttrs.addAttribute(K); + } + + auto &Overloads = Signatures[Sig.Name]; + if (!Overloads.empty()) { + if (Overloads.front().OwnerUnit != CurrentUnit) + reportError("Duplicate definition %s in %s and %s", Name.c_str(), + UnitPaths[Overloads.front().OwnerUnit].c_str(), UnitPaths[CurrentUnit].c_str()); + else reportError("Function %s cannot be redefined", Name.c_str()); + return false; + } + Sig.ExternType = FunctionType::get(RetType, ArgTypes, Proto->isVariadic()); + Sig.ExternAttrs = AttributeList::get(Context, AttributeSet(), + AttributeSet::get(Context, RetAttrs), ParamAttrs); + Module.getOrInsertFunction(Name, Sig.ExternType); + PrototypeLinks.emplace(Proto, Name); + Overloads.push_back(std::move(Sig)); + return true; +} + Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, const std::function<void(StmtAST*)> &StmtEmitter, unsigned ScopeID) { PrototypeAST *Proto = FuncAST->getProto(); @@ -309,6 +399,15 @@ llvm::Value *FunctionGen::emitCall(const std::string &Callee, const std::vector< return GenerateCall(Module, Exceptions, Callee, Args, HadError, DiagnosticLine); } +llvm::Value *FunctionGen::emitCall(const FuncSig &Sig, const std::vector<llvm::Value*> &Args) { + if (!Sig.IsExternal) return emitCall(Sig.LinkName, Args); + FunctionCallee Callee(Sig.ExternType, Module.getNamedValue(Sig.LinkName)); + Value *Call = Sig.ExternType->getReturnType()->isVoidTy() + ? Exceptions.emitCall(Callee, Args) : Exceptions.emitCall(Callee, Args, "calltmp"); + cast<CallBase>(Call)->setAttributes(Sig.ExternAttrs); + return Call; +} + void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) { Instruction *CatchCleanup = Exceptions.emitReturnCleanup(); Instruction *RetInst = RetVal ? Builder.CreateRet(RetVal) : Builder.CreateRetVoid(); diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc index 022c550..99a269d 100644 --- a/lib/CodeGen/StatementGen.cc +++ b/lib/CodeGen/StatementGen.cc @@ -15,6 +15,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { if (dynamic_cast<IncludeStmtAST*>(Stmt)) return; if (dynamic_cast<GlobalBlockAST*>(Stmt)) return; + if (dynamic_cast<IncludeObjStmtAST*>(Stmt) || dynamic_cast<ExternDeclAST*>(Stmt)) return; if (auto *Class = dynamic_cast<ClassTypeDeclAST*>(Stmt)) { for (const auto &Method : Class->getMethods()) { |
