loop unrolling durch inlining hier möglich?



  • Hallo zusammen,

    ich habe folgende Klasse

    namespace
    {
        class rl_list_traverser_t
        {
    
        public:
    
            explicit
            rl_list_traverser_t(rl_val_t traverse_list, std::string func_name)
                : traverse_list{ traverse_list }
                , func_name{ func_name }
            {
            }
    
            auto car()
                -> rl_list_traverser_t&
            {
                try
                {
                    (*this).traverse_list = traverse_list.car();
                }
                catch(rl_unsupported_operation_t const& e)
                {
                    throw rl_ill_formed_list_error_t{ (*this).func_name };
                }
    
                return (*this);
            }
    
            auto cdr()
                -> rl_list_traverser_t&
            {
                try
                {
                    (*this).traverse_list = traverse_list.cdr();
                }
                catch(rl_unsupported_operation_t const& e)
                {
                    throw rl_ill_formed_list_error_t{ (*this).func_name };
                }
    
                return (*this);
            }
    
            auto get_list()
                -> rl_val_t
            {
                return traverse_list;
            }
    
        private:
    
            rl_val_t traverse_list;
            std::string func_name;
    
        }; 
    }
    

    Diese wird wie folgt verwendet:

    auto rl_lisp_cddddr(rl_val_array_t args)
        -> rl_val_array_t
    {    
        return { rl_list_traverser_t{ args[0], "cddddr" }
            .cdr()
            .cdr()
            .cdr()
            .cdr()
            .get_list();
        }
    }
    

    Es stellt sich mir die Frage ob die Chance besteht, dass hier der Code so optimiert wird, dass das Ergebnis leistungstechnisch folgendem entspricht.

    rl_val_t tmp{ args[0] };
    
    tmp = tmp.cdr();
    tmp = tmp.cdr();
    tmp = tmp.cdr();
    tmp = tmp.cdr()
    

    Oder spricht etwas konkret gegen solch eine Optimierung?

    MFG

    Martin



  • Wenn wir schon beim Thema loop unrolling sind. Hat es irgend einen Vorteil wenn die Anzahl der Durchläufe einer Zählschleife bereits währen der Kompilierung bekannt ist. Also

    template <size_t n>
    void do_it_n_times()
    {
        for(size_t i = 0; i < n; i++)
            do_it();
    }
    

    anstatt

    void do_it_n_times(size_t n)
    {
    for(size_t i = 0; i < n; i++)
    do_it();
    }
    [/code]



  • anstatt

    void do_it_n_times(size_t n)
    {
        for(size_t i = 0; i < n; i++)
            do_it();
    }
    


  • Einfach mal den erzeugten Assemblercode ansehen. Hier ist die nicht-template Version:

    int k = 0;
    
    void do_n_times(unsigned n)
    {
      for(unsigned i = 0; i < n; ++i)
      {
        k += i;
      }
    }
    
    int main()
    {
      do_n_times(5);
    }
    

    ergibt

    do_n_times(unsigned int):
    	xor	eax, eax
    	test	edi, edi
    	mov	edx, DWORD PTR k[rip]
    	je	.L1
    .L5:
    	add	edx, eax
    	add	eax, 1
    	cmp	edi, eax
    	jne	.L5
    	mov	DWORD PTR k[rip], edx
    .L1:
    	rep ret
    main:
    	add	DWORD PTR k[rip], 10
    	xor	eax, eax
    	ret
    k:
    	.zero	4
    

    Es wird zwar Code für die Funktion generiert, allerdings ist das Ergebnis schon vorberechnet in der main-Funktion und wird einfach nur noch in die Variable geschrieben.

    Man kann die Funktion static machen oder in einen anonymen Namespace packen, dann wird auch kein Code mehr dafür generiert.

    Die Template-Version

    int k = 0;
    
    template<unsigned int n>
    void t_do_n_times()
    {
      for(unsigned i = 0; i < n; ++i)
      {
        k+= i;
      }
    }
    
    int main()
    {
      t_do_n_times<5>();
    }
    

    ergibt

    main:
    	add	DWORD PTR k[rip], 10
    	xor	eax, eax
    	ret
    k:
    	.zero	4
    

    Hier ist das gleiche Ergebnis, wie mit static oder namespace {}.

    Fazit: Nein, hat keinen Vorteil, wenn dann kommt es auf den Inhalt von do_it an, ob der Compiler das zur Compilezeit berechnen kann.


Log in to reply