0

そもそもインラインアセンブリについてはあまり詳しくなく、blackfinプロセッサのアセンブリについてはあまり詳しくありません。私はレガシーCアプリケーションをC++に移行している最中であり、今朝、次のルーチンに関して問題が発生しました。

//
void clear_buffer ( short * buffer, int len ) {
    __asm__ (
            "/* clear_buffer */\n\t"
            "LSETUP (1f, 1f) LC0=%1;\n"
            "1:\n\t"
            "W [%0++] = %2;"
            :: "a" ( buffer ), "a" ( len ), "d" ( 0 )
            : "memory", "LC0", "LT0", "LB0"
    );
}

shortオーディオ処理に使用されるsの配列を含むクラスがあります。

class AudProc
{
    enum { buffer_size = 512 };

    short M_samples[ buffer_size * 2 ];

    // remaining part of class omitted for brevity
};

AudProcクラス内clear_bufferに、サンプル配列を渡すメソッドがあります。

clear_buffer ( M_samples, sizeof ( M_samples ) / 2 );

これにより「バスエラー」が発生し、アプリケーションが中止されます。

配列を公開しようとしましたが、同じ結果になります。また、静的にしようとしました。これにより、呼び出しはエラーなしで通過できますが、クラスの複数のインスタンスは、それぞれが独自のバッファーを使用する必要があるため、許可されなくなりました。さて、私の最初の考えは、バッファがメモリ内のどこにあるか、またはバッファがアクセスされている場所と関係があるということです。これを機能させるには、インラインアセンブリで何かを変更する必要がありますか、それとも呼び出される方法で変更する必要がありますか?

これは私が達成しようとしていたことと似ていると思いましたが、それはasmの異なる方言を使用しており、それが私が経験しているのと同じ問題であるかどうかを理解できません。

GCC拡張asm、構造体要素オフセットエンコーディング

  1. なぜこれが起こっているのか、そしてそれを修正する方法を知っている人はいますか?
  2. blackfin asm命令セットに関する役立つドキュメントがどこにあるか知っている人はいますか?ADSPサイトを調べてみましたが、役に立ちませんでした。
4

3 に答える 3

0

私はあなたがあなたを次のように定義できると思いclear_bufferます

 inline void clear_buffer (short * buffer, int len) {
   memset (buffer, 0, sizeof(short)*len);
 }

-O2そしておそらくGCCは(またはで呼び出されたときに-O3)それを巧妙に最適化することができます(GCCはについて知っているからですmemset)。

アセンブリコードを理解するにはgcc -S -O -fverbose-asm、小さなCファイルで実行してから、生成されたファイルの内部を調べることをお勧めし.sます。

于 2012-12-04T16:16:35.543 に答える
0

同様の状況に遭遇した他の人にとって、ここでの問題は、インラインアセンブリにも、それが呼び出されていた方法にもありませんでした。それは、プログラムのクラス/構造体にありました。私が犯罪者であると信じていたクラスは問題ではありませんでした-そのインスタンスを保持する別のクラスがあり、その外側のクラスの他のメンバーのために、内側のクラスは単語の境界に整列していませんでした。これは私が経験していた「バスエラー」を引き起こしていました。クラスが他のコードで宣言されていなかったため、これまでに遭遇したことはありませんでした__attribute__((packed))が、それらは私の実装に含まれています。

タイプ属性を与える-GNUコンパイラコレクション(GCC)を使用して、読み取りが実際に私にとっての答えを引き起こしたものでした。メモリアライメントに影響を与える2つの特定の属性(したがって、私が使用しているようなインラインアセンブリ)はとpackedですaligned

前述のリンクから取得:

整列(整列)

この属性は、指定されたタイプの変数の最小アライメント(バイト単位)を指定します。たとえば、宣言は次のとおりです。

          struct S { short f[3]; } __attribute__ ((aligned (8)));
          typedef int more_aligned_int __attribute__ ((aligned (8)));

struct Sタイプがmore_aligned_intである各変数が、少なくとも8バイト境界で割り当てられ、整列されるように、コンパイラーに(可能な限り)強制します。SPARCでは、型のすべての変数struct Sを8バイト境界に揃えることで、コンパイラは型の変数を別の変数にコピーするときにlddand (ダブルワードのロードおよびストア)命令を使用できるため、実行時の効率が向上します。stdstruct S

ISO C規格では、任意のstructまたはタイプのアラインメントは、または問題unionのすべてのメンバーのアラインメントの最小公倍数の少なくとも完全な倍数である必要があることに注意してください。これは、そのようなタイプのメンバーのいずれかに属性を付加することで、またはタイプの配置を効果的に調整できることを意味しますが、上記の例に示されている表記法は、コンパイラーを要求するためのより明白で直感的で読みやすい方法です。またはタイプ全体の配置を調整します。structunionstructunionalignedstructunion

struct前の例のように、コンパイラーが特定のタイプまたはタイプに使用するアライメント(バイト単位)を明示的に指定できますunion。または、アラインメントファクターを省略して、コンパイルするターゲットマシンの最大の有用なアラインメントにタイプをアラインメントするようコンパイラーに要求することもできます。たとえば、次のように書くことができます。

          struct S { short f[3]; } __attribute__ ((aligned));

アラインされた属性指定でアラインメント係数を省略すると、コンパイラーは、タイプのアラインメントを、コンパイル対象のターゲットマシン上の任意のデータ型でこれまでに使用された最大のアラインメントに自動的に設定します。これを行うと、多くの場合、コピー操作がより効率的になります。コンパイラは、この方法で整列した型を持つ変数との間でコピーを実行するときに、メモリの最大のチャンクをコピーする命令を使用できるためです。

上記の例では、それぞれのサイズshortが2バイトの場合、タイプ全体のサイズstruct Sは6バイトです。それ以上の2の最小の累乗は8であるため、コンパイラーはstruct Sタイプ全体のアラインメントを8バイトに設定します。

特定のタイプの時間効率の良いアラインメントを選択してから、そのタイプの個々のスタンドアロンオブジェクトのみを宣言するようコンパイラーに要求できますが、時間効率の高いアラインメントを選択するコンパイラーの機能は、主に次のことを計画している場合にのみ役立ちます。関連する(効率的に整列された)型を持つ変数の配列を作成します。効率的に整列された型の変数の配列を宣言または使用する場合、プログラムは、関連する型へのポインター、およびコンパイラーが行うコードに対して、ポインター演算(または同じことになる添え字)も実行する可能性があります。これらのポインタの算術演算の生成は、他の型よりも効率的に整列された型の方が効率的であることがよくあります。

aligned属性は、alignmentを増やすことしかできません。ただし、packedを指定することで減らすことができます。下記参照。

整列された属性の有効性は、リンカーに固有の制限によって制限される場合があることに注意してください。多くのシステムでは、リンカは変数を特定の最大整列まで整列させることしかできません。(一部のリンカーでは、サポートされる最大アラインメントが非常に小さい場合があります。)リンカーが変数を最大8バイトのアラインメントまでしかアラインできない場合、それでもで指定するaligned(16)__attribute__8バイトのアラインメントしか提供されません。詳細については、リンカのドキュメントを参照してください。

パック

この属性は、定義structまたはunion型定義に付加され、必要なメモリを最小限に抑えるために、構造体または共用体の各メンバー(ゼロ幅ビットフィールドを除く)が配置されることを指定します。定義に添付するenumと、最小の積分型を使用する必要があることを示します。

この属性をstructおよびuniontypesに指定することは、各構造体または共用体メンバーにpacked属性を指定することと同じです。-fshort-enums行にフラグを指定することは、すべての定義に属性を指定することと同じですpackedenum

次の例では、struct my_packed_structのメンバーは密にパックされていますが、そのsメンバーの内部レイアウトはパックされていません。そのためには、メンバーもパックstruct my_unpacked_structする必要があります。

          struct my_unpacked_struct
           {
              char c;
              int i;
           };

          struct __attribute__ ((__packed__)) my_packed_struct
            {
               char c;
               int  i;
               struct my_unpacked_struct s;
            };

この属性は、列挙型、構造体、または共用体も定義していない、、またはenumstruct定義でのみ指定できます。uniontypedef

私が経験した問題は、特にの使用によるものでしpackedた。aligned構造体とクラスに属性を追加しようとしましたが、エラーが解決しませんでした。属性を削除するだけpackedで問題は解決しました。今のところ、私はalignedそれらに属性を残し、単に単語の境界に配置されているために、上記のようにコードの効率に改善が見られるかどうかをテストしています。アプリケーションはこれらの構造体の配列を利用するため、パフォーマンスが向上する可能性がありますが、コードのプロファイリングのみが確実になります。

于 2012-12-05T15:49:47.513 に答える
0

Blackfinアセンブラがわからないので、推測してみてください。

これLC0は「ループカウンター」のように聞こえLSETUPますが、マクロ/ insnのように見えます。これは、2つのラベルの間に、特定のループカウンターを使用してループを設定します。

「%0」オペランドは明らかに書き込み先のアドレスであり、ループ内でインクリメントされていると安全に推測できます。つまり、入力オペランドと出力オペランドの両方であり、そのように説明する必要があります。したがって、次のように、「+」制約修飾子を使用して、入出力オペランドのように記述することをお勧めします。

void clear_buffer ( short * buffer, int len ) {
    __asm__ (
            "/* clear_buffer */\n\t"
            "LSETUP (1f, 1f) LC0=%1;\n"
            "1:\n\t"
            "W [%0++] = %2;"
            : "+a" ( buffer )
            : "a" ( len ), "d" ( 0 )
            : "memory", "LC0", "LT0", "LB0"
    );
}

もちろん、これは単なる仮説ですが、コードを分解して、GCCが「%0」と「%2」に同じレジスタを割り当てたかどうかを確認できます。

PS。実際には、「+ a」だけで十分であり、アーリークローバーは関係ありません。

于 2012-12-05T15:21:21.577 に答える