福野泰介の一日一創 - create every day

iPhoneインラインアセンブラ入門、64bit Armマシン語はじめのいっぽ

2016/08/17
#Arm #swift 

IchigoJamもiPhoneも同じArmのCPU、IchigoJamでマシン語を覚えたらiPhoneでも使ってみましょう。今回の対象は、64bit化したArm64(Armv8)対応のiPhone5s以降です。ネットや書籍での資料には32bit時代のものも混在しているので注意が必要です。(iPhone Wikipedia)。

Swiftにはインラインアセンブラ機能はまだないようなので、Objective-CでGameをテンプレートに選び、次の行を viewDidLoad の [super viedDidLoad]; の後に追加します。

__asm__ volatile ("mov x0, x0");

※__asm__ はインラインアセンブラ、volatile で最適化を停止
エミュレーター向けだとコンパイルエラーになります。(IntelがArmライセンス取得とのことなので、MacBookへのArmv8組み込みにも期待!まずはApple-Aの生産から?詳しい解説記事


iPhoneでArm64マシン語、動きました!
(3Dの飛行機はサンプルのままで、今回のアセンブラでの動作とは無関係です)

mov x0, x0 は、レジスタX0の内容をレジスタX0に入れる(つまり、ほぼ何もしない)というマシン語を生成します。やっかいなことにこのコードはMacのiPhoneエミュレーターでは動きません。iPhoneエミュレーターはArmのCPUまでは動かしてくれないようです。実機向けにコンパイルすると動きます。(Arm64では64bitになったレジスタをRではなくXで呼ぶようになった様子)

Objective-Cでの変数との足し算をやってみます。

long num = 1; __asm__ volatile ( "mov x1, #1 \n\t" "add %[n], %[n], x1 \n\t" : [n] "+r" (num) : : "x1" ); NSLog(@"res: %ld\n", n);

コンソールに結果として 2 と表示されます。mov x1,#1 でレジスタX1に1を入れ、add命令で%[n]というコンパイラ任せなレジスタX?にX1の値を加えます。IchigoJamマシン語入門では X1=1 と表記していました。

最初のコロンの後 [n] "+r" (num) で、Objective-Cの変数numを%[n]というレジスタに割り当てて、読み書き"+"するよと指定しています。

三番目のコロンの後の "x1" で、インラインアセンブラ内で X1 レジスタを使用すると宣言して、前後のプログラムと干渉しないようにコンパイラに指定します。

これで基本はOKですね!
より詳しい解説は、こちら「Arm GCC Inline Assembler Cookbook」など参照ください

せっかくなので、アセンブラならでは機能を使った便利な関数を作ってみます。

- (unsigned long)rbit:(unsigned long)n { __asm__ volatile ( "rbit %[n], %[n] \n\t" : [n] "+r" (n) ); return n; }

rbitというのは、64のbit列を反転する命令です。普通に計算すると結構手間ですが、マシン語なら1クロック、0.1nsecで計算します!(参照、Arm64(Armv8) Assembly Programming (08) 分岐命令

iPhone(Armv8)とIchigoJam(Armv6-M)との比較です。

IchigoJamのCortex-M0のThumb-2命令とも互換性あるiPhone6sですが、浮動小数やSIMD命令など性能をフルに活かすならArm64マシン語プログラミングへのステップアップがオススメです!レジスタもたくさんあるので作るのも楽!

参考
- Arm64(Armv8) Assembly Programming (00)(とっても詳しいRAM64解説)
- 連載、IchigoJamではじめる、Armマシン語入門
- 連載、iPhoneゲームづくりからはじめる、Swift入門

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY 福野泰介 - Taisuke Fukuno / @taisukef / アイコン画像 / プロフィール画像