私のコンパイラ (OS X の clang++ v2.9 ) の場合、これと似ているが同一ではないコードをコンパイルします。
void foo();
void bar();
template<int N>
void do_something( int arg ) {
if ( N<0 && arg<0 ) { foo(); }
else { bar(); }
}
// Some functions to instantiate the templates.
void one_fn(int arg) {
do_something<1>(arg);
}
void neg_one_fn(int arg) {
do_something<-1>(arg);
}
これにより、次のアセンブリが生成されますclang++ -S -O3
。
one_fn = do_something<1>
最初の関数アセンブリには、明らかに への呼び出ししかありませんbar
。
.globl __Z6one_fni
.align 4, 0x90
__Z6one_fni: ## @_Z6one_fni
Leh_func_begin0:
pushl %ebp
movl %esp, %ebp
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end0:
neg_one_fn = do_something<-1>
bar
2 番目の関数は、 または のいずれかを呼び出す単純な if に縮小されましたfoo
。
.globl __Z10neg_one_fni
.align 4, 0x90
__Z10neg_one_fni: ## @_Z10neg_one_fni
Leh_func_begin1:
pushl %ebp
movl %esp, %ebp
cmpl $0, 8(%ebp)
jns LBB1_2 ## %if.else.i
popl %ebp
jmp __Z3foov ## TAILCALL
LBB1_2: ## %if.else.i
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end1:
概要
したがって、コンパイラがテンプレートをインライン化し、可能であればブランチを最適化したことがわかります。したがって、あなたが望んでいる種類の変換は、現在のコンパイラで発生します。古い g++ 4.0.1 コンパイラからも同様の結果が得られました (ただし、アセンブリはあまり明確ではありません)。
補遺:
この例は最初のケースと十分に似ていないと判断したので(三項演算子が含まれていないため)、次のように変更しました:(同じ種類の結果を得る)
template<int X>
void do_something_else( int _ncx ) {
static const int _cx = (X<0) ? (-X) : (X);
if ( (X < 0) ? (_cx > 5) : (_ncx > 5)) {
foo();
} else {
bar();
}
}
void a(int arg) {
do_something_else<1>(arg);
}
void b(int arg) {
do_something_else<-1>(arg);
}
これにより、アセンブリが生成されます
a() = do_something_else<1>
これにはまだブランチが含まれています。
__Z1ai: ## @_Z1ai
Leh_func_begin2:
pushl %ebp
movl %esp, %ebp
cmpl $6, 8(%ebp)
jl LBB2_2 ## %if.then.i
popl %ebp
jmp __Z3foov ## TAILCALL
LBB2_2: ## %if.else.i
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end2:
b() = do_something_else<-1>
ブランチは最適化されています。
__Z1bi: ## @_Z1bi
Leh_func_begin3:
pushl %ebp
movl %esp, %ebp
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end3: