/** * forspll - LLVM-based Forsp compiler * Copyright (C) 2024 Clyne Sullivan * * 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 . */ #include "ast.hpp" #include #include 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 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; }