aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/FunctionGen.cc
blob: b2adc08e5c4e3c03fbfc006535cbd7bfbd722616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

#include "cps/FunctionGen.h"
#include "llvm/IR/Verifier.h"
#include <iostream>

using namespace llvm;
using namespace cps;

Type *FunctionGen::getLLVMType(const std::string &TypeName) {
    if (TypeName == "INTEGER") return Type::getInt64Ty(Context);
    if (TypeName == "BOOLEAN") return Type::getInt1Ty(Context);
    if (TypeName == "REAL")    return Type::getDoubleTy(Context);
    if (TypeName == "VOID")    return Type::getVoidTy(Context);
    return Type::getInt64Ty(Context);
}

void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::pair<std::string, std::string>> &Args) {
    Function::arg_iterator AI = F->arg_begin();
    for (unsigned Idx = 0, E = Args.size(); Idx != E; ++Idx, ++AI) {
        std::string ArgName = Args[Idx].first;
        std::string ArgTypeStr = Args[Idx].second;
        
        Type *ArgType = getLLVMType(ArgTypeStr);
        IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
        AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName);
        
        Value *ArgVal = &(*AI);
        Builder.CreateStore(ArgVal, Alloca);
        
        NamedValues[ArgName] = Alloca; 
    }
}

Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
    std::vector<Type*> ArgTypes;
    for (const auto &Arg : Proto->getArgs()) {
        ArgTypes.push_back(getLLVMType(Arg.second));
    }

    Type *RetType = getLLVMType(Proto->getReturnType());
    FunctionType *FT = FunctionType::get(RetType, ArgTypes, false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);

    unsigned Idx = 0;
    for (auto &Arg : F->args()) {
        if (Idx < Proto->getArgs().size())
            Arg.setName(Proto->getArgs()[Idx++].first);
    }
    return F;
}

Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, 
                                       const std::function<void(StmtAST*)> &StmtEmitter) {
    PrototypeAST *Proto = FuncAST->getProto();
    Function *TheFunction = Module.getFunction(Proto->getName());

    if (!TheFunction)
        TheFunction = emitPrototype(Proto);

    if (!TheFunction) return nullptr;
    if (!TheFunction->empty()) {
        fprintf(stderr, "Error: Function %s cannot be redefined.\n", Proto->getName().c_str());
        return nullptr;
    }

    BasicBlock *BB = BasicBlock::Create(Context, "entry", TheFunction);
    Builder.SetInsertPoint(BB);

    std::map<std::string, llvm::AllocaInst*> OldNamedValues = NamedValues;
    NamedValues.clear();
    
    createArgumentAllocas(TheFunction, Proto->getArgs());

    for (const auto &Stmt : FuncAST->getBody()) {
        StmtEmitter(Stmt.get());
    }

    if (!Builder.GetInsertBlock()->getTerminator()) {
        if (Proto->getReturnType() == "VOID")
            Builder.CreateRetVoid();
        else
            Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType()));
    }

    verifyFunction(*TheFunction);
    NamedValues = OldNamedValues;
    return TheFunction;
}

static Value *GenerateCall(llvm::Module &Module, llvm::IRBuilder<> &Builder, llvm::LLVMContext &Context,
                    const std::string &CalleeName, const std::vector<llvm::Value*> &Args) {
    Function *CalleeF = Module.getFunction(CalleeName);
    if (!CalleeF) {
        std::vector<Type*> ArgTypes;
        for (auto *Val : Args) ArgTypes.push_back(Val->getType());
        FunctionType *FT = FunctionType::get(Type::getInt64Ty(Context), ArgTypes, false);
        CalleeF = Function::Create(FT, Function::ExternalLinkage, CalleeName, &Module);
    }

    if (CalleeF->arg_size() != Args.size()) {
        fprintf(stderr, "Error: Incorrect # arguments passed to %s\n", CalleeName.c_str());
        return nullptr;
    }

    if (CalleeF->getReturnType()->isVoidTy()) {
        return Builder.CreateCall(CalleeF, Args);
    }

    return Builder.CreateCall(CalleeF, Args, "calltmp");
}

llvm::Value *FunctionGen::emitCallExpr(CallExprAST *Call, const std::vector<llvm::Value*> &Args) {
    return GenerateCall(Module, Builder, Context, Call->getCallee(), Args);
}

void FunctionGen::emitCallStmt(CallStmtAST *Call, const std::vector<llvm::Value*> &Args) {
    GenerateCall(Module, Builder, Context, Call->getCallee(), Args);
}

void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) {
    if (RetVal) {
        Builder.CreateRet(RetVal);
    } else {
        Builder.CreateRetVoid();
    }
}