diff --git a/include/xo/jit/MachPipeline.hpp b/include/xo/jit/MachPipeline.hpp index 3e475e92..14003c44 100644 --- a/include/xo/jit/MachPipeline.hpp +++ b/include/xo/jit/MachPipeline.hpp @@ -152,6 +152,13 @@ namespace xo { std::vector> find_lambdas(ref::brw expr) const; public: + /** codegen helper for a user-defined function. + * create stack slot on behalf of formal parameters. + * linked to (dynamic) callers for stack unwinding + **/ + llvm::AllocaInst * create_entry_frame_alloca(llvm::Function * llvm_fn, + llvm::StructType * frame_llvm_type); + /** codegen helper for a user-defined function (codegen_lambda()): * create stack slot on behalf of some formal parameter to a function, * so we can avoid SSA restriction on function body diff --git a/include/xo/jit/activation_record.hpp b/include/xo/jit/activation_record.hpp index c2aba2dd..7c70ba3f 100644 --- a/include/xo/jit/activation_record.hpp +++ b/include/xo/jit/activation_record.hpp @@ -22,16 +22,41 @@ namespace xo { **/ class activation_record { public: - activation_record() = default; + activation_record(llvm::Function * llvm_fn, + llvm::AllocaInst * frame) : frame_{frame} { + int i_arg = 0; + for (auto & arg : llvm_fn->args()) { + std::string arg_name = std::string(arg.getName()); + name2ix_map_[arg_name] = 2 + i_arg; + } + } + + std::int32_t lookup_var(const std::string & var_name) const; + +#ifdef OBSOLETE llvm::AllocaInst * lookup_var(const std::string & var_name) const; llvm::AllocaInst * alloc_var(const std::string & var_name, llvm::AllocaInst * alloca); +#endif private: + /** stack frame for a user-defined function (lambda) **/ + llvm::AllocaInst * frame_ = nullptr; + + /** for each formal parameter, + * reports its position in stack frame. + * This is the position to use with getelementptr, + * i.e. +2 to skip first two slots, that are reserved + * for nextframe pointer (slot 0) + unwind pointer (slot 1) + **/ + std::map name2ix_map_; + +#ifdef OBSOLETE /** maps named slots in a stack frame to logical addresses **/ std::map frame_; /* <-> kaleidoscope NamedValues */ +#endif }; /*activation_record*/ } /*namespace jit*/ diff --git a/src/jit/MachPipeline.cpp b/src/jit/MachPipeline.cpp index 386f16e4..76fa68ae 100644 --- a/src/jit/MachPipeline.cpp +++ b/src/jit/MachPipeline.cpp @@ -627,6 +627,42 @@ namespace xo { } /*create_entry_block_alloca*/ + /* in kaleidoscope7.cpp: CreateEntryBlockAlloca */ + llvm::AllocaInst * + MachPipeline::create_entry_frame_alloca(llvm::Function * llvm_fn, + llvm::StructType * frame_llvm_type) + { + constexpr bool c_debug_flag = true; + using xo::scope; + + scope log(XO_DEBUG(c_debug_flag), + xtag("llvm_fn", (void*)llvm_fn)); + + llvm::IRBuilder<> tmp_ir_builder(&llvm_fn->getEntryBlock(), + llvm_fn->getEntryBlock().begin()); + + if (!frame_llvm_type) + return nullptr; + + if (log) { + std::string llvm_frame_type_str; + llvm::raw_string_ostream ss(llvm_frame_type_str); + frame_llvm_type->print(ss); + + log(xtag("frame_llvm_type", llvm_frame_type_str)); + } + + llvm::AllocaInst * retval = tmp_ir_builder.CreateAlloca(frame_llvm_type, + nullptr, + llvm_fn->getName()); + + log && log(xtag("alloca", (void*)retval), + xtag("align", retval->getAlign().value()), + xtag("size", retval->getAllocationSize(jit_->data_layout()).value())); + + return retval; + } /*create_entry_frame_alloca*/ + std::vector> MachPipeline::find_lambdas(ref::brw expr) const { @@ -869,7 +905,6 @@ namespace xo { } /*frame_to_llvm_type*/ } /*namespace*/ - llvm::Function * MachPipeline::codegen_lambda_defn(ref::brw lambda, llvm::IRBuilder<> & ir_builder) @@ -900,12 +935,24 @@ namespace xo { ir_builder.SetInsertPoint(block); + /* create stack frame */ + llvm::StructType * frame_llvm_type + = frame_to_llvm_type(llvm_cx_, + lambda, + llvm_fn); + + llvm::AllocaInst * frame_alloca = create_entry_frame_alloca(llvm_fn, + frame_llvm_type); + + if (!frame_alloca) + return nullptr; + /** Actual parameters will need their own activation record. * Track its shape here. * * Local variables will be formal parameters to a nested lambda; **/ - this->env_stack_.push(activation_record()); + this->env_stack_.push(activation_record(llvm_fn, frame_alloca)); { log && log("lambda: stack size Z", xtag("Z", env_stack_.size())); @@ -918,6 +965,7 @@ namespace xo { std::string arg_name = std::string(arg.getName()); +#ifdef OBSOLETE /* stack location for arg[i] */ llvm::AllocaInst * alloca = create_entry_block_alloca(llvm_fn, @@ -928,17 +976,45 @@ namespace xo { this->env_stack_.pop(); return nullptr; } +#endif + + /* need to store args to stack frame */ + + std::int32_t i_slot = env_stack_.top().lookup_var(arg_name); + + if (i_slot == -1) { + /* variable not found! */ + return nullptr; + } + + llvm::Value * i32_zero = llvm::ConstantInt::get(llvm_cx_->llvm_cx_ref(), + llvm::APInt(32, 0)); + llvm::Value * i32_slot = llvm::ConstantInt::get(llvm_cx_->llvm_cx_ref(), + llvm::APInt(32, i_slot)); + + std::array index_v = { + {i32_zero /*deref frame pointer*/, + i32_slot /*field# relative to frame pointer*/}}; + + /* location in stack frame of arg #i */ + auto arg_ptr + = ir_builder.CreateInBoundsGEP(frame_llvm_type, + frame_alloca, + index_v); /* store on function entry * see codegen_variable() for corresponding load */ - ir_builder.CreateStore(&arg, alloca); + ir_builder.CreateStore(&arg, + alloca /*destination*/); +#ifdef OBSOLETE /* remember stack location for reference + assignment * in lambda body. * */ env_stack_.top().alloc_var(arg_name, alloca); +#endif ++i; } } diff --git a/src/jit/activation_record.cpp b/src/jit/activation_record.cpp index c7f40362..cc1aaae3 100644 --- a/src/jit/activation_record.cpp +++ b/src/jit/activation_record.cpp @@ -9,21 +9,22 @@ namespace xo { using std::cerr; using std::endl; - llvm::AllocaInst * + int32_t activation_record::lookup_var(const std::string & x) const { - auto ix = frame_.find(x); + auto ix = name2ix_map_.find(x); - if (ix == frame_.end()) { + if (ix == name2ix_map_.end()) { cerr << "activation_record::lookup_var: no binding for variable x" << xtag("x", x) << endl; - return nullptr; + return -1; } return ix->second; } /*lookup_var*/ +#ifdef OBSOLETE llvm::AllocaInst * activation_record::alloc_var(const std::string & x, llvm::AllocaInst * alloca) @@ -38,6 +39,7 @@ namespace xo { frame_[x] = alloca; return alloca; } /*alloc_var*/ +#endif } /*namespace jit*/ } /*namespace xo*/