2013-05-05 11 views
5

Objective-Cプログラムの変数に対してRORおよびROL演算を実行したいとします。しかし、私はそれを管理することはできません - 私はアセンブリの専門家ではありません。ここでObjective-Cのインラインアセンブリを使用した変数のROL/ROR

は、私がこれまで行っているものです:私が得る

uint8_t v1 = ....; 
uint8_t v2 = ....; // v2 is either 1, 2, 3, 4 or 5 

asm("ROR v1, v2"); 

エラーは次のとおりです。

未知のサイズの接尾辞

どのようにすることができますと命令ニーモニックの未知の使用これを修正しますか?

編集:コードはインラインアセンブリを使用する必要はありません。しかし、Objective-C/C++/C命令を使用してこれを行う方法が見つかりませんでした。標準のCでこれを行うには

+2

本当に組み立てが必要ですか?これがパフォーマンスのボトルネックである場合にのみ必要です。通常の使用では、 'var =(var << shift)| (var >>(sizeof(var)* 8-shift)) 'となります。 – Dave

+2

詳細については、http://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts – Dave

+0

nice。ご返信ありがとうございます。これが質問に答えるので、あなたが答えを出すなら、私はそれを受け入れます。 –

答えて

2

、あなたが行うことができます:

var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift)) 

ほとんどのコンパイラは、とにかく(ターゲットがそれをサポートしている場合)、そのパターンを認識し、単一の命令にそれを最適化します。

あなたはもっとここで読むことができます:http://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts

+1

'++ posting ++';特にこのタイプのコードをhardware-rotateに変換することに関して 'gcc' /' clang'によって適用された最適化を引用しているウィキペディアの記事の_references_に注目してください。 Objective C/C++は常に 'gcc' /' clang'を意味するので、最適化が適用されていると仮定するのは安全です。さらに、ARMの場合、バレルシフタは任意の算術演算にローテーションを「統合」できるため、_separateとして回転をコーディングするのではなく、_分かりやすくなりました。 'var = rotate(var、xxx)+ 1'はARMでは_single命令_ですが、_not_ splitが関数呼び出し/インラインasmとして検出される場合にのみ検出されます。 –

+0

ありがとうございます。それが最も役に立ちます。インラインアセンブリを使用してそれを行う方法を知っていますか?私は、コードがどのように見えるのか、そのアセンブリコード内のローカル変数を参照する方法を知りたいと思っています。 –

+0

アセンブリでコード化する方法は、ターゲットアーキテクチャによって異なります。アセンブリを自分で書くことはできませんが、エラーメッセージの表示によって、32ビットまたは64ビットのオペレーションが必要な場合など、そのことを伝える必要があります。多分、このページは役に立ちます:http://sourceware.org/binutils/docs/as/i386_002dMnemonics.html – Dave

1
var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift)) 

このコードを使用しないでください。 shiftが0の場合、動作は未定義です。インテルのICCは、未定義の動作を含む文を削除します。私は最初の手を知っている。

さらに、コードはClangまたはGCCのUndefined Behaviorサニタイザを渡しません。読書については、ClangのControlling Code GenerationまたはGCCのUndefined Behavior Sanitizer – ubsanを参照してください。


私が手にエラーがある:あなたは2つのツールのいずれかを使用している未知のサイズの接尾辞

と命令ニーモニックの
不明使用 - GCCやクランのいずれか。私はAppleがXcode 4の周りにデフォルトでClangに切り詰めると思うので、おそらくあなたはClangを使用しているだろう。

GCCはGNU AS(GAS)に委任し、Clangは統合アセンブラを使用します。どちらの場合も、インテルアセンブリのClangサポートには問題があるため、AT & Tインラインアセンブリを使用する必要があります。たとえば、Clang can't generate a negate instructions(a.k.a. LLVM Bug 24232)です。

Clangを使用する場合は、オペランドサイズを指定する必要があります。したがって、rolbrolwroll、およびrolqとお友達を使用します。これはClangのLanguage Compatibility | Inline Assemblyページに記載されています。

// Immediate 
inline word8 rotlImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolb %1, %0" : "+mq" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word8 rotl8 (word8 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

// Immediate 
inline word8 rotrImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorb %1, %0" : "+mq" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word8 rotr8 (word8 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

8ビットワードが制約に特別な処理を必要とします:

は、ここのような8ビットの回転が見えるものです。 +gは使用できません。むしろ+mqが必要です。ここで

は、16ビット・ワードのバージョンです:

// Immediate 
inline word16 rotlImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolw %1, %0" : "+g" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word16 rotl16 (word16 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolw %1, %0" : "+g" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

// Immediate 
inline word16 rotrImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorw %1, %0" : "+g" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word16 rotr16 (word16 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorw %1, %0" : "+g" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

そして、ここでは32ビット版です:

// Immediate 
inline word32 rotlImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("roll %1, %0" : "+g" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word32 rotl32 (word32 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("roll %1, %0" : "+g" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

// Immediate 
inline word32 rotrImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorl %1, %0" : "+g" (x) : "I" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word32 rotr32 (word32 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorl %1, %0" : "+g" (x) : "cI" ((unsigned char)y)); 
    return x; 
} 

最後に、ここでは64ビット版です。あなたは__amd64または__x86_64__のようなものでそれを守るべきです。回転量は[0,63]になる可能性があるため、Jという制約を使用します。

// Immediate 
inline word64 rotlImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolq %1, %0" : "+g" (x) : "J" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word64 rotl64 (word64 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rolq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y)); 
    return x; 
} 

// Immediate 
inline word64 rotrImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorq %1, %0" : "+g" (x) : "J" ((unsigned char)y)); 
    return x; 
} 

// Immediate or register 
inline word64 rotr64 (word64 x /*value*/, unsigned int y /*rotate*/) 
{ 
    __asm__ ("rorq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y)); 
    return x; 
} 

ClangはGCCのような定数を伝播しないので、Immediate-8バージョンの回転に問題が生じる可能性があります。 Stack OverflowのForce Clang to “perform math early” on constant valuesLLVM Bug 24226を参照してください。


時間を取って、John RegehrのSafe, Efficient, and Portable Rotate in C/C++にアクセスしてください。そのような反楽観主義のようなものです。これは、C/C++で回転を正しく書くと(つまり、未定義の振る舞いがなくなると)回転として認識されなくなり、回転命令になりません。

最後に、スタックオーバーフローに関するNear constant time rotate that does not violate the standardsも参照してください。

関連する問題