表达式模板代码未完全优化

时间:2018-08-20 16:59:54

标签: c++ optimization expression-templates

在C ++中,我有以下线性代数函数调用(向量-向量加法)。

int m = 4;

blasfeo_dvec one, two, three;

blasfeo_allocate_dvec(m, &one);
blasfeo_allocate_dvec(m, &two);
blasfeo_allocate_dvec(m, &three);

// initialize vectors ... (omitted)

blasfeo_daxpy(m, 1.0, &one, 0, &two, 0, &three, 0);

使用expression templates(ET),我们可以将其包装如下:

three = one + two;

向量struct看起来像

struct blasfeo_dvec {
    int m;          // length
    int pm;         // packed length
    double *pa;     // pointer to a pm array of doubles, the first is aligned to cache line size
    int memsize;    // size of needed memory

    void operator=(const vec_expression_sum<blasfeo_dvec, blasfeo_dvec> expr) {
        blasfeo_daxpy(m, 1.0, (blasfeo_dvec *) &expr.vec_a, 0, (blasfeo_dvec *) &expr.vec_b, 0, this, 0);
    }
};

强制转换为非const是因为blasfeo_daxpy采用非const指针。 ET代码很简单

template<typename Ta, typename Tb>
struct vec_expression_sum {
    const Ta vec_a;
    const Tb vec_b;

    vec_expression_sum(const Ta va, const Tb vb) : vec_a {va}, vec_b {vb} {}
};

template<typename Ta, typename Tb>
auto operator+(const Ta a, const Tb b) {
    return vec_expression_sum<Ta, Tb>(a, b);
}

“本地”调用即blasfeo_daxpy(...)生成以下程序集:

; allocation and initialization omitted ...
movl    $0, (%rsp)
movl    $4, %edi
xorl    %edx, %edx
xorl    %r8d, %r8d
movsd   LCPI0_0(%rip), %xmm0    ## xmm0 = mem[0],zero
movq    %r14, %rsi
movq    %rbx, %rcx
movq    %r15, %r9
callq   _blasfeo_daxpy
...

这正是您所期望的。 ET代码更长一些:

; allocation :
leaq    -120(%rbp), %rbx
movl    $4, %edi
movq    %rbx, %rsi
callq   _blasfeo_allocate_dvec
leaq    -96(%rbp), %r15
movl    $4, %edi
movq    %r15, %rsi
callq   _blasfeo_allocate_dvec
leaq    -192(%rbp), %r14
movl    $4, %edi
movq    %r14, %rsi
callq   _blasfeo_allocate_dvec

; initialization code omitted    

; operator+ :
movq    -104(%rbp), %rax
movq    %rax, -56(%rbp)
movq    -120(%rbp), %rax
movq    -112(%rbp), %rcx
movq    %rcx, -64(%rbp)
movq    %rax, -72(%rbp)

; vec_expression_sum : 
movq    -80(%rbp), %rax
movq    %rax, -32(%rbp)
movq    -96(%rbp), %rax
movq    -88(%rbp), %rcx
movq    %rcx, -40(%rbp)
movq    %rax, -48(%rbp)
movq    -32(%rbp), %rax
movq    %rax, -128(%rbp)
movq    -40(%rbp), %rax
movq    %rax, -136(%rbp)
movq    -48(%rbp), %rax
movq    %rax, -144(%rbp)
movq    -56(%rbp), %rax
movq    %rax, -152(%rbp)
movq    -72(%rbp), %rax
movq    -64(%rbp), %rcx
movq    %rcx, -160(%rbp)
movq    %rax, -168(%rbp)
leaq    -144(%rbp), %rcx

; blasfeo_daxpy :
movl    -192(%rbp), %edi
movl    $0, (%rsp)
leaq    -168(%rbp), %rsi
xorl    %edx, %edx
xorl    %r8d, %r8d
movsd   LCPI0_0(%rip), %xmm0    ## xmm0 = mem[0],zero
movq    %r14, %r9
callq   _blasfeo_daxpy
...

它涉及大量复制,即blasfeo_dvec的字段。我(天真的,也许是)希望ET代码能够生成与本地调用完全相同的代码,因为所有内容都是在编译时固定的,const是固定的,但事实并非如此。

问题是:为什么要加重负载?,有没有办法获得完全“优化”的代码? (编辑:我将Apple LLVM版本8.1.0(clang-802.0.42)与-std=c++14 -O3一起使用)

注意:我阅读并了解了thisthis关于类似主题的帖子,但是很遗憾,它们没有包含我的问题的答案。

0 个答案:

没有答案