找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 222|回复: 3

【图形学】不使用矩阵乘法实现生成四阶欧拉角旋转矩阵

[复制链接]
发表于 2026-5-2 19:43:28 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×

不使用矩阵乘法实现生成四阶欧拉角旋转矩阵

欧拉角旋转矩阵

欧拉角旋转矩阵在图形学有很多的作用,配合平移矩阵,可以通过平移坐标 + 旋转,对一个需要渲染的物件的空间姿态进行控制。当给这个物件的所有顶点都经过矩阵变换后,就可以得到它在屏幕上的显示坐标。

欧拉角旋转矩阵是通过将单位矩阵先进行按 Z 轴的滚动旋转,然后再按 X 轴进行俯仰旋转,最后按 Y 轴进行朝向旋转。这样一来,就需要按 X、Y、Z 三个轴都旋转一下,需要生成三个矩阵,用矩阵乘法合并三个矩阵得到一个矩阵,让每个顶点都按这个矩阵进行旋转;或者不把三个矩阵合并,但是每个顶点需要分别乘以滚动、俯仰、朝向矩阵,才能变换到指定旋转后的位置。因此需要优化欧拉角旋转矩阵的生成方式,一次性生成一整个矩阵。

示例代码(未优化版:生成三个轴的旋转矩阵,再合并矩阵。)

#include <math.h>

typedef struct Vector_s
{
    float x, y, z, w;
}Vector_t, *Vector_p;

typedef struct Matrix_s
{
    Vector_t x, y, z, w;
}Matrix_t, *Matrix_p;

static void MatrixItentity(Matrix_p out)
{
    *out = (Matrix_t){
        {1, 0, 0, 0},
        {0, 1, 0, 0},
        {0, 0, 1, 0},
        {0, 0, 0, 1},
    };
}

static void MatrixRotationX(Matrix_p out, float angle)
{
    float ca = (float)cos(angle);
    float sa = (float)sin(angle);
    *out = (Matrix_t){
        {1, 0, 0, 0},
        {0, ca, sa, 0},
        {0, -sa, ca, 0},
        {0, 0, 0, 1},
    };
}

static void MatrixRotationY(Matrix_p out, float angle)
{
    float ca = (float)cos(angle);
    float sa = (float)sin(angle);
    *out = (Matrix_t){
        {ca, 0, -sa, 0},
        {0, 1, 0, 0},
        {sa, 0, ca, 0},
        {0, 0, 0, 1},
    };
}

static void MatrixRotationZ(Matrix_p out, float angle)
{
    float ca = (float)cos(angle);
    float sa = (float)sin(angle);
    *out = (Matrix_t){
        {ca, sa, 0, 0},
        {-sa, ca, 0, 0},
        {0, 0, 1, 0},
        {0, 0, 0, 1},
    };
}

static void VectorMultMatrix(Vector_p out, Vector_p v, Matrix_p m)
{
    *out = (Vector_t){
        v->x * m->x.x + v->y * m->y.x + v->z * m->z.x + v->w * m->w.x,
        v->x * m->x.y + v->y * m->y.y + v->z * m->z.y + v->w * m->w.y,
        v->x * m->x.z + v->y * m->y.z + v->z * m->z.z + v->w * m->w.z,
        v->x * m->x.w + v->y * m->y.w + v->z * m->z.w + v->w * m->w.w
    };
}

static void MatrixMultMatrix(Matrix_p out, Matrix_p l, Matrix_p r)
{
    Vector_t ox, oy, oz, ow;
    VectorMultMatrix(&ox, &l->x, r);
    VectorMultMatrix(&oy, &l->y, r);
    VectorMultMatrix(&oz, &l->z, r);
    VectorMultMatrix(&ow, &l->w, r);
    *out = (Matrix_t){ox, oy, oz, ow};
}

void MatrixRotationEuler(Matrix_p out, float yaw, float pitch, float roll)
{
    Matrix_t ym, pm, rm, rpm;
    MatrixRotationZ(&rm, roll);
    MatrixRotationX(&pm, pitch);
    MatrixRotationY(&ym, yaw);
    MatrixMultMatrix(&rpm, &rm, &pm);
    MatrixMultMatrix(out, &ym, &rpm);
}

尝试优化:减少不必要的计算步骤

由于按 X、Y、Z 旋转的俯仰、朝向、滚动的矩阵里面有很多成员的值都是零,其实会有很多无用的计算。此处我使用 TDM-GCC 通过设置 -O3 的优化将上述代码编译为 32 位、使用 FPU 进行计算的二进制,然后使用 IDA 进行逆向,看看它能不能帮我完成代数运算的项合并。

IDA.png

如图所示,直接生啃 FPU 的指令实在是令人头大。不如按 F5,对生成的 C 代码进行一些标注,应该能得到更清晰的计算过程。

IDAF5.png

目前的问题

可以看到它有非常多的局部变量,并且对这些变量进行赋值时,会有很多的乘零、加零的操作。 恕我直言,这 gcc10 是有点逊啦!

TDM-GCC.png

对反编译的变量名进行标记

标记规则:

  • 朝向角(yaw)的 cos 值名为 cy,yaw 的 sin 值为 sy;以此类推的话,俯仰角(pitch)的 cos 值名为 cp,sin 值为 sp;滚动角(roll)的 cos 和 sin 值分别为 crsr
  • 如果是负值,则添加 n 前缀(negative),比如负的 cy 起名为 ncy,以此类推。
  • 乘到一起的项,则将名字合并。比如 cp * sr 得到的值存入的变量名为 cpsr
  • 如果遇到不同的变量但是具有相同的值,则给这个变量名字后面加下划线,比如重复的 cpsr 变量,取名为 cpsr_cpsr__ 等,以此类推。
  • 值为零的变量取名为 zr,并且根据变量的数量,后面加上十进制的数值后缀,比如 zr0zr1,以此类推。

标记后的代码:

void __cdecl MatrixRotationEuler(float *out, float yaw, float pitch, float roll)
{
    long double sr__; // fst6
    long double zr0; // fst5
    long double zr1; // fst4
    long double zr2; // fst3
    long double cp_; // fst2
    long double zr3; // fst1
    long double zr4; // rt0
    long double zr5; // fst1
    long double zr6; // fst5
    long double cp__; // rt1
    long double zr8; // fst2
    long double zr9; // fst1
    long double crsp; // fst4
    long double zr11; // fst2
    long double nsp; // fst1
    long double zr12; // rt0
    long double cp___; // rt1
    long double nsp_; // fst6
    long double zr15; // fst2
    long double crsp_; // fst0
    long double zr16; // fst4
    long double zr18; // fst1
    long double zr19; // fst3
    long double cpsr_; // fst5
    float sr; // [esp+10h] [ebp-6Ch]
    float cy; // [esp+10h] [ebp-6Ch]
    float sp; // [esp+14h] [ebp-68h]
    float zr14; // [esp+14h] [ebp-68h]
    float cr; // [esp+18h] [ebp-64h]
    float zr17; // [esp+18h] [ebp-64h]
    float sy; // [esp+1Ch] [ebp-60h]
    float nsy; // [esp+20h] [ebp-5Ch]
    float sr_; // [esp+24h] [ebp-58h]
    float cr_; // [esp+24h] [ebp-58h]
    float cp; // [esp+28h] [ebp-54h]
    float spsr; // [esp+28h] [ebp-54h]
    float zr7; // [esp+2Ch] [ebp-50h]
    float zr21; // [esp+30h] [ebp-4Ch]
    float zr13; // [esp+34h] [ebp-48h]
    float cpsr; // [esp+38h] [ebp-44h]
    float cp____; // [esp+38h] [ebp-44h]
    float nsr; // [esp+3Ch] [ebp-40h]
    float crcp; // [esp+40h] [ebp-3Ch]
    float zr10; // [esp+44h] [ebp-38h]
    float zr23; // [esp+48h] [ebp-34h]
    float zr24; // [esp+4Ch] [ebp-30h]
    float zr25; // [esp+50h] [ebp-2Ch]
    float zr26; // [esp+54h] [ebp-28h]
    float zr27; // [esp+58h] [ebp-24h]
    float zr28; // [esp+5Ch] [ebp-20h]
    float zr22; // [esp+60h] [ebp-1Ch]
    float zr20; // [esp+64h] [ebp-18h]
    float crsp__; // [esp+68h] [ebp-14h]
    float zr29; // [esp+6Ch] [ebp-10h]

    cr = cos(roll);
    sr = sin(roll);
    sr_ = sr;
    cp = cos(pitch);
    sp = sin(pitch);
    cy = cos(yaw);
    sy = sin(yaw);
    nsy = -sy;
    sr__ = sr_;
    zr0 = sr_ * 0.0;
    cr_ = cr + zr0 + 0.0;
    zr1 = cr * 0.0;
    zr2 = -sp * 0.0;
    cp_ = cp;
    cpsr = cp * sr__ + zr1 + zr2 + 0.0;
    zr3 = cp * 0.0;
    spsr = sp * sr__ + zr1 + zr3 + 0.0;
    zr4 = zr3;
    zr5 = zr0;
    zr6 = zr4;
    zr7 = zr5 + zr1 + 0.0;
    nsr = zr1 - sr__ + 0.0;
    cp__ = cp_;
    zr8 = -sr__ * 0.0;
    crcp = cr * cp__ + zr8 + zr2 + 0.0;
    zr9 = zr1;
    crsp = cr * sp + zr8 + zr4 + 0.0;
    zr10 = zr8 + zr9 + 0.0;
    zr11 = zr4 + 0.0;
    nsp = zr4 + 0.0 - sp + 0.0;
    zr12 = sp * 0.0 + 0.0;
    cp___ = cp__ + zr12 + 0.0;
    zr13 = zr11 + zr2 + 0.0;
    nsp_ = nsp;
    zr14 = nsr * 0.0;
    zr15 = nsy * 0.0;
    crsp_ = crsp;
    zr16 = zr13 * 0.0;
    crsp__ = crsp_;
    zr17 = crsp_ * 0.0;
    zr18 = zr6 + zr12 + 0.0;
    zr19 = crcp * 0.0;
    zr20 = zr18;
    zr21 = zr18 * 0.0;
    zr22 = zr10 * 0.0;
    zr23 = cr_ * 0.0;
    zr24 = cpsr * 0.0;
    zr25 = nsp_ * 0.0;
    zr26 = spsr * 0.0;
    cpsr_ = cpsr;
    cp____ = cp___;
    zr27 = cp___ * 0.0;
    zr28 = zr7 * 0.0;
    zr29 = cy * 0.0;
    out[0] = cy * cr_ + zr14 + zr15 + 0.0;
    out[1] = cy * cpsr_ + zr19 + nsy * nsp_ + zr16;
    out[2] = cy * spsr + zr17 + nsy * cp____ + zr21;
    out[3] = zr15 + zr7 * cy + zr22 + 0.0;
    out[4] = nsr + zr23 + 0.0;
    out[5] = crcp + zr24 + zr25 + zr16;
    out[6] = crsp__ + zr26 + zr27 + zr21;
    out[7] = zr10 + zr28 + 0.0;
    out[8] = cr_ * sy + zr14 + zr29 + 0.0;
    out[9] = zr16 + cpsr_ * sy + zr19 + nsp_ * cy;
    out[10] = spsr * sy + zr17 + cy * cp____ + zr21;
    out[11] = zr29 + sy * zr7 + zr22 + 0.0;
    out[12] = zr23 + zr14 + 0.0;
    out[13] = zr19 + zr24 + zr25 + zr13;
    out[14] = zr26 + zr17 + zr27 + zr20;
    out[15] = zr22 + zr28 + 0.0 + 1.0;
}

可以看到,有大量的变量值为零,并且有非常多的重复的值的变量。

剔除无用变量,手动简化代码

#include <math.h>

typedef struct Vector_s
{
    float x, y, z, w;
}Vector_t, *Vector_p;

typedef struct Matrix_s
{
    Vector_t x, y, z, w;
}Matrix_t, *Matrix_p;

void MatrixRotationEuler(Matrix_p out, float yaw, float pitch, float roll)
{
    float cy = (float)cos(yaw);
    float sy = (float)sin(yaw);
    float cp = (float)cos(pitch);
    float sp = (float)sin(pitch);
    float cr = (float)cos(roll);
    float sr = (float)sin(roll);
    float cpsr = cp * sr;
    float spsr = sp * sr;
    *out = (Matrix_t){
        {
            cy * cr,
            cy * cpsr + sy * sp,
            cy * spsr - sy * cp,
            0.0f
        },
        {
            -sr,
            cr * cp,
            cr * sp,
            0.0f
        },
        {
            cr * sy,
            cpsr * sy - sp * cy,
            spsr * sy + cp * cy,
            0.0f
        },
        {
            0.0f,
            0.0f,
            0.0f,
            1.0f
        },
    };
}

既然 GCC 那么菜,那么 clang 的表现如何呢?

人肉编译优化过的 C 源码

如果是我手写汇编(我 = 人肉编译器),得到的指令是像下面这样的(已根据流水线优化的需求,对代码进行排序)

segment .bss
alignb 16
global _ZeroVector
_ZeroVector resd 4

segment .text
; void MatrixRotationEuler(Matrix_p out, float yaw, float pitch, float roll)
global _MatrixRotationEuler
_MatrixRotationEuler:
    sub esp, 32
    %define _CY [esp]
    %define _SY [esp + 4]
    %define _CP [esp + 8]
    %define _SP [esp + 12]
    %define _CR [esp + 16]
    %define _SR [esp + 20]
    %define _CPSR [esp + 24]
    %define _SPSR [esp + 28]
    %define _OUT [esp + 36]
    %define _YAW [esp + 40]
    %define _PITCH [esp + 44]
    %define _ROLL [esp + 48]

    fld dword _YAW
    fsincos
    fstp _CY
    fstp _SY
    fld dword _PITCH
    fsincos
    fstp _CP
    fstp _SP
    fld dword _ROLL
    fsincos
    fstp _CR
    fstp _SR

    mov eax, _OUT
    movaps xmm0, [_ZeroVector]
    movaps [eax + Matrix.x], xmm0
    movaps [eax + Matrix.y], xmm0
    movaps [eax + Matrix.z], xmm0
    movaps [eax + Matrix.w], xmm0

    movss xmm0, _CP
    movss xmm1, _SP
    movss xmm2, _CR
    movss xmm3, _CY
    movss xmm4, _CY
    movss xmm5, _SY
    movss xmm6, _CY
    movss xmm7, _SY
    mulss xmm0, _SR
    mulss xmm1, _SR
    mulss xmm2, _CP
    mulss xmm3, _CR
    mulss xmm4, xmm0
    mulss xmm5, _SP
    mulss xmm6, xmm1
    mulss xmm7, _CP
    addss xmm4, xmm5
    subss xmm6, xmm7
    movss _CPSR, xmm0
    movss _SPSR, xmm1
    movss [eax + Matrix.xx], xmm3
    movss [eax + Matrix.xy], xmm4
    movss [eax + Matrix.xz], xmm6
    movss [eax + Matrix.yy], xmm2

    movss xmm0, [_ZeroVector]
    movss xmm1, _CR
    movss xmm2, _CR
    movss xmm3, _CPSR
    movss xmm4, _SP
    movss xmm5, _SPSR
    movss xmm6, _CY
    subss xmm0, _SR
    mulss xmm1, _SP
    mulss xmm2, _SY
    mulss xmm3, _SY
    mulss xmm4, _CY
    mulss xmm5, _SY
    mulss xmm6, _CP
    subss xmm3, xmm4
    addss xmm5, xmm6
    movss [eax + Matrix.yx], xmm0
    movss [eax + Matrix.yz], xmm1
    movss [eax + Matrix.zx], xmm2
    movss [eax + Matrix.zy], xmm3
    movss [eax + Matrix.zz], xmm5
    mov dword[eax + Matrix.ww], 0x3F800000

    add esp, 32
    ret
    %undef _CY
    %undef _SY
    %undef _CP
    %undef _SP
    %undef _CR
    %undef _SR
    %undef _CPSR
    %undef _SPSR
    %undef _OUT
    %undef _YAW
    %undef _PITCH
    %undef _ROLL

使用 clang 开 -O3 编译原始源码(编译为 x86-64 平台机器,生成汇编文件)

请看汇编:

    .def    @feat.00;
    .scl    3;
    .type   0;
    .endef
    .globl  @feat.00
@feat.00 = 0
    .intel_syntax noprefix
    .file   "matrot.c"
    .def    MatrixRotationEuler;
    .scl    2;
    .type   32;
    .endef
    .globl  __xmm@80000000800000008000000080000000 # -- Begin function MatrixRotationEuler
    .section    .rdata,"dr",discard,__xmm@80000000800000008000000080000000
    .p2align    4, 0x0
__xmm@80000000800000008000000080000000:
    .long   0x80000000                      # float -0
    .long   0x80000000                      # float -0
    .long   0x80000000                      # float -0
    .long   0x80000000                      # float -0
    .globl  __real@80000000
    .section    .rdata,"dr",discard,__real@80000000
    .p2align    2, 0x0
__real@80000000:
    .long   0x80000000                      # float -0
    .globl  __xmm@00000000000000008000000080000000
    .section    .rdata,"dr",discard,__xmm@00000000000000008000000080000000
    .p2align    4, 0x0
__xmm@00000000000000008000000080000000:
    .long   0x80000000                      # float -0
    .long   0x80000000                      # float -0
    .long   0x00000000                      # float 0
    .long   0x00000000                      # float 0
    .globl  __xmm@00000000000000003f80000000000000
    .section    .rdata,"dr",discard,__xmm@00000000000000003f80000000000000
    .p2align    4, 0x0
__xmm@00000000000000003f80000000000000:
    .long   0x00000000                      # float 0
    .long   0x3f800000                      # float 1
    .zero   4
    .zero   4
    .text
    .globl  MatrixRotationEuler
    .p2align    4
MatrixRotationEuler:                    # @MatrixRotationEuler
.seh_proc MatrixRotationEuler
# %bb.0:
    push    rsi
    .seh_pushreg rsi
    sub rsp, 368
    .seh_stackalloc 368
    movaps  xmmword ptr [rsp + 352], xmm15  # 16-byte Spill
    .seh_savexmm xmm15, 352
    movaps  xmmword ptr [rsp + 336], xmm14  # 16-byte Spill
    .seh_savexmm xmm14, 336
    movaps  xmmword ptr [rsp + 320], xmm13  # 16-byte Spill
    .seh_savexmm xmm13, 320
    movaps  xmmword ptr [rsp + 304], xmm12  # 16-byte Spill
    .seh_savexmm xmm12, 304
    movaps  xmmword ptr [rsp + 288], xmm11  # 16-byte Spill
    .seh_savexmm xmm11, 288
    movaps  xmmword ptr [rsp + 272], xmm10  # 16-byte Spill
    .seh_savexmm xmm10, 272
    movaps  xmmword ptr [rsp + 256], xmm9   # 16-byte Spill
    .seh_savexmm xmm9, 256
    movaps  xmmword ptr [rsp + 240], xmm8   # 16-byte Spill
    .seh_savexmm xmm8, 240
    movaps  xmmword ptr [rsp + 224], xmm7   # 16-byte Spill
    .seh_savexmm xmm7, 224
    movaps  xmmword ptr [rsp + 208], xmm6   # 16-byte Spill
    .seh_savexmm xmm6, 208
    .seh_endprologue
    movaps  xmm6, xmm2
    movaps  xmm7, xmm1
    mov rsi, rcx
    xorps   xmm8, xmm8
    cvtss2sd    xmm8, xmm3
    movaps  xmm0, xmm8
    call    cos
    xorps   xmm11, xmm11
    cvtsd2ss    xmm11, xmm0
    movaps  xmm0, xmm8
    call    sin
    xorps   xmm9, xmm9
    cvtsd2ss    xmm9, xmm0
    movaps  xmm0, xmmword ptr [rip + __xmm@80000000800000008000000080000000] # xmm0 = [-0.0E+0,-0.0E+0,-0.0E+0,-0.0E+0]
    xorps   xmm0, xmm9
    movaps  xmmword ptr [rsp + 192], xmm0   # 16-byte Spill
    cvtss2sd    xmm6, xmm6
    movaps  xmm0, xmm6
    call    cos
    xorps   xmm8, xmm8
    cvtsd2ss    xmm8, xmm0
    movaps  xmm0, xmm6
    call    sin
    cvtsd2ss    xmm0, xmm0
    movaps  xmmword ptr [rsp + 64], xmm0    # 16-byte Spill
    xorps   xmm6, xmm6
    cvtss2sd    xmm6, xmm7
    movaps  xmm0, xmm6
    call    cos
    cvtsd2ss    xmm0, xmm0
    movaps  xmmword ptr [rsp + 32], xmm0    # 16-byte Spill
    movaps  xmm0, xmm6
    call    sin
    xorps   xmm7, xmm7
    cvtsd2ss    xmm7, xmm0
    xorps   xmm4, xmm4
    movaps  xmm13, xmm9
    mulss   xmm13, xmm4
    movaps  xmm14, xmm13
    addss   xmm14, xmm11
    addss   xmm14, xmm4
    movaps  xmm10, xmm9
    mulss   xmm10, xmm8
    movaps  xmm12, xmm11
    movaps  xmm6, xmm11
    mulss   xmm12, xmm4
    addss   xmm10, xmm12
    movss   xmm11, dword ptr [rip + __real@80000000] # xmm11 = [-0.0E+0,0.0E+0,0.0E+0,0.0E+0]
    movaps  xmm1, xmm9
    movaps  xmm5, xmm12
    movaps  xmmword ptr [rsp + 96], xmm12   # 16-byte Spill
    subss   xmm5, xmm9
    movaps  xmm15, xmm6
    mulss   xmm15, xmm8
    movaps  xmmword ptr [rsp + 128], xmm8   # 16-byte Spill
    mulss   xmm9, xmm11
    addss   xmm15, xmm9
    movaps  xmm3, xmmword ptr [rsp + 64]    # 16-byte Reload
    mulss   xmm6, xmm3
    addss   xmm6, xmm9
    movaps  xmmword ptr [rsp + 160], xmm6   # 16-byte Spill
    movaps  xmm2, xmm3
    mulss   xmm2, xmm11
    addss   xmm10, xmm2
    movaps  xmm9, xmm2
    addss   xmm10, xmm4
    movaps  xmm6, xmm10
    mulss   xmm6, xmm4
    movaps  xmm2, xmm14
    movaps  xmm0, xmm7
    movaps  xmmword ptr [rsp + 80], xmm7    # 16-byte Spill
    mulss   xmm2, xmm7
    movaps  xmm7, xmm6
    subss   xmm7, xmm2
    mulss   xmm1, xmm3
    movaps  xmm11, xmm3
    addss   xmm1, xmm12
    movaps  xmm12, xmm8
    mulss   xmm12, xmm4
    addss   xmm1, xmm12
    movaps  xmmword ptr [rsp + 144], xmm12  # 16-byte Spill
    addss   xmm1, xmm4
    movaps  xmm8, xmm1
    movaps  xmm2, xmmword ptr [rsp + 32]    # 16-byte Reload
    mulss   xmm8, xmm2
    addss   xmm8, xmm7
    movaps  xmm7, xmm14
    mulss   xmm7, xmm4
    addss   xmm7, xmm6
    movaps  xmm3, xmm1
    mulss   xmm3, xmm4
    addss   xmm3, xmm7
    addss   xmm15, xmm9
    movaps  xmmword ptr [rsp + 112], xmm15  # 16-byte Spill
    movaps  xmm15, xmm12
    addss   xmm15, xmm4
    addss   xmm9, xmm15
    movaps  xmmword ptr [rsp + 48], xmm9    # 16-byte Spill
    subss   xmm15, xmm11
    movaps  xmm9, xmm15
    mulss   xmm9, xmm4
    mulss   xmm2, xmm4
    movaps  xmm12, xmm2
    addss   xmm12, xmm9
    movss   xmm7, dword ptr [rip + __real@80000000] # xmm7 = [-0.0E+0,0.0E+0,0.0E+0,0.0E+0]
    mulss   xmm7, xmm0
    movaps  xmm11, xmm7
    addss   xmm11, xmm9
    addss   xmm9, xmm4
    unpcklps    xmm11, xmm9                     # xmm11 = xmm11[0],xmm9[0],xmm11[1],xmm9[1]
    movaps  xmm9, xmmword ptr [rsp + 48]    # 16-byte Reload
    addss   xmm9, xmm4
    movaps  xmmword ptr [rsp + 48], xmm9    # 16-byte Spill
    mulss   xmm9, xmm4
    addss   xmm2, xmm9
    movaps  xmmword ptr [rsp + 176], xmm2   # 16-byte Spill
    addss   xmm7, xmm9
    addss   xmm9, xmm4
    unpcklps    xmm7, xmm9                      # xmm7 = xmm7[0],xmm9[0],xmm7[1],xmm9[1]
    unpcklps    xmm6, xmm10                     # xmm6 = xmm6[0],xmm10[0],xmm6[1],xmm10[1]
    xorps   xmm0, xmm0
    movaps  xmm2, xmmword ptr [rsp + 32]    # 16-byte Reload
    movss   xmm0, xmm2                      # xmm0 = xmm2[0],xmm0[1,2,3]
    unpcklps    xmm14, xmm14                    # xmm14 = xmm14[0,0,1,1]
    mulps   xmm14, xmm0
    addps   xmm14, xmm6
    unpcklps    xmm1, xmm1                      # xmm1 = xmm1[0,0,1,1]
    xorps   xmm2, xmm2
    movaps  xmm9, xmmword ptr [rsp + 80]    # 16-byte Reload
    movss   xmm2, xmm9                      # xmm2 = xmm9[0],xmm2[1,2,3]
    movaps  xmmword ptr [rsp + 32], xmm2    # 16-byte Spill
    mulps   xmm1, xmm2
    addps   xmm1, xmm14
    movaps  xmm2, xmmword ptr [rsp + 96]    # 16-byte Reload
    addss   xmm13, xmm2
    addss   xmm13, xmm4
    addss   xmm3, xmm13
    mulss   xmm13, xmm4
    addss   xmm8, xmm13
    unpcklps    xmm13, xmm13                    # xmm13 = xmm13[0,0,1,1]
    addps   xmm13, xmm1
    movlps  qword ptr [rsi], xmm13
    movss   dword ptr [rsi + 8], xmm8
    movss   dword ptr [rsi + 12], xmm3
    unpcklps    xmm2, xmmword ptr [rsp + 160]   # 16-byte Folded Reload
                                        # xmm2 = xmm2[0],mem[0],xmm2[1],mem[1]
    movaps  xmm6, xmm2
    movaps  xmm2, xmmword ptr [rsp + 192]   # 16-byte Reload
    movaps  xmm3, xmmword ptr [rsp + 128]   # 16-byte Reload
    unpcklps    xmm2, xmm3                      # xmm2 = xmm2[0],xmm3[0],xmm2[1],xmm3[1]
    xorps   xmm1, xmm1
    mulps   xmm2, xmm1
    addps   xmm2, xmm6
    movaps  xmm6, xmmword ptr [rsp + 64]    # 16-byte Reload
    mulss   xmm6, xmm4
    movaps  xmm10, xmm2
    shufps  xmm10, xmm6, 4                  # xmm10 = xmm10[0,1],xmm6[0,0]
    shufps  xmm5, xmm2, 212                 # xmm5 = xmm5[0,1],xmm2[1,3]
    shufps  xmm5, xmm2, 82                  # xmm5 = xmm5[2,0],xmm2[1,1]
    xorps   xmm8, xmm8
    shufps  xmm8, xmm3, 4                   # xmm8 = xmm8[0,1],xmm3[0,0]
    addps   xmm10, xmmword ptr [rip + __xmm@00000000000000008000000080000000]
    movaps  xmm2, xmmword ptr [rsp + 112]   # 16-byte Reload
    addss   xmm2, xmm4
    addps   xmm8, xmm10
    movhlps xmm10, xmm10                    # xmm10 = xmm10[1,1]
    addss   xmm10, dword ptr [rsp + 144]    # 16-byte Folded Reload
    movaps  xmm3, xmm2
    movaps  xmm14, xmm2
    mulss   xmm3, xmm4
    addps   xmm5, xmm1
    movaps  xmm2, xmm5
    shufps  xmm2, xmm5, 85                  # xmm2 = xmm2[1,1],xmm5[1,1]
    movaps  xmm6, xmm2
    movaps  xmm13, xmm9
    mulss   xmm6, xmm9
    movaps  xmm9, xmm3
    subss   xmm9, xmm6
    unpcklps    xmm9, xmm3                      # xmm9 = xmm9[0],xmm3[0],xmm9[1],xmm3[1]
    mulps   xmm5, xmm0
    addps   xmm5, xmm9
    unpcklps    xmm12, xmm15                    # xmm12 = xmm12[0],xmm15[0],xmm12[1],xmm15[1]
    movlhps xmm5, xmm12                     # xmm5 = xmm5[0],xmm12[0]
    movq    xmm6, xmm13                     # xmm6 = xmm13[0],zero
    xorps   xmm9, xmm9
    shufps  xmm9, xmm6, 132                 # xmm9 = xmm9[0,1],xmm6[0,2]
    mulps   xmm9, xmm8
    addps   xmm9, xmm5
    movss   xmm5, dword ptr [rip + __real@80000000] # xmm5 = [-0.0E+0,0.0E+0,0.0E+0,0.0E+0]
    movaps  xmm6, xmm8
    movlhps xmm6, xmm5                      # xmm6 = xmm6[0],xmm5[0]
    shufps  xmm6, xmm5, 226                 # xmm6 = xmm6[2,0],xmm5[2,3]
    addps   xmm6, xmm9
    unpcklps    xmm3, xmm14                     # xmm3 = xmm3[0],xmm14[0],xmm3[1],xmm14[1]
    mulps   xmm2, xmm0
    addps   xmm2, xmm3
    movaps  xmm3, xmm8
    shufps  xmm3, xmm8, 85                  # xmm3 = xmm3[1,1],xmm8[1,1]
    movaps  xmm5, xmmword ptr [rsp + 32]    # 16-byte Reload
    mulps   xmm3, xmm5
    addps   xmm3, xmm2
    addss   xmm10, xmm4
    mulss   xmm4, xmm8
    unpcklps    xmm4, xmm4                      # xmm4 = xmm4[0,0,1,1]
    addps   xmm4, xmm3
    movlps  qword ptr [rsi + 16], xmm4
    movups  xmmword ptr [rsi + 24], xmm6
    shufps  xmm8, xmm10, 10                 # xmm8 = xmm8[2,2],xmm10[0,0]
    unpcklps    xmm10, xmm10                    # xmm10 = xmm10[0,0,1,1]
    mulps   xmm10, xmm0
    movaps  xmm4, xmm0
    movlhps xmm4, xmm5                      # xmm4 = xmm4[0],xmm5[0]
    mulps   xmm4, xmm8
    movaps  xmm0, xmmword ptr [rsp + 176]   # 16-byte Reload
    unpcklps    xmm0, xmmword ptr [rsp + 48]    # 16-byte Folded Reload
                                        # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
    movlhps xmm11, xmm0                     # xmm11 = xmm11[0],xmm0[0]
    addps   xmm11, xmm4
    addps   xmm11, xmm1
    movups  xmmword ptr [rsi + 40], xmm11
    addps   xmm10, xmm7
    addps   xmm10, xmmword ptr [rip + __xmm@00000000000000003f80000000000000]
    movlps  qword ptr [rsi + 56], xmm10
    movaps  xmm6, xmmword ptr [rsp + 208]   # 16-byte Reload
    movaps  xmm7, xmmword ptr [rsp + 224]   # 16-byte Reload
    movaps  xmm8, xmmword ptr [rsp + 240]   # 16-byte Reload
    movaps  xmm9, xmmword ptr [rsp + 256]   # 16-byte Reload
    movaps  xmm10, xmmword ptr [rsp + 272]  # 16-byte Reload
    movaps  xmm11, xmmword ptr [rsp + 288]  # 16-byte Reload
    movaps  xmm12, xmmword ptr [rsp + 304]  # 16-byte Reload
    movaps  xmm13, xmmword ptr [rsp + 320]  # 16-byte Reload
    movaps  xmm14, xmmword ptr [rsp + 336]  # 16-byte Reload
    movaps  xmm15, xmmword ptr [rsp + 352]  # 16-byte Reload
    .seh_startepilogue
    add rsp, 368
    pop rsi
    .seh_endepilogue
    ret
    .seh_endproc
                                        # -- End function
    .section    .debug$S,"dr"
    .p2align    2, 0x0
    .long   4                               # Debug section magic
    .long   241
    .long   .Ltmp1-.Ltmp0                   # Subsection size
.Ltmp0:
    .short  .Ltmp3-.Ltmp2                   # Record length
.Ltmp2:
    .short  4353                            # Record kind: S_OBJNAME
    .long   0                               # Signature
    .byte   0                               # Object name
    .p2align    2, 0x0
.Ltmp3:
    .short  .Ltmp5-.Ltmp4                   # Record length
.Ltmp4:
    .short  4412                            # Record kind: S_COMPILE3
    .long   0                               # Flags and language
    .short  208                             # CPUType
    .short  22                              # Frontend version
    .short  1
    .short  1
    .short  0
    .short  22011                           # Backend version
    .short  0
    .short  0
    .short  0
    .asciz  "clang version 22.1.1 (https://github.com/llvm/llvm-project fef02d48c08db859ef83f84232ed78bd9d1c323a)" # Null-terminated compiler version string
    .p2align    2, 0x0
.Ltmp5:
.Ltmp1:
    .p2align    2, 0x0
    .addrsig
    .globl  _fltused

结论:显然 clang 生成的指令明显更多,计算复杂度也更大,使用的常量也更多,而且栈用的也更大。

这也表示编译器似乎没有做到浮点数的乘零步骤的优化过程。
古法编程之:人肉编译器战胜了 gcc、clang
我虽然不能用针扎 CD、磁针扎硬盘、软盘、口算 MD5 等方式工作,但是我充当个编译器是可以的

回复

使用道具 举报

发表于 2026-5-3 15:41:14 | 显示全部楼层
浮点数算数计算优化用单独的编译参数。 无标题.png
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2026-5-3 19:32:57 | 显示全部楼层
AyalaRs 发表于 2026-5-3 15:41
浮点数算数计算优化用单独的编译参数。

确实有效。这个优化选项竟然不是默认开启的。优化后的效果和我自己手动优化的一致。

opti.png
回复 赞! 靠!

使用道具 举报

发表于 2026-5-3 19:56:45 | 显示全部楼层
0xAA55 发表于 2026-5-3 19:32
确实有效。这个优化选项竟然不是默认开启的。优化后的效果和我自己手动优化的一致。

...

浮点数优化容易损失精度,编译器默认甚至都不会改变前后指令顺序。
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2026-5-13 04:55 , Processed in 0.040285 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表