MENU

競技プログラミングのためにインラインアセンブラに入門してみたので解説【入出力,基本命令編】

0.はじめに

僕自身が学んでる途中なので嘘などあるかも知れません
高速化に目覚めたので書いていきます
これ使うだけじゃ速くならないと思います
SIMD使う前の準備だと思って練習してます
atcoderC++(GCC 9.2.1)準拠です

1.入出力

int main(){
    int res;
    asm("":"=a"(res):"a"(2));
    cout<<res<<endl;
}

2をaに入力して、何もせず、aをresに出力するコードです。
当然resは2になります

asm("コード":"出力":"入力");

が基本の書き方になります。
セミコロンで区切れば命令を繋げられます

2. 変数と代入

int main(){
    int res;
    asm("mov %2,%1":"=a"(res):"a"(0),"b"(2));
    cout<<res<<endl;
}

左にあるものから変数が割り当てられて行きます

つまり
"=a"とあるので%0はa
"a"とあるので%1はa
"b"とあるので%2はb
といった具合です

"="は出力専用であることを示しているらしいですが普通に読めてそうでよくわからないです
また、a,b,=といった文字は制約文字と言ってなんでもいいわけでは無いです
とりあえず、a,b,c,dが変数っぽく使えるので今回はそれで行きます。
制約文字についての詳しい説明はGCC x86 Inline Assemblerにあります

次にmov関数について説明すると
mov x,y はyにxを代入する構文です
x,y逆じゃないのって思うんですが、デフォルトだとこれらしいです(GAS構文と言うらしいです)

3. 注意の要らない基本命令

整数型限定です
64bitで渡せば64bitで
32bitで渡せば32bitでやってくれるみたいです
fujita nozomuさんありがとうございます!!


int main(){
    int a;
    asm("add %2,%1":"=a"(a):"a"(1),"b"(2)); //(%1)+=(%2);
    asm("sub %2,%1":"=a"(a):"a"(1),"b"(2)); //(%1)-=(%2);
    asm("imul %2,%1":"=a"(a):"a"(1),"b"(2)); //(%1)*=(%2); imulなので注意
    asm("inc %1":"=a"(a):"a"(1));           //(%1)++;
    asm("dec %1":"=a"(a):"a"(1));           //(%1)--;
    asm("or %2,%1":"=a"(a):"a"(1),"b"(2));  //(%1)|=(%2);
    asm("and %2,%1":"=a"(a):"a"(1),"b"(2)); //(%1)&=(%2);
    asm("xor %2,%1":"=a"(a):"a"(1),"b"(2)); //(%1)^=(%2);
    asm("not %1":"=a"(a):"a"(1));           //(%1)=~(%1);
    asm("shl %1":"=a"(a):"a"(1));           //(%1)<<=1;
    asm("shr %1":"=a"(a):"a"(2));           //(%1)>>=1;
}

http://ankokudan.org/d/dl/pdf/pdf-linuxasm.pdf
が詳しいです

4.注意のいる命令(idiv)

この場合、aを(%3)で割った商をaに、余りをdに格納します
aとdは固定です。意味わかんねぇ
なので下の場合出力は1 2です

int main(){
    int a,d;
    // (a,d)=(a/(%3),a%(%3))
    asm("idiv %3":"=a"(a),"=d"(d):"a"(5),"b"(3),"d"(0));
    cout<<a<<" "<<d<<endl;
}

5.終わりに

学んだのはここまでなので、一旦ここまでにします
if,forを使える様になりたい