Example #1
0
void Codegen_C::make_code() {
    // a clone of the whole hierarchy
    ++Inst::cur_op_id;
    Vec<Expr> out, created;
    for( Expr inst : fresh )
        out << cloned( inst, created );

    // simplifications
    // e.g. ReplBits offset in bytes if possible
    // slices that do not change the size
    for( Expr &e : created )
        e->codegen_simplification( created, out );
    update_created( created, out );

    // display if necessary
    if ( disp_inst_graph )
        Inst::display_graph( out );

    // scheduling (and creation of IfInst)
    Inst *beg = scheduling( out );
    update_created( created, out );

    // display if necessary
    if ( disp_inst_graph_wo_phi )
        Inst::display_graph( out );

    // get reg constraints
    struct GetConstraint : Inst::Visitor {
        virtual bool operator()( Inst *inst ) {
            inst->get_constraints();
            return true;
        }
    };
    GetConstraint gc;
    beg->visit_sched( gc, true );

    //
    //    DisplayConstraints dv;
    //    beg->visit_sched( dv );

    // assign (missing) out_reg
    struct AssignOutReg : Inst::Visitor {
        virtual bool operator()( Inst *inst ) {
            if ( inst->out_reg or not inst->need_a_register() )
                return true;

            // make a new reg
            CppOutReg *out_reg = cc->new_out_reg( inst->type() );

            // assign out_reg + constraint propagation ()
            Vec<InstAndPort> assigned_ports;
            if ( not assign_port_rec( assigned_ports, inst, -1, out_reg ) ) {
                std::cerr << "base constraint cannot be fullfilled !\n";
                return false;
            }

            // edges and optionnal constraints
            int num_edge = 0; // , num_optionnal_constraint = 0;
            while ( true ) {
                // there's an edge for propagation ?
                if ( num_edge < assigned_ports.size() ) {
                    InstAndPort port = assigned_ports[ num_edge++ ];
                    if ( port.is_an_output() ) {
                        // sort parents by apparition order
                        struct SortBySchedNum {
                            bool operator()( const Inst::Parent &a, const Inst::Parent &b ) const {
                                return a.inst->sched_num < b.inst->sched_num;
                            }
                        };
                        port.inst->update_sched_num();
                        std::sort( port.inst->par.begin(), port.inst->par.end(), SortBySchedNum() );

                        // try to propagate the reg through each output edge
                        CppOutReg *reg = port.inst->out_reg;
                        for( Inst::Parent &p : port.inst->par ) {
                            // std::cout << "    " << *port.inst << " -> " << *p.inst << std::endl;
                            for( Inst *inst = port.inst; ; inst = inst->next_sched ) {
                                // target is reached ?
                                if ( inst == p.inst ) {
                                    // assign input port, or insert a copy instruction
                                    if ( not assign_port_rec( assigned_ports, p.inst, p.ninp, reg ) )
                                        insert_copy_inst_before( assigned_ports, inst, p );
                                    break;
                                }

                                // if there a conflict
                                if ( not inst->used_reg_ok_for( reg, port.inst ) ) {
                                    // add a copy inst
                                    insert_copy_inst_before( assigned_ports, inst, p );
                                    break;
                                }
                                // -> say that here, reg should be the output of port.inst (and nothing else)
                                inst->add_used_reg( reg, port.inst );
                            }
                        }
                    } else {
                        CppOutReg *reg = port.inst->inp_reg[ port.ninp() ];
                        if ( Inst *dst = port.inst->inp[ port.ninp() ].inst ) {
                            // std::cout << "    " << *port.inst << " <- " << *dst << " " << reg << std::endl;
                            for( Inst *inst = port.inst->prev_sched; ; inst = inst->prev_sched ) {
                                if ( not inst ) {
                                    PRINT( *port.inst );
                                    PRINT( *dst );
                                    ERROR( "..." );
                                }

                                // target is reached ?
                                if ( inst == dst ) {
                                    Inst *beg_reg = dst;
                                    // assign output port, or insert a copy instruction
                                    if ( not assign_port_rec( assigned_ports, dst, -1, reg ) ) {
                                        insert_copy_inst_after( assigned_ports, dst, port );
                                        beg_reg = dst->next_sched; // reg will be used starting from the copy inst
                                    }
                                    // -> register the use of reg as output of beg_reg
                                    for( Inst *d = beg_reg; d != port.inst; d = d->next_sched )
                                        inst->add_used_reg( reg, beg_reg );
                                    break;
                                }

                                // if there is a conflict
                                if ( not inst->used_reg_ok_for( reg, dst ) ) {
                                    // add a copy inst
                                    insert_copy_inst_after( assigned_ports, inst, port );
                                    // -> register the use of reg as output of beg_reg
                                    for( Inst *c = inst->next_sched, *d = c; d != port.inst; d = d->next_sched )
                                        inst->add_used_reg( reg, c );
                                    break;
                                }
                            }
                        }
                    }

                    continue;
                }

                // constraint that would be good to fullfill
                //            if ( num_optionnal_constraint < assigned_ports.size() ) {
                //                InstAndPort port = assigned_ports[ num_optionnal_constraint++ ];

                //                for( std::pair<const Inst::PortConstraint,int> &c : port.inst->same_out )
                //                    if ( c.second != Inst::COMPULSORY and c.first.src_ninp == port.ninp_constraint() )
                //                        assign_port_rec( assigned_ports, c.first.dst_inst, c.first.dst_ninp, out_reg );

                //                continue;
                //            }


                // nothing to propagate
                break;
            }
            return true;
        }
        Codegen_C *cc;
    };
    AssignOutReg aor; aor.cc = this;
    beg->visit_sched( aor, true );

    // display if necessary
    //    if ( disp_inst_graph_wo_phi ) {
    //        beg->update_sched_num();
    //        Inst::display_graph( out );
    //    }

    // specify where the registers have to be declared
    for( int n = 0; n < out_regs.size(); ++n ) {
        CppOutReg *reg = &out_regs[ n ];
        Inst *anc = reg->common_provenance_ancestor();
        anc->reg_to_decl << reg;
    }

    // write the code
    for( Inst *inst = beg; inst; inst = inst->next_sched )
        write( inst );
}