gcc/memo

gcc/memo

まあ適当に…

最適化レベルを -O3 以上にした場合、ループ展開が抑止できない

http://pc11.2ch.net/test/read.cgi/tech/1145357824/963-993 あたり。

963 :デフォルトの名無しさん:2007/10/09(火) 11:05:30 
gccのループ展開の抑制について質問させてください。 

コードサイズの評価をしようとして、常用している -O3 に 
ループ展開の抑制だけを加えて -O3 -fno-unroll-loops -fno-peel-loops と 
したんですが、ループ展開を止めてくれません。どうやればいいんでしょう? 

gccのバージョンは4.1.2(tarballから展開・パッチなし)、 
実行環境はi686-pc-linux-gnuとpowerpc-linuxです(どちらでも現象は同じ)。 

問題のコードを直接晒せないので、再現コードを書きます: 

 #define N 5 

 int foo(int a[]) 
 { 
  int t = 0, i; 
  for (i = 0; i < N; i++) t += a[i]; 
  return t; 
 } 

上のように定数回の小ループがあって、ループ回数が少ないと展開するようです。 
展開した場合は、ループ構造は削除され、中身が回数分反復されます。 

-O2 とすればループ展開を行わなくなります。 
でも、ループ展開以外の最適化は -O3 のままにしておきたいんです。 


968 :デフォルトの名無しさん:2007/10/09(火) 21:51:46 
>>963 
4.1.2で色々やってみたけど抑制できなかった 


969 :デフォルトの名無しさん:2007/10/09(火) 22:02:20 
そこだけソース別けて-O2でコンパイルするとか... 


970 :デフォルトの名無しさん:2007/10/09(火) 23:04:35 
>>967 
了解。今から長いコンパイルを開始します。 


971 :963:2007/10/10(水) 00:53:43 
>>968 
どもです。お手数おかけしてます。やっぱり地味に難しいんでしょうか。 

>>969 
避けてしまうのはどうにでもできるんですが、ほしいのは 
「このコードをこういう条件でコンパイルするとこういう結果になります」という 
コード評価でして。コードの一部だけ最適化条件を変えるのは 
できるだけしたくない、という事情です。 
ただ、ここで詰まっていてもしょうがないので、 
適当なところで見切りをつけますけどね。全体を-O2にしてしまうとか。 

4.1.2のmanを調べたら「-O3は-O2に-finline-functions -funswitch-loops 
-fgcse-after-reloadを足したもの」と書いてあったのですが、 
-O2にこれらを足しても-O3と等しくはなりませんでした。うーむ。 


972 :デフォルトの名無しさん:2007/10/10(水) 02:02:49 
-O3 -fno-unroll-loops でいいんでないの? 


973 :デフォルトの名無しさん:2007/10/10(水) 04:53:20 
>>971 
manは結構いいかげんなのでソースを当たるべし。 


974 :デフォルトの名無しさん:2007/10/10(水) 08:52:16 
さんざん既出だが、 
自分で細かくコントロールしたければ、 
-O3, -O2などを使ってはいけない。 


981 :デフォルトの名無しさん:2007/10/10(水) 15:35:05 
GNU製品のmanなんて宛てにしないでソースで正確なの調べろよ。 


982 :デフォルトの名無しさん:2007/10/10(水) 18:33:46 
GNU製品のmanなんて信用せずに素直にinfo見ろよな 

985 :デフォルトの名無しさん:2007/10/10(水) 20:57:03 
infoもこう書いてあるけど 
`-O3' 
Optimize yet more. `-O3' turns on all optimizations specified by 
`-O2' and also turns on the `-finline-functions', 
`-funswitch-loops' and `-fgcse-after-reload' options. 


988 :デフォルトの名無しさん:2007/10/11(木) 08:03:19 
>>975 
-O2使ったとたんに他の指定は上書きされるのが現実です。 

個別に設定しても必ずその通りになるものではないし。 
最適化技法間の制約があるので。 

暗黙に無効、有効にする時に、Warningも出しません。 
ソース読むしかないんです。 

989 :デフォルトの名無しさん:2007/10/11(木) 09:27:31 
どの最適化をするかくらいならすぐ読めるよね 

990 :963:2007/10/12(金) 00:58:21 
ソースを読みました。opts.c の decode_options() に最適化オプション読み込みの 
基本部分がありました。大雑把には次のような構造でした。 

 for (i = 1; i < argc; i++) 
  { /* すべての-Oxオプションを通し読み */ } 
 if (optimize >= 1) 
  { flag_hoge = 1; ... } /* -O1以上でのフラグ設定を適用 */ 
 if (optimize >= 2) 
  { flag_geho = 1; ... } /* -O2以上でのフラグ設定を適用 */ 
 ... 
 handle_options(argc, argv, ...); /* 各オプションを処理 */ 

optimize >= 3 では、flag_inline_functions と flag_unswitch_loops と 
flag_gcse_after_reload を 1 にしていました。 
その箇所だけ読むとmanやinfoの記述は正しいことになるんですが、はて。 
結局追いきれませんでした。 

それから、>>988の通り、フラグ変数を書き換えてもその情報をどこにも伝えません。 
ちょっと不便なような。。。 

で、別解なんですが、「-O3 --param max-completely-peeled-insns=0」 
と指定してpeelingを止めてしまえば目的を果たせることがわかりました。 
この指定で行こうと思います。 



991 :デフォルトの名無しさん:2007/10/12(金) 01:22:28 
いや、該当するフラグ変数を全ソースで検索しないと。 
コンパイル中にフラグの値変ることもあるし。 


992 :デフォルトの名無しさん:2007/10/12(金) 02:23:32 
>>991 
ヒントありがとうございます。flag_unroll_loops と flag_peel_loops に 
当たりをつけて探してみました。これだろうな、ってのが出てきました。 

tree-ssa-loop.c: 
static void 
tree_complete_unroll (void) 
{ 
 if (!current_loops) 
  return; 

 tree_unroll_loops_completely (current_loops, 
                flag_unroll_loops 
                || flag_peel_loops 
                || optimize >= 3); 
} 

"optimize" でも軽く眺めてみましたが、フラグではなく最適化レベルの数値を 
最適化の適用条件にしている箇所はそれなりに珍しいようです。 

993 :デフォルトの名無しさん:2007/10/12(金) 08:47:02 
> optimize >= 3 

ワラ 
イヤだねー 

994 :デフォルトの名無しさん:2007/10/12(金) 09:03:27 
将来を見据えた設計なのでは? 

995 :デフォルトの名無しさん:2007/10/12(金) 12:37:26 
>>994 
断言できる。何も考えてないだけ。