まず、RAMとROMの使用が優先されるようにマイクロコントローラ用に開発しています。GCCは初期化されていないスタティックコンストラクタの構造体コピーを最適化していません
私はこれがバグレポートとして読んでも、それほど具体的ではないことに気付いています。私がここで何の答えも得られないならば、私はそのように答えるだろう。
私はstatic const
構造体を使用して、スタック構造体をデフォルトに初期化するのが好きです。ほとんどの場合、デフォルトの構造体はすべてゼロです。私は私の現在のツールチェーンを最適化-Os
とのCortex M4のターゲット向けにコンパイル、arm-none-eabi-gcc-4_7_3
ある
static const
構造体ではなく、memset
(memset or struct assignment、static const assignment)でこれを行うことを好みます。
私は以下に気付きました。 GCCは私がstatic const
構造体をゼロに明示的に初期化すると、異なるコードを生成します(static const struct foo;
vs static const struct foo = {0};
)。特に、初期化されていないstatic const
構造体をメモリに割り当て、コピー操作を実行します。ここで
は、コードサンプルです:
struct foo {int foo; int bar;};
struct bar {int bar[20];};
static const struct foo foo1_init, foo2_init = {0};
static const struct bar bar1_init, bar2_init = {0};
extern struct foo foo1, foo2;
extern struct bar bar1, bar2;
void init_foo1(void)
{
foo1 = foo1_init;
}
void init_foo2(void)
{
foo2 = foo2_init;
}
void init_bar1(void)
{
bar1 = bar1_init;
}
void init_bar2(void)
{
bar2 = bar2_init;
}
はコンパイル、これは(再配置し、簡潔にするためにトリミング)リスト次のアセンブラを生成します。
396 .section .bss.foo1_init,"aw",%nobits
397 .align 2
398 .set .LANCHOR0,. + 0
401 foo1_init:
402 0000 00000000 .space 8
402 00000000
40 .L2:
41 0010 00000000 .word .LANCHOR0
42 0014 00000000 .word foo1
55: **** foo1 = foo1_init;
32 .loc 1 55 0
33 0000 034A ldr r2, .L2
34 0002 044B ldr r3, .L2+4
35 0004 92E80300 ldmia r2, {r0, r1}
36 0008 83E80300 stmia r3, {r0, r1}
67 .L5:
68 000c 00000000 .word foo2
60: **** foo2 = foo2_init;
60 0000 024B ldr r3, .L5
61 0002 0022 movs r2, #0
62 0004 1A60 str r2, [r3, #0]
63 0006 5A60 str r2, [r3, #4]
389 .section .bss.bar1_init,"aw",%nobits
390 .align 2
391 .set .LANCHOR1,. + 0
394 bar1_init:
395 0000 00000000 .space 80
395 00000000
395 00000000
395 00000000
395 00000000
98 .L8:
99 0010 00000000 .word .LANCHOR1
100 0014 00000000 .word bar1
65: **** bar1 = bar1_init;
89 .loc 1 65 0
90 0002 0349 ldr r1, .L8
91 0004 0348 ldr r0, .L8+4
92 0006 5022 movs r2, #80
93 0008 FFF7FEFF bl memcpy
130 .L11:
131 0010 00000000 .word bar2
70: **** bar2 = bar2_init;
121 .loc 1 70 0
122 0002 0021 movs r1, #0
123 0004 5022 movs r2, #80
124 0006 0248 ldr r0, .L11
125 0008 FFF7FEFF bl memset
我々はfoo2 = init_foo2
とbar2 = init_bar2
コンパイラのためにそれを見ることができますそのコピーを最適化してfoo2
に直接格納するか、bar2
の場合はmemset
を呼び出します。
我々はfoo1 = init_foo1
とbar1 = init_bar1
のために、コンパイラは、明示的なコピーを実行しているにロードし、foo1
用レジスタから保存しfoo2
ためmemcpy
を呼び出すことがわかります。
- が、これはGCCの操作を期待されている: は、私はいくつか質問がありますか?初期化されていない
static const
構造体が、初期化されたstatic const
構造体と同じGCC内の同じパスをたどり、同じ出力を生成することを期待しています。 - これは他のバージョンのARM GCCで発生しますか?私は手作業で他のバージョンを用意していません。
C
はアセンブラコンパイラには実際にはC++
コンパイラです。 - これはGCCの他のターゲットアーキテクチャで起こりますか?繰り返しますが、私は他のバージョンを手にすることはありません。
あなたは一貫性のために、あなたのコードを編集してもらえますか?現在、 'foo1_init'などを参照しています。これらはあなたのコードで定義されていません(代わりに' init_foo1'を定義しています)。私はあなたが同じスコープ内の変数と関数の両方として 'init_foo1'を持っているので、それは単にタイプミスであると思います。 –
'memcpy()'を呼び出すと、スペースがかなり安いので、コピーをインライン化するのにかかるコストと比較しましたか?おそらく、バイト数が十分に大きいときに呼び出しを発行するヒューリスティックがあります。 – unwind
@イアン確かにタイプミス。私はもともと何か別の名前の関数を持っていましたが、アセンブリの出力を理解するのが難しくなりました。 –