タグ付けされた質問 「compiler-optimization」

コンパイラーの最適化には、ランタイムまたはオブジェクトのサイズ、あるいはその両方を削減するようにコンパイラーを調整することが含まれます。これは、コンパイラー引数(CFLAGS、LDFLAGSなど)、コンパイラープラグイン(DEHYDRAなど)、またはコンパイラーへの直接変更(ソースコードの変更など)を使用して実行できます。

13
最適化されない無限の空のループを作成するにはどうすればよいですか?
C11標準は、定数制御式を含む反復ステートメントを最適化してはならないことを示唆しているようです。私はこの回答から私のアドバイスを取り入れています。これは、ドラフト標準のセクション6.8.5を具体的に引用しています。 制御式が定数式ではない反復文...は、実装によって終了するものと想定されます。 その答えでは、ループのようなループwhile(1) ;は最適化の対象とすべきではないと述べています。 では、なぜClang / LLVMは(でコンパイルされたcc -O2 -std=c11 test.c -o test)以下のループを最適化するのですか? #include <stdio.h> static void die() { while(1) ; } int main() { printf("begin\n"); die(); printf("unreachable\n"); } 私のマシンでは、これはを出力しbegin、次に不正な命令(のud2後にトラップが配置されたdie())でクラッシュします。godboltでは、の呼び出し後に何も生成されないことがわかりputsます。 Clangに無限ループを出力させるのは意外と難しい作業でし-O2たが、volatile変数を繰り返しテストすることはできましたが、これには不要なメモリ読み取りが含まれています。そして、私がこのようなことをした場合: #include <stdio.h> static void die() { while(1) ; } int main() { printf("begin\n"); volatile int x = 1; if(x) die(); …

3
このポインタを使用すると、ホットループで奇妙な最適化が解除されます
最近、奇妙な最適化解除に遭遇しました(または最適化の機会を逃しました)。 3ビット整数の配列を8ビット整数に効率的にアンパックするには、この関数を検討してください。ループの繰り返しごとに16の整数をアンパックします。 void unpack3bit(uint8_t* target, char* source, int size) { while(size > 0){ uint64_t t = *reinterpret_cast<uint64_t*>(source); target[0] = t & 0x7; target[1] = (t >> 3) & 0x7; target[2] = (t >> 6) & 0x7; target[3] = (t >> 9) & 0x7; target[4] = (t >> 12) & 0x7; …

11
関数の早期復帰の効率
これは、経験の浅いプログラマーとして頻繁に遭遇する状況であり、特に最適化しようとしている私の野心的でスピード重視のプロジェクトについて疑問に思っています。主要なCのような言語(C、objC、C ++、Java、C#など)と通常のコンパイラーの場合、これら2つの関数は同じくらい効率的に実行されますか?コンパイルされたコードに違いはありますか? void foo1(bool flag) { if (flag) { //Do stuff return; } //Do different stuff } void foo2(bool flag) { if (flag) { //Do stuff } else { //Do different stuff } } 基本的に、breakINGまたはreturnINGを早くするときに、直接的な効率のボーナス/ペナルティはありますか?スタックフレームはどのように関係していますか?最適化された特別なケースはありますか?これに大きな影響を与える可能性のある要因(インライン化や "Do stuff"のサイズなど)はありますか? 私は常に、マイナーな最適化よりも読みやすさを改善することを支持しています(パラメーターの検証でfoo1がよく見られます)。 そして、私は時期尚早の最適化の落とし穴を知っています...うーん、それらはいくつかのつらい思い出です。 編集:私は答えを受け入れましたが、EJPの答えはaの使用returnが実質的に無視できる理由をかなり簡潔に説明しています(アセンブリでreturnは、関数の終わりに「ブランチ」を作成しますが、これは非常に高速です。ブランチはPCレジスタを変更し、両方のためにも、キャッシュとパイプライン、かなり微小である。)特にこの場合のためにに影響を与える可能性があり、それは文字通り違いはありませんif/elseし、return関数の最後に同じブランチを作成します。

3
Clang最適化レベル
gccのでは、マニュアルには何を説明し-O3、-Os具体的な最適化の引数(の用語で翻訳など、-funswitch-loops、-fcompare-elim、など) clangについて同じ情報を探しています。 私が見てきた、オンラインとでman clangどののみ(一般的な情報提供します-O2以上に最適化し-O1、-Os速度を最適化し、...)ともスタックオーバーフローの上に、ここで見て、見つけ、これを、私は引用したソースファイル内の関連する何かを発見していません。 編集:答えを見つけましたが、すべての最適化パスとによって選択されたパスを文書化したユーザーマニュアルへのリンクがある場合は、まだ興味があります。現在、私はこのパスのリストを見つけましたが、最適化レベルについては何もありません。-Ox


3
コードが末尾呼び出しの最適化を積極的に防止しようとするのはなぜですか?
質問のタイトルは少し奇妙かもしれませんが、私が知る限り、末尾呼び出しの最適化に反対するものは何もありません。しかし、オープンソースプロジェクトを閲覧しているときに、コンパイラが末尾呼び出しの最適化を実行するのを積極的に阻止しようとするいくつかの関数にすでに遭遇しました。たとえば、そのようなハックでいっぱいのCFRunLoopRefの実装です。例えば: static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline)); static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { if (func) { func(observer, activity, info); } getpid(); // thwart tail-call optimization } なぜこれがそれほど重要に見えるのか知りたいのですが、通常の開発者として私もこれを念頭に置いておく必要がある場合はありますか?例えば。末尾呼び出しの最適化に関する一般的な落とし穴はありますか?

2
スイッチがチェーン化されているのと同じように最適化されていないのはなぜですか?
次のsquareの実装は、連鎖ifステートメントに期待するような一連のcmp / jeステートメントを生成します。 int square(int num) { if (num == 0){ return 0; } else if (num == 1){ return 1; } else if (num == 2){ return 4; } else if (num == 3){ return 9; } else if (num == 4){ return 16; } else if (num == …

2
%演算子よりも速い分割可能性テスト?
コンピューターに不思議なことに気づきました。*手書きの分割可能性テストは、%オペレーターよりも大幅に高速です。最小限の例を考えてみましょう: * AMD Ryzen Threadripper 2990WX、GCC 9.2.0 static int divisible_ui_p(unsigned int m, unsigned int a) { if (m <= a) { if (m == a) { return 1; } return 0; } m += a; m >>= __builtin_ctz(m); return divisible_ui_p(m, a); } 例は奇数aとによって制限されm > 0ます。ただし、すべてのaおよびに簡単に一般化できますm。コードは除算を一連の追加に変換するだけです。 でコンパイルされたテストプログラムを考えてみましょう-std=c99 -march=native -O3: for (unsigned …

1
なぜGCCは配列の初期化を集約して、最初にゼロ以外の要素を含めて全体をゼロで埋めるのですか?
なぜgccは残りの96個の整数だけではなく、配列全体をゼロで埋めるのですか?ゼロ以外の初期化子はすべて配列の先頭にあります。 void *sink; void bar() { int a[100]{1,2,3,4}; sink = a; // a escapes the function asm("":::"memory"); // and compiler memory barrier // forces the compiler to materialize a[] in memory instead of optimizing away } MinGW8.1とgcc9.2はどちらもこのようにasmを作成します(Godboltコンパイラエクスプローラー)。 # gcc9.2 -O3 -m32 -mno-sse bar(): push edi # save call-preserved EDI which …

2
Java 8:Class.getName()が文字列連結チェーンを遅くする
最近、文字列の連結に関する問題に遭遇しました。このベンチマークはそれを要約します: @OutputTimeUnit(TimeUnit.NANOSECONDS) public class BrokenConcatenationBenchmark { @Benchmark public String slow(Data data) { final Class<? extends Data> clazz = data.clazz; return "class " + clazz.getName(); } @Benchmark public String fast(Data data) { final Class<? extends Data> clazz = data.clazz; final String clazzName = clazz.getName(); return "class " + clazzName; } @State(Scope.Thread) …

2
コンパイラーは未使用の静的なthread_localクラスメンバーを無視しましたか?
クラスでスレッド登録をしたいので、thread_local機能のチェックを追加することにします。 #include <iostream> #include <thread> class Foo { public: Foo() { std::cout << "Foo()" << std::endl; } ~Foo() { std::cout << "~Foo()" << std::endl; } }; class Bar { public: Bar() { std::cout << "Bar()" << std::endl; //foo; } ~Bar() { std::cout << "~Bar()" << std::endl; } private: static thread_local …

1
C ++でのif / elseブランチのコンパイル時の削除
次のコードサンプルでは、ifステートメントはboolコンパイル時定数であるテンプレートパラメーターに依存しています。コンパイラはこのコードを別の方法で処理します。 MSVCはリンクエラーで失敗します(これは私が予想したことです)。elseブランチのテンプレート関数にはtrueテンプレートパラメーター値の特殊化がないため(呼び出されることはありません)。 GCCとClangはどちらも問題なくコンパイルされ、実行時の動作は正しいです。これはif、コンパイル時にステートメントを評価し、リンクする前に未使用のブランチを削除するためです。 問題は、どの動作が標準に準拠しているか(または、未定義の動作であり、どちらも独自の方法で正しいか)です。 #include <iostream> template<const bool condition> struct Struct { void print() { if (condition) { std::cout << "True\n"; } else { printIfFalse(); } } private: void printIfFalse(); }; template <> void Struct<false>::printIfFalse() { std::cout << "False\n"; } int main() { Struct<true> withTrue{}; withTrue.print(); Struct<false> withFalse{}; withFalse.print(); return …

1
コンパイル時に解決されない文字列リテラルとの比較
私は最近、次のようなものを見つけました。 #include <string> // test if the extension is either .bar or .foo bool test_extension(const std::string& ext) { return ext == ".bar" || ".foo"; // it obviously should be // return ext == ".bar" || ext == ".foo"; } 関数は明らかにコメントが示唆することを行いません。しかし、それはここでのポイントではありません。これはifステートメントで2つ以上のOR条件を使用できますか?あなたが関数を適切に書く方法を私は完全に知っているので! コンパイラがこのスニペットをどのように処理するのか疑問に思い始めました。私の最初の直感は、これがreturn true;基本的にコンパイルされるということでした。この例をgodboltに接続すると、GCC 9.2もclang 9も最適化でこの最適化を行わないことがわかりました-O2。 ただし、コードを1に変更する #include <string> using namespace std::string_literals; …
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.