irgenerator.h 6.89 KB
Newer Older
1
// Copyright (c) 2014 Dropbox, Inc.
Kevin Modzelewski's avatar
Kevin Modzelewski committed
2
//
3 4 5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Kevin Modzelewski's avatar
Kevin Modzelewski committed
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
Kevin Modzelewski's avatar
Kevin Modzelewski committed
8
//
9 10 11 12 13 14 15 16 17 18 19
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef PYSTON_CODEGEN_IRGEN_IRGENERATOR_H
#define PYSTON_CODEGEN_IRGEN_IRGENERATOR_H

#include <map>

Kevin Modzelewski's avatar
Kevin Modzelewski committed
20
#include "llvm/ADT/iterator_range.h"
21
#include "llvm/IR/Instructions.h"
Kevin Modzelewski's avatar
Kevin Modzelewski committed
22

23 24 25 26 27 28
#include "core/types.h"

namespace llvm {
class AllocaInst;
class BasicBlock;
class BranchInst;
29
// class Function;
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
class MDNode;
}

namespace pyston {

class CFGBlock;
class GCBuilder;
class ScopeInfo;
class TypeAnalysis;

typedef std::unordered_map<std::string, CompilerVariable*> SymbolTable;
typedef std::map<std::string, CompilerVariable*> SortedSymbolTable;
typedef std::unordered_map<std::string, ConcreteCompilerVariable*> ConcreteSymbolTable;

// Class that holds state of the current IR generation, that might not be local
// to the specific phase or pass we're in.
// TODO this probably shouldn't be here
class IRGenState {
48 49 50 51 52
private:
    CompiledFunction* cf;
    SourceInfo* source_info;
    GCBuilder* gc;
    llvm::MDNode* func_dbg_info;
53

54 55
    llvm::AllocaInst* scratch_space;
    int scratch_size;
56

57 58 59 60 61 62
public:
    IRGenState(CompiledFunction* cf, SourceInfo* source_info, GCBuilder* gc, llvm::MDNode* func_dbg_info)
        : cf(cf), source_info(source_info), gc(gc), func_dbg_info(func_dbg_info), scratch_space(NULL), scratch_size(0) {
        assert(cf->func);
        assert(!cf->clfunc); // in this case don't need to pass in sourceinfo
    }
63

64
    CompiledFunction* getCurFunction() { return cf; }
65

66
    llvm::Function* getLLVMFunction() { return cf->func; }
67

68
    EffortLevel::EffortLevel getEffortLevel() { return cf->effort; }
69

70
    GCBuilder* getGC() { return gc; }
71

72
    llvm::Value* getScratchSpace(int min_bytes);
73

74
    ConcreteCompilerType* getReturnType() {
75 76
        assert(cf->spec);
        return cf->spec->rtn_type;
77
    }
78

79
    SourceInfo* getSourceInfo() { return source_info; }
80

81
    ScopeInfo* getScopeInfo();
82

83 84
    llvm::MDNode* getFuncDbgInfo() { return func_dbg_info; }
};
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 126
class GuardList {
public:
    struct ExprTypeGuard {
        CFGBlock* cfg_block;
        llvm::BranchInst* branch;
        AST_expr* ast_node;
        CompilerVariable* val;
        SymbolTable st;

        ExprTypeGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val,
                      const SymbolTable& st);
    };

    struct BlockEntryGuard {
        CFGBlock* cfg_block;
        llvm::BranchInst* branch;
        SymbolTable symbol_table;

        BlockEntryGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, const SymbolTable& symbol_table);
    };

private:
    std::unordered_map<AST_expr*, ExprTypeGuard*> expr_type_guards;
    std::unordered_map<CFGBlock*, std::vector<BlockEntryGuard*> > block_begin_guards;
    // typedef std::unordered_map<AST_expr*, ExprTypeGuard*>::iterator expr_type_guard_iterator;
    // typedef std::unordered_map<AST_expr*, ExprTypeGuard*>::const_iterator expr_type_guard_const_iterator;
    typedef decltype(expr_type_guards)::iterator expr_type_guard_iterator;
    typedef decltype(expr_type_guards)::const_iterator expr_type_guard_const_iterator;

public:
    llvm::iterator_range<expr_type_guard_iterator> exprGuards() {
        return llvm::iterator_range<expr_type_guard_iterator>(expr_type_guards.begin(), expr_type_guards.end());
    }

    void getBlocksWithGuards(std::unordered_set<CFGBlock*>& add_to) {
        for (const auto& p : block_begin_guards) {
            add_to.insert(p.first);
        }
    }

    void assertGotPatched() {
127
#ifndef NDEBUG
128 129 130
        for (const auto& p : block_begin_guards) {
            for (const auto g : p.second) {
                assert(g->branch->getSuccessor(0) != g->branch->getSuccessor(1));
131
            }
132 133
        }

134 135
        for (const auto& p : expr_type_guards) {
            assert(p.second->branch->getSuccessor(0) != p.second->branch->getSuccessor(1));
136
        }
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
#endif
    }

    ExprTypeGuard* getNodeTypeGuard(AST_expr* node) const {
        expr_type_guard_const_iterator it = expr_type_guards.find(node);
        if (it == expr_type_guards.end())
            return NULL;
        return it->second;
    }

    bool isEmpty() const { return expr_type_guards.size() == 0 && block_begin_guards.size() == 0; }

    void addExprTypeGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val,
                          const SymbolTable& st) {
        ExprTypeGuard*& g = expr_type_guards[ast_node];
        assert(g == NULL);
        g = new ExprTypeGuard(cfg_block, branch, ast_node, val, st);
    }

    void registerGuardForBlockEntry(CFGBlock* cfg_block, llvm::BranchInst* branch, const SymbolTable& st) {
        // printf("Adding guard for block %p, in %p\n", cfg_block, this);
        std::vector<BlockEntryGuard*>& v = block_begin_guards[cfg_block];
        v.push_back(new BlockEntryGuard(cfg_block, branch, st));
    }

    const std::vector<BlockEntryGuard*>& getGuardsForBlock(CFGBlock* block) const {
        std::unordered_map<CFGBlock*, std::vector<BlockEntryGuard*> >::const_iterator it
            = block_begin_guards.find(block);
        if (it != block_begin_guards.end())
            return it->second;
167

168 169 170
        static std::vector<BlockEntryGuard*> empty_list;
        return empty_list;
    }
171 172 173
};

class IRGenerator {
174 175 176 177 178 179 180 181 182 183 184 185
private:
public:
    struct EndingState {
        SymbolTable* symbol_table;
        ConcreteSymbolTable* phi_symbol_table;
        llvm::BasicBlock* ending_block;
        EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table, llvm::BasicBlock* ending_block)
            : symbol_table(symbol_table), phi_symbol_table(phi_symbol_table), ending_block(ending_block) {}
    };

    virtual ~IRGenerator() {}

Kevin Modzelewski's avatar
Kevin Modzelewski committed
186
    virtual void doFunctionEntry(const std::vector<AST_expr*>& arg_names,
187
                                 const std::vector<ConcreteCompilerType*>& arg_types) = 0;
Kevin Modzelewski's avatar
Kevin Modzelewski committed
188

189 190 191 192
    virtual void giveLocalSymbol(const std::string& name, CompilerVariable* var) = 0;
    virtual void copySymbolsFrom(SymbolTable* st) = 0;
    virtual void run(const CFGBlock* block) = 0;
    virtual EndingState getEndingSymbolTable() = 0;
193
    virtual void doSafePoint() = 0;
194 195
};

196
class IREmitter;
197
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock);
198 199 200
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
                               CFGBlock* myblock, TypeAnalysis* types, GuardList& out_guards,
                               const GuardList& in_guards, bool is_partial);
201 202 203
}

#endif