使用整数的C++模板化数组运算符[]

teo*_*ron 3 c++ templates operator-overloading swizzling

我正在尝试操纵一个特殊的结构,我需要某种混合运算符.为此,有一个重载的数组[]运算符是有意义的,但我不想有任何分支,因为结构的特定规范允许理论上的解决方法.

目前,结构看起来像这样:

struct f32x4
{
    float fLow[2];
    float fHigh[2];

    f32x4(float a, float b, float c, float d)
    {
        fLow[0] = a; 
        fLow[1] = b;
        fHigh[0] = c;
        fHigh[1] = d;
    }

    // template with an int here?
    inline float& operator[] (int x) {
        if (x < 2)
            return fLow[x];
        else
            return fHigh[x - 2];
    }
};
Run Code Online (Sandbox Code Playgroud)

我可以/应该做些什么来避免分支?我的想法是使用带有整数参数的模板并定义特化,但目前尚不清楚它是否有意义以及该怪物的语法是什么样的.

在任何情况下,我都没有明确地使用float[4]数组来合并这两个(也没有联合技巧).如果你需要一个很好的理由,那是因为它float[2]实际上类似于平台特定的PowerPC配对单曲.普通的Windows编译器不适用于配对的单个,这就是我用float[2]s 替换代码的原因.

使用GreenHills编译器我得到这个程序集输出(这表明分支确实发生):

.LDW31:
00000050 80040000           89      lwz r0, 0(r4)
00000054 2c000000           90      cmpwi   r0, 0
00000058 41820000           91      beq .L69
                            92  #line32
                            93  
                            94  .LDWlin1:
0000005c 2c000001           95      cmpwi   r0, 1
00000060 40820000           96      bne .L74
                            97  #line32
                            98  
                            99  .LDWlin2:
00000064 38630004          100      addi    r3, r3, 4
00000068 38210018          101      addi    sp, sp, 24
0000006c 4e800020          102      blr
                           103  .L74:
00000070 2c000002          104      cmpwi   r0, 2
00000074 40820000          105      bne .L77
                           106  #line33
                           107  
                           108  .LDWlin3:
00000078 38630008          109      addi    r3, r3, 8
0000007c 38210018          110      addi    sp, sp, 24
00000080 4e800020          111      blr
                           112  .L77:
00000084 2c000003          113      cmpwi   r0, 3
00000088 40820000          114      bne .L80
                           115  #line34
                           116  
                           117  .LDWlin4:
0000008c 3863000c          118      addi    r3, r3, 12
00000090 38210018          119      addi    sp, sp, 24
00000094 4e800020          120      blr
                           121  .L80:
00000098 38610008          122      addi    r3, sp, 8
                           123  .L69:
                           124  #       .ef
Run Code Online (Sandbox Code Playgroud)

该片段的相应C++代码应该是这个:

 inline const float& operator[](const unsigned& idx) const
        {
            if (idx == 0)  return xy[0];
            if (idx == 1)  return xy[1];
            if (idx == 2)  return zw[0];
            if (idx == 3)  return zw[1];
            return 0.f;
        }
Run Code Online (Sandbox Code Playgroud)

Use*_*ess 6

索引x是运行时变量,还是编译时常量.

  • 如果它是一个编译时常量,那么优化器很可能在内联时修剪死分支operator[].

  • 如果是运行时变量,就像

    for (int i=0; i<4; ++i) { dosomething(f[i]); }
    
    Run Code Online (Sandbox Code Playgroud)

    无论如何你需要分支.当然,除非你的优化器展开循环,在这种情况下它可以用四个常量替换变量,如上所述内联和修剪.

您是否对此进行了剖析以显示存在真正的问题,并对其进行编译以显示分支是否真的发生在可以避免的地方?


示例代码:

float foo(f32x4 &f)
{
    return f[0]+f[1]+f[2]+f[3];
}
Run Code Online (Sandbox Code Playgroud)

来自的示例输出 g++ -O3 -S

.globl _Z3fooR5f32x4
        .type       _Z3fooR5f32x4, @function
_Z3fooR5f32x4:
.LFB4:
        .cfi_startproc
        movss       (%rdi), %xmm0
        addss       4(%rdi), %xmm0
        addss       8(%rdi), %xmm0
        addss       12(%rdi), %xmm0
        ret
        .cfi_endproc
Run Code Online (Sandbox Code Playgroud)