aboutsummaryrefslogtreecommitdiffstats
path: root/ast.cpp
blob: a528cc3ef52499e0f5a98e5ee1ff4d3ca404fdcc (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
/**
 * forspll - LLVM-based Forsp compiler
 * Copyright (C) 2024  Clyne Sullivan <clyne@bitgloo.com>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "ast.hpp"

#include <charconv>
#include <iostream>

int ThunkAST::tcount = 0;

NumberAST::NumberAST(const std::string& n): BaseAST(n) {}

llvm::Value *NumberAST::codegen(LLVMState& llvmState) const
{
    int value;
    auto [ptr, _] = std::from_chars(&name.front(), &name.back() + 1, value);

    if (ptr <= &name.back()) {
        std::cerr << "error: not a number: " << name << std::endl;
        return nullptr;
    } else {
        auto val = llvmState.createInt(value);
        return llvmState.builder.CreateStore(val, llvmState.createPush());
    }
}

PushAST::PushAST(const std::string& n): BaseAST(n) {}

llvm::Value *PushAST::codegen(LLVMState& llvmState) const
{
    if (auto [var, thunk] = Var::lookup(name); var) {
        auto dsget = llvmState.createPush();
        if (!thunk)
            var = llvmState.builder.CreateLoad(llvmState.inttype, var);

        return llvmState.builder.CreateStore(var, dsget);
    } else {
        std::cerr << "error: not defined: " << name << std::endl;
        return nullptr;
    }
}

PopAST::PopAST(const std::string& n): BaseAST(n) {}

llvm::Value *PopAST::codegen(LLVMState& llvmState) const
{
    if (name == "self") {
        extern std::list<ThunkAST> scope;
        auto func = scope.back().func;
        auto var = llvmState.createVariable(name);
        llvmState.builder.CreateStore(func, var, false);
        return Var::addLocal(name, var).value;
    } else {
        auto gep = llvmState.createPop();
        auto var = llvmState.createVariable(name);
        auto load = llvmState.builder.CreateLoad(llvmState.inttype, gep);
        llvmState.builder.CreateStore(load, var, false);

        return Var::addLocal(name, var).value;
    }
}

CallAST::CallAST(const std::string& n): BaseAST(n) {}

llvm::Value *CallAST::codegen(LLVMState& llvmState) const
{
    if (auto [var, call] = Var::lookup(name); var) {
        if (call) {
            return llvmState.builder.CreateCall(llvmState.ftype, var);
        } else {
            auto val = llvmState.builder.CreateLoad(llvmState.inttype, var);
            auto cast = llvmState.builder.CreateIntToPtr(val,
                llvmState.inttype->getPointerTo());
            return llvmState.builder.CreateCall(llvmState.ftype, cast);
        }
    } else {
        std::cerr << "warning: anticipating external function: "
            << name << std::endl;
        auto func = llvmState.createFunction(name);
        Var::addGlobal(name, Var {func, true});
        return llvmState.builder.CreateCall(llvmState.ftype, func);
    }
}

ThunkAST::ThunkAST(LLVMState& llvmState):
    ThunkAST(llvmState, std::string("__t") + std::to_string(tcount++)) {}

ThunkAST::ThunkAST(LLVMState& llvmState, std::string n): BaseAST(n)
{
    parent = llvmState.builder.saveIP();
    func = llvmState.createFunction(name);
    auto BB = llvmState.createEntry(func);
    llvmState.builder.SetInsertPoint(BB);
}

llvm::Value *ThunkAST::codegen(LLVMState& llvmState) const
{
    llvmState.builder.CreateRetVoid();
    llvmState.builder.restoreIP(parent);

    return func;
}