我有2个小型本地数组:
short int xpLeft [4], xpRight [4];
我将它们设置为全局(以不同的方式访问它们,但只能在同一个C文件中访问它们(例如,其他模块无法访问)),性能(在Motorola 68000上)下降。 而不是224个vblanks(对于本地),整个基准测试(呈现一个场景的320帧)突然需要249个vblanks(全局数组)!
我尝试了什么:
由于数组中的数据没有在该函数中使用,我虽然编译器捕获了这一点并且没有费心将结果值(从寄存器)写入内存(68000上的极慢操作 - 访问内存)。因此,我添加了一些小代码,以便在函数末尾使用这些数组值,并相应地提高了性能成本(仅1 vblank)。
有什么帮助:
我需要检查最终的ASM代码(并比较两个版本),但我不知道如何使用 vbcc编译器(来自Volker博士)。我从文档中尝试了几个开关,虽然它们确实产生了一些中间输出,但是我无法提供它来提供每个模块的完整ASM列表(具有来自C的函数名称)。
我刚接到开关“-k”才能工作。显然,交换机的顺序很重要,我在命令行中找到了一个可以识别它的地方,我终于得到了* .ASM输出(不超过300多行),但我终于有了一些东西(带符号的ASM)挖掘。
我认为发生了什么:
有关为什么会发生这种情况的提示,或者如何使用相应的ASM代码获取每个已编译模块的vbcc输出完整列表?
使用ASM输出我创建了一个小测试repro案例:
short int tmpfn1 ()
{
short int xpLeft [4], xpRight [4];
short int i, tmp;
for (i = 0; i < 4; i++)
{
xpLeft [i] = 137 + i;
xpRight [i] = 215 + i;
}
tmp = xpLeft [0] + xpRight [0];
return tmp;
}
这是最终的ASM。尽管ASM非常明显,但我还是添加了一些评论:
public _tmpfn1
cnop 0,4
_tmpfn1
sub.w #16,a7
movem.l l4150,-(a7)
moveq #0,d1
lea (0+l4152,a7),a1 ; a1 = &xpLeft [0]
lea (8+l4152,a7),a2 ; a2 = &xpRight [0]
move.w #215,d3 ; d2/d3 = The Bulgarian constants
move.w #137,d2
l4148
move.w d1,d0
ext.l d0
lsl.l #1,d0
move.w d2,(0,a1,d0.l) ; xpLeft [i] = 137 + i;
move.w d3,(0,a2,d0.l) ; xpRight [i] = 215 + i;
addq.w #1,d1 ; d1 = Loop Counter (i++)
addq.w #1,d2
addq.w #1,d3
cmp.w #4,d1
blt l4148 ; Repeat the loop
move.w (8+l4152,a7),d0
add.w (0+l4152,a7),d0 ; tmp = xpLeft [0] + xpRight [0];
l4150 reg a2/d2/d3
movem.l (a7)+,a2/d2/d3
add.w #16,a7
l4152 equ 12
rts
; stacksize=28
opt 0
opt NQLPSMRBT
现在,我将把数组从本地转移到全局。
以下是包含全局变量的代码。
public _tmpfn1
cnop 0,4
_tmpfn1
movem.l l4150,-(a7)
moveq #0,d1
move.w #215,d2
move.w #137,d3
l4148
move.w d1,d0
ext.l d0
lsl.l #1,d0
lea _AxpLeft,a0
move.w d3,(0,a0,d0.l)
lea _AxpRight,a0
move.w d2,(0,a0,d0.l)
addq.w #1,d1
addq.w #1,d3
addq.w #1,d2
cmp.w #4,d1
blt l4148
move.w _AxpRight,d0
add.w _AxpLeft,d0
l4150 reg d2/d3
movem.l (a7)+,d2/d3
l4152 equ 8
rts
; stacksize=8
opt 0
opt NQLPSMRBT
唯一的区别是两个lea指令,如果记忆正确,则最多16个周期 实际函数必定会发生其他事情,但由于某种原因,其代码在ASM中被混淆(ASM中只有6行,没有跳转,没有其他标签,没有)。我将继续搜索ASM,确切地说是代码。
答案 0 :(得分:0)
我怀疑,有一个与WTF编译器有关的怪物。原因是,为什么在局部变量的情况下只有6行代码,是编译器能够弄清楚,那120行C代码在全局级别上并没有真正做任何事情,所以它完全忽略了代码干脆!这意味着该方法的ASM代码只有6行(带rts)。然而,我得到的基准测试结果并没有多大意义(但这将是一个不同的故事)
故事的道德:通过使变量成为全局变量,编译器实际上打算为函数创建代码(而不仅仅是空的6-op存根)。因为我在该函数内部编写了所有内容,所以没有嵌套函数调用。 现在,这显然是荒谬的,因为我在目标设备上有大约25个调试会话,其中包含变量和输出。但是那一刻,我删除了那些外部打印/调试调用,这一定是编译器根本没有生成功能代码的时刻。 A-血性-MAZING ....