【图形学】不使用矩阵乘法实现生成四阶欧拉角旋转矩阵
# 不使用矩阵乘法实现生成四阶欧拉角旋转矩阵## 欧拉角旋转矩阵
欧拉角旋转矩阵在图形学有很多的作用,配合平移矩阵,可以通过平移坐标 + 旋转,对一个需要渲染的物件的空间姿态进行控制。当给这个物件的所有顶点都经过矩阵变换后,就可以得到它在屏幕上的显示坐标。
欧拉角旋转矩阵是通过将单位矩阵先进行按 Z 轴的滚动旋转,然后再按 X 轴进行俯仰旋转,最后按 Y 轴进行朝向旋转。这样一来,就需要按 X、Y、Z 三个轴都旋转一下,需要生成三个矩阵,用矩阵乘法合并三个矩阵得到一个矩阵,让每个顶点都按这个矩阵进行旋转;或者不把三个矩阵合并,但是每个顶点需要分别乘以滚动、俯仰、朝向矩阵,才能变换到指定旋转后的位置。因此需要优化欧拉角旋转矩阵的生成方式,一次性生成一整个矩阵。
## 示例代码(未优化版:生成三个轴的旋转矩阵,再合并矩阵。)
```C
#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 进行逆向,看看它能不能帮我完成代数运算的项合并。如图所示,直接生啃 FPU 的指令实在是令人头大。不如按 F5,对生成的 C 代码进行一些标注,应该能得到更清晰的计算过程。### 目前的问题
可以看到它有非常多的局部变量,并且对这些变量进行赋值时,会有很多的乘零、加零的操作。 **恕我直言,这 gcc10 是有点逊啦!**### 对反编译的变量名进行标记
标记规则:
* 朝向角(yaw)的 cos 值名为 `cy`,yaw 的 sin 值为 `sy`;以此类推的话,俯仰角(pitch)的 cos 值名为 `cp`,sin 值为 `sp`;滚动角(roll)的 cos 和 sin 值分别为 `cr`、`sr`。
* 如果是负值,则添加 `n` 前缀(negative),比如负的 `cy` 起名为 `ncy`,以此类推。
* 乘到一起的项,则将名字合并。比如 `cp * sr` 得到的值存入的变量名为 `cpsr`
* 如果遇到不同的变量但是具有相同的值,则给这个变量名字后面加下划线,比如重复的 `cpsr` 变量,取名为 `cpsr_`,`cpsr__` 等,以此类推。
* 值为零的变量取名为 `zr`,并且根据变量的数量,后面加上十进制的数值后缀,比如 `zr0`、`zr1`,以此类推。
标记后的代码:
```C
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; //
float cy; //
float sp; //
float zr14; //
float cr; //
float zr17; //
float sy; //
float nsy; //
float sr_; //
float cr_; //
float cp; //
float spsr; //
float zr7; //
float zr21; //
float zr13; //
float cpsr; //
float cp____; //
float nsr; //
float crcp; //
float zr10; //
float zr23; //
float zr24; //
float zr25; //
float zr26; //
float zr27; //
float zr28; //
float zr22; //
float zr20; //
float crsp__; //
float zr29; //
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 = cy * cr_ + zr14 + zr15 + 0.0;
out = cy * cpsr_ + zr19 + nsy * nsp_ + zr16;
out = cy * spsr + zr17 + nsy * cp____ + zr21;
out = zr15 + zr7 * cy + zr22 + 0.0;
out = nsr + zr23 + 0.0;
out = crcp + zr24 + zr25 + zr16;
out = crsp__ + zr26 + zr27 + zr21;
out = zr10 + zr28 + 0.0;
out = cr_ * sy + zr14 + zr29 + 0.0;
out = zr16 + cpsr_ * sy + zr19 + nsp_ * cy;
out = spsr * sy + zr17 + cy * cp____ + zr21;
out = zr29 + sy * zr7 + zr22 + 0.0;
out = zr23 + zr14 + 0.0;
out = zr19 + zr24 + zr25 + zr13;
out = zr26 + zr17 + zr27 + zr20;
out = zr22 + zr28 + 0.0 + 1.0;
}
```
可以看到,有大量的变量值为零,并且有非常多的重复的值的变量。
### 剔除无用变量,手动简化代码
```C
#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
%define _SY
%define _CP
%define _SP
%define _CR
%define _SR
%define _CPSR
%define _SPSR
%define _OUT
%define _YAW
%define _PITCH
%define _ROLL
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,
movaps , xmm0
movaps , xmm0
movaps , xmm0
movaps , 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 , xmm3
movss , xmm4
movss , xmm6
movss , xmm2
movss xmm0,
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 , xmm0
movss , xmm1
movss , xmm2
movss , xmm3
movss , xmm5
mov dword, 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 , xmm15# 16-byte Spill
.seh_savexmm xmm15, 352
movaps xmmword ptr , xmm14# 16-byte Spill
.seh_savexmm xmm14, 336
movaps xmmword ptr , xmm13# 16-byte Spill
.seh_savexmm xmm13, 320
movaps xmmword ptr , xmm12# 16-byte Spill
.seh_savexmm xmm12, 304
movaps xmmword ptr , xmm11# 16-byte Spill
.seh_savexmm xmm11, 288
movaps xmmword ptr , xmm10# 16-byte Spill
.seh_savexmm xmm10, 272
movaps xmmword ptr , xmm9 # 16-byte Spill
.seh_savexmm xmm9, 256
movaps xmmword ptr , xmm8 # 16-byte Spill
.seh_savexmm xmm8, 240
movaps xmmword ptr , xmm7 # 16-byte Spill
.seh_savexmm xmm7, 224
movaps xmmword ptr , 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 # xmm0 = [-0.0E+0,-0.0E+0,-0.0E+0,-0.0E+0]
xorps xmm0, xmm9
movaps xmmword ptr , 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 , xmm0 # 16-byte Spill
xorps xmm6, xmm6
cvtss2sd xmm6, xmm7
movaps xmm0, xmm6
call cos
cvtsd2ss xmm0, xmm0
movaps xmmword ptr , 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 # xmm11 = [-0.0E+0,0.0E+0,0.0E+0,0.0E+0]
movaps xmm1, xmm9
movaps xmm5, xmm12
movaps xmmword ptr , xmm12 # 16-byte Spill
subss xmm5, xmm9
movaps xmm15, xmm6
mulss xmm15, xmm8
movaps xmmword ptr , xmm8 # 16-byte Spill
mulss xmm9, xmm11
addss xmm15, xmm9
movaps xmm3, xmmword ptr # 16-byte Reload
mulss xmm6, xmm3
addss xmm6, xmm9
movaps xmmword ptr , 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 , 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 , xmm12# 16-byte Spill
addss xmm1, xmm4
movaps xmm8, xmm1
movaps xmm2, xmmword ptr # 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 , xmm15# 16-byte Spill
movaps xmm15, xmm12
addss xmm15, xmm4
addss xmm9, xmm15
movaps xmmword ptr , 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 # 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,xmm9,xmm11,xmm9
movaps xmm9, xmmword ptr # 16-byte Reload
addss xmm9, xmm4
movaps xmmword ptr , xmm9 # 16-byte Spill
mulss xmm9, xmm4
addss xmm2, xmm9
movaps xmmword ptr , xmm2 # 16-byte Spill
addss xmm7, xmm9
addss xmm9, xmm4
unpcklps xmm7, xmm9 # xmm7 = xmm7,xmm9,xmm7,xmm9
unpcklps xmm6, xmm10 # xmm6 = xmm6,xmm10,xmm6,xmm10
xorps xmm0, xmm0
movaps xmm2, xmmword ptr # 16-byte Reload
movss xmm0, xmm2 # xmm0 = xmm2,xmm0
unpcklps xmm14, xmm14 # xmm14 = xmm14
mulps xmm14, xmm0
addps xmm14, xmm6
unpcklps xmm1, xmm1 # xmm1 = xmm1
xorps xmm2, xmm2
movaps xmm9, xmmword ptr # 16-byte Reload
movss xmm2, xmm9 # xmm2 = xmm9,xmm2
movaps xmmword ptr , xmm2 # 16-byte Spill
mulps xmm1, xmm2
addps xmm1, xmm14
movaps xmm2, xmmword ptr # 16-byte Reload
addss xmm13, xmm2
addss xmm13, xmm4
addss xmm3, xmm13
mulss xmm13, xmm4
addss xmm8, xmm13
unpcklps xmm13, xmm13 # xmm13 = xmm13
addps xmm13, xmm1
movlps qword ptr , xmm13
movss dword ptr , xmm8
movss dword ptr , xmm3
unpcklps xmm2, xmmword ptr # 16-byte Folded Reload
# xmm2 = xmm2,mem,xmm2,mem
movaps xmm6, xmm2
movaps xmm2, xmmword ptr # 16-byte Reload
movaps xmm3, xmmword ptr # 16-byte Reload
unpcklps xmm2, xmm3 # xmm2 = xmm2,xmm3,xmm2,xmm3
xorps xmm1, xmm1
mulps xmm2, xmm1
addps xmm2, xmm6
movaps xmm6, xmmword ptr # 16-byte Reload
mulss xmm6, xmm4
movaps xmm10, xmm2
shufps xmm10, xmm6, 4 # xmm10 = xmm10,xmm6
shufps xmm5, xmm2, 212 # xmm5 = xmm5,xmm2
shufps xmm5, xmm2, 82 # xmm5 = xmm5,xmm2
xorps xmm8, xmm8
shufps xmm8, xmm3, 4 # xmm8 = xmm8,xmm3
addps xmm10, xmmword ptr
movaps xmm2, xmmword ptr # 16-byte Reload
addss xmm2, xmm4
addps xmm8, xmm10
movhlps xmm10, xmm10 # xmm10 = xmm10
addss xmm10, dword ptr # 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,xmm5
movaps xmm6, xmm2
movaps xmm13, xmm9
mulss xmm6, xmm9
movaps xmm9, xmm3
subss xmm9, xmm6
unpcklps xmm9, xmm3 # xmm9 = xmm9,xmm3,xmm9,xmm3
mulps xmm5, xmm0
addps xmm5, xmm9
unpcklps xmm12, xmm15 # xmm12 = xmm12,xmm15,xmm12,xmm15
movlhps xmm5, xmm12 # xmm5 = xmm5,xmm12
movq xmm6, xmm13 # xmm6 = xmm13,zero
xorps xmm9, xmm9
shufps xmm9, xmm6, 132 # xmm9 = xmm9,xmm6
mulps xmm9, xmm8
addps xmm9, xmm5
movss xmm5, dword ptr # xmm5 = [-0.0E+0,0.0E+0,0.0E+0,0.0E+0]
movaps xmm6, xmm8
movlhps xmm6, xmm5 # xmm6 = xmm6,xmm5
shufps xmm6, xmm5, 226 # xmm6 = xmm6,xmm5
addps xmm6, xmm9
unpcklps xmm3, xmm14 # xmm3 = xmm3,xmm14,xmm3,xmm14
mulps xmm2, xmm0
addps xmm2, xmm3
movaps xmm3, xmm8
shufps xmm3, xmm8, 85 # xmm3 = xmm3,xmm8
movaps xmm5, xmmword ptr # 16-byte Reload
mulps xmm3, xmm5
addps xmm3, xmm2
addss xmm10, xmm4
mulss xmm4, xmm8
unpcklps xmm4, xmm4 # xmm4 = xmm4
addps xmm4, xmm3
movlps qword ptr , xmm4
movups xmmword ptr , xmm6
shufps xmm8, xmm10, 10 # xmm8 = xmm8,xmm10
unpcklps xmm10, xmm10 # xmm10 = xmm10
mulps xmm10, xmm0
movaps xmm4, xmm0
movlhps xmm4, xmm5 # xmm4 = xmm4,xmm5
mulps xmm4, xmm8
movaps xmm0, xmmword ptr # 16-byte Reload
unpcklps xmm0, xmmword ptr # 16-byte Folded Reload
# xmm0 = xmm0,mem,xmm0,mem
movlhps xmm11, xmm0 # xmm11 = xmm11,xmm0
addps xmm11, xmm4
addps xmm11, xmm1
movups xmmword ptr , xmm11
addps xmm10, xmm7
addps xmm10, xmmword ptr
movlps qword ptr , xmm10
movaps xmm6, xmmword ptr # 16-byte Reload
movaps xmm7, xmmword ptr # 16-byte Reload
movaps xmm8, xmmword ptr # 16-byte Reload
movaps xmm9, xmmword ptr # 16-byte Reload
movaps xmm10, xmmword ptr # 16-byte Reload
movaps xmm11, xmmword ptr # 16-byte Reload
movaps xmm12, xmmword ptr # 16-byte Reload
movaps xmm13, xmmword ptr # 16-byte Reload
movaps xmm14, xmmword ptr # 16-byte Reload
movaps xmm15, xmmword ptr # 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 等方式工作,但是我充当个编译器是可以的 浮点数算数计算优化用单独的编译参数。 AyalaRs 发表于 2026-5-3 15:41
浮点数算数计算优化用单独的编译参数。
确实有效。这个优化选项竟然不是默认开启的。优化后的效果和我自己手动优化的一致。
0xAA55 发表于 2026-5-3 19:32
确实有效。这个优化选项竟然不是默认开启的。优化后的效果和我自己手动优化的一致。
...
浮点数优化容易损失精度,编译器默认甚至都不会改变前后指令顺序。 AyalaRs 发表于 2026-5-3 19:56
浮点数优化容易损失精度,编译器默认甚至都不会改变前后指令顺序。
看需求嘛,对于像游戏这种以速度为主的实时渲染来说,不在乎那点精度。
页:
[1]