第7章 コンパイル結果のアセンブリを読む

7.1 この章で学ぶこと

この章で学ぶ内容は以下のとおりです。

表7-1: 本章で学ぶこと

学ぶこと

ポイント

定数畳み込み最適化

n * 2 がコンパイル時に 84 に確定し、実行時に乗算命令が発生しない理由

List 構築の内部呼び出し列

__init___annotate_increase → 転送用クロージャの初期化 → consume_elements → クロージャの後始末、という呼び出し順

文字列オブジェクトのレイアウト

データポインタ・長さ・タグ・関数ポインタ 2 本がスタック上に並ぶ様子

引数テーブルとスコープ最適化

多引数 print() の組み立て方と、Listprint() より前に解放される理由

後片付けパターンの繰り返し

String オブジェクトに対するエラーチェック・refcount デクリメント・解放の流れ

7.2 対象コードとアセンブリ出力

前章では、言語基礎の最小サンプル(リスト6-1)を示しました。 この章では、そのコンパイル結果(リスト7-2)を手がかりに、main() の機械語を段階的に追います。

対象のソースコードは以下のとおりです(前章リスト6-1 の再掲)。

def main():
    var n: Int = 42
    var doubled = n * 2
    var xs: List[Int] = [1, 2, 3]
    var label = String("count")
    print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))

リスト7-1(再掲): language_basics_minimal.mojo

このコードをコンパイルすると、実際には機械語へ変換されます。

language_basics_minimal.o:
(__TEXT,__text) section
_language_basics_minimal::main():
; def main():
       0:	48 81 ec b8 04 00 00	subq	$0x4b8, %rsp
;     var n: Int = 42
       7:	48 c7 84 24 e8 01 00 00 2a 00 00 00	movq	$0x2a, 0x1e8(%rsp)
;     var doubled = n * 2
      13:	48 c7 84 24 f0 01 00 00 54 00 00 00	movq	$0x54, 0x1f0(%rsp)
;     var xs: List[Int] = [1, 2, 3]
      1f:	48 c7 84 24 f8 01 00 00 01 00 00 00	movq	$0x1, 0x1f8(%rsp)
      2b:	48 c7 84 24 00 02 00 00 02 00 00 00	movq	$0x2, 0x200(%rsp)
      37:	48 c7 84 24 08 02 00 00 03 00 00 00	movq	$0x3, 0x208(%rsp)
      43:	48 8d 84 24 08 02 00 00	leaq	0x208(%rsp), %rax
      4b:	48 89 84 24 20 02 00 00	movq	%rax, 0x220(%rsp)
      53:	48 8d 84 24 00 02 00 00	leaq	0x200(%rsp), %rax
      5b:	48 89 84 24 18 02 00 00	movq	%rax, 0x218(%rsp)
      63:	48 8d 84 24 f8 01 00 00	leaq	0x1f8(%rsp), %rax
      6b:	48 89 84 24 10 02 00 00	movq	%rax, 0x210(%rsp)
      73:	90	nop
      74:	48 8d 84 24 10 02 00 00	leaq	0x210(%rsp), %rax
      7c:	48 89 84 24 38 01 00 00	movq	%rax, 0x138(%rsp)
      84:	48 89 84 24 e0 03 00 00	movq	%rax, 0x3e0(%rsp)
      8c:	48 89 84 24 28 02 00 00	movq	%rax, 0x228(%rsp)
      94:	48 89 84 24 30 02 00 00	movq	%rax, 0x230(%rsp)
      9c:	48 89 84 24 38 02 00 00	movq	%rax, 0x238(%rsp)
      a4:	48 89 84 24 e8 03 00 00	movq	%rax, 0x3e8(%rsp)
      ac:	48 89 84 24 40 02 00 00	movq	%rax, 0x240(%rsp)
      b4:	48 89 84 24 48 02 00 00	movq	%rax, 0x248(%rsp)
      bc:	48 89 84 24 f0 03 00 00	movq	%rax, 0x3f0(%rsp)
;     var xs: List[Int] = [1, 2, 3]
      c4:	90	nop
      c5:	48 89 84 24 f8 03 00 00	movq	%rax, 0x3f8(%rsp)
      cd:	48 c7 84 24 00 04 00 00 03 00 00 00	movq	$0x3, 0x400(%rsp)
      d9:	90	nop
      da:	48 89 84 24 08 04 00 00	movq	%rax, 0x408(%rsp)
      e2:	48 c7 84 24 10 04 00 00 03 00 00 00	movq	$0x3, 0x410(%rsp)
      ee:	90	nop
      ef:	48 89 84 24 18 04 00 00	movq	%rax, 0x418(%rsp)
      f7:	48 c7 84 24 20 04 00 00 03 00 00 00	movq	$0x3, 0x420(%rsp)
     103:	90	nop
     104:	48 89 84 24 28 04 00 00	movq	%rax, 0x428(%rsp)
     10c:	48 c7 84 24 30 04 00 00 03 00 00 00	movq	$0x3, 0x430(%rsp)
;     var xs: List[Int] = [1, 2, 3]
     118:	bf 03 00 00 00	movl	$0x3, %edi
     11d:	48 89 bc 24 40 01 00 00	movq	%rdi, 0x140(%rsp)
     125:	48 8d b4 24 50 02 00 00	leaq	0x250(%rsp), %rsi
     12d:	48 89 b4 24 50 01 00 00	movq	%rsi, 0x150(%rsp)
     135:	e8 00 00 00 00	callq	"_std::collections::list::List::__init__(capacity:::SIMD[::DType(int), ::SIMDLength(1)]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>]"
     13a:	48 8b b4 24 40 01 00 00	movq	0x140(%rsp), %rsi
     142:	48 8b bc 24 50 01 00 00	movq	0x150(%rsp), %rdi
     14a:	e8 00 00 00 00	callq	"_std::collections::list::List::_annotate_increase(::List[$0],::SIMD[::DType(int), ::SIMDLength(1)]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>]"
     14f:	48 8b bc 24 50 01 00 00	movq	0x150(%rsp), %rdi
     157:	48 8d b4 24 68 02 00 00	leaq	0x268(%rsp), %rsi
     15f:	48 89 b4 24 30 01 00 00	movq	%rsi, 0x130(%rsp)
     167:	e8 00 00 00 00	callq	"_std::collections::list::List::__init__[LITMutOrigin,::Origin[::Bool(True), $1]]($0$*,__list_literal__:::NoneType)::init_elt::__storage::__init__(::List[$0]%),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>]"
     16c:	48 8b bc 24 30 01 00 00	movq	0x130(%rsp), %rdi
     174:	48 8d b4 24 70 02 00 00	leaq	0x270(%rsp), %rsi
     17c:	48 89 b4 24 48 01 00 00	movq	%rsi, 0x148(%rsp)
     184:	e8 00 00 00 00	callq	"_std::collections::list::def[T: Movable, //](idx: Int, var elt: T) -> None{1}_3::__init__($0$),impl=[typevalue<#kgen.instref<\"std::collections::list::List::__init__[LITMutOrigin,::Origin[::Bool(True), $1]]($0$*,__list_literal__:::NoneType)::init_elt::__storage,T=[typevalue<#kgen.instref<\\1B\\22std::builtin::simd::SIMD,dtype=index,length=1\\22>>, scalar<index>],self`2x3={  }\">>, struct<(pointer<struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>>) memoryOnly>]"
     189:	48 8b bc 24 38 01 00 00	movq	0x138(%rsp), %rdi
     191:	48 8b b4 24 40 01 00 00	movq	0x140(%rsp), %rsi
     199:	48 8b 94 24 48 01 00 00	movq	0x148(%rsp), %rdx
     1a1:	e8 00 00 00 00	callq	"_std::builtin::variadics::VariadicList::consume_elements[def[element_type: AnyType, //](idx: Int, var elt: element_type) -> None{1} & ::AnyType & ::Deinitable & ::Movable](::VariadicList[$0, $1, $2, $3, $4]$,$5){$4._mlir_value,(eq $5.element_type, $3)},elt_is_mutable=true,element_type=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>],is_owned=true,elt_handler.T`2x1=[typevalue<#kgen.instref<\"std::collections::list::def[T: Movable, //](idx: Int, var elt: T) -> None{1}_3,impl=[typevalue<#kgen.instref<\\1B\\22std::collections::list::List::__init__[LITMutOrigin,::Origin[::Bool(True), $1]]($0$*,__list_literal__:::NoneType)::init_elt::__storage,T=[typevalue<#kgen.instref<\\\\1B\\\\22std::builtin::simd::SIMD,dtype=index,length=1\\\\22>>, scalar<index>],self`2x3={  }\\22>>, struct<(pointer<struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>>) memoryOnly>],origin_set={  }\">>, struct<(struct<(pointer<struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>>) memoryOnly>) memoryOnly>]"
     1a6:	48 8b bc 24 48 01 00 00	movq	0x148(%rsp), %rdi
     1ae:	e8 00 00 00 00	callq	"_std::collections::list::def[T: Movable, //](idx: Int, var elt: T) -> None{1}_3::__deinit__(::def[T: Movable, //](idx: Int, var elt: T) -> None{1}_3[$0, $1]$),impl=[typevalue<#kgen.instref<\"std::collections::list::List::__init__[LITMutOrigin,::Origin[::Bool(True), $1]]($0$*,__list_literal__:::NoneType)::init_elt::__storage,T=[typevalue<#kgen.instref<\\1B\\22std::builtin::simd::SIMD,dtype=index,length=1\\22>>, scalar<index>],self`2x3={  }\">>, struct<(pointer<struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>>) memoryOnly>]"
     1b3:	48 8b bc 24 50 01 00 00	movq	0x150(%rsp), %rdi
     1bb:	48 c7 84 24 58 02 00 00 03 00 00 00	movq	$0x3, 0x258(%rsp)
;     var label = String("count")
     1c7:	48 8d 84 24 80 02 00 00	leaq	0x280(%rsp), %rax
     1cf:	48 89 84 24 58 01 00 00	movq	%rax, 0x158(%rsp)
     1d7:	48 c7 84 24 80 02 00 00 05 00 00 00	movq	$0x5, 0x280(%rsp)
     1e3:	48 8d 84 24 78 02 00 00	leaq	0x278(%rsp), %rax
     1eb:	48 89 84 24 60 01 00 00	movq	%rax, 0x160(%rsp)
     1f3:	48 8d 05 00 00 00 00	leaq	_static_string_3abc19b547835280(%rip), %rax
     1fa:	48 89 84 24 90 02 00 00	movq	%rax, 0x290(%rsp)
     202:	48 89 84 24 98 02 00 00	movq	%rax, 0x298(%rsp)
     20a:	48 89 84 24 78 02 00 00	movq	%rax, 0x278(%rsp)
     212:	48 8d 84 24 88 02 00 00	leaq	0x288(%rsp), %rax
     21a:	48 89 84 24 68 01 00 00	movq	%rax, 0x168(%rsp)
     222:	48 b8 00 00 00 00 00 00 00 20	movabsq	$0x2000000000000000, %rax
     22c:	48 89 84 24 88 02 00 00	movq	%rax, 0x288(%rsp)
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     234:	48 8d 8c 24 a8 02 00 00	leaq	0x2a8(%rsp), %rcx
     23c:	48 89 8c 24 70 01 00 00	movq	%rcx, 0x170(%rsp)
     244:	48 c7 84 24 a8 02 00 00 02 00 00 00	movq	$0x2, 0x2a8(%rsp)
     250:	48 8d 8c 24 a0 02 00 00	leaq	0x2a0(%rsp), %rcx
     258:	48 89 8c 24 78 01 00 00	movq	%rcx, 0x178(%rsp)
     260:	48 8d 0d 00 00 00 00	leaq	_static_string_8cc7ea4ad907a4ea(%rip), %rcx
     267:	48 89 8c 24 b8 02 00 00	movq	%rcx, 0x2b8(%rsp)
     26f:	48 89 8c 24 c0 02 00 00	movq	%rcx, 0x2c0(%rsp)
     277:	48 89 8c 24 a0 02 00 00	movq	%rcx, 0x2a0(%rsp)
     27f:	48 8d 8c 24 b0 02 00 00	leaq	0x2b0(%rsp), %rcx
     287:	48 89 8c 24 80 01 00 00	movq	%rcx, 0x180(%rsp)
     28f:	48 89 84 24 b0 02 00 00	movq	%rax, 0x2b0(%rsp)
     297:	48 8d 8c 24 d0 02 00 00	leaq	0x2d0(%rsp), %rcx
     29f:	48 89 8c 24 88 01 00 00	movq	%rcx, 0x188(%rsp)
     2a7:	48 c7 84 24 d0 02 00 00 05 00 00 00	movq	$0x5, 0x2d0(%rsp)
     2b3:	48 8d 8c 24 c8 02 00 00	leaq	0x2c8(%rsp), %rcx
     2bb:	48 89 8c 24 90 01 00 00	movq	%rcx, 0x190(%rsp)
     2c3:	48 8d 0d 00 00 00 00	leaq	_static_string_d170193af0361179(%rip), %rcx
     2ca:	48 89 8c 24 e0 02 00 00	movq	%rcx, 0x2e0(%rsp)
     2d2:	48 89 8c 24 e8 02 00 00	movq	%rcx, 0x2e8(%rsp)
     2da:	48 89 8c 24 c8 02 00 00	movq	%rcx, 0x2c8(%rsp)
     2e2:	48 8d 8c 24 d8 02 00 00	leaq	0x2d8(%rsp), %rcx
     2ea:	48 89 8c 24 98 01 00 00	movq	%rcx, 0x198(%rsp)
     2f2:	48 89 84 24 d8 02 00 00	movq	%rax, 0x2d8(%rsp)
     2fa:	48 8d 8c 24 f8 02 00 00	leaq	0x2f8(%rsp), %rcx
     302:	48 89 8c 24 a0 01 00 00	movq	%rcx, 0x1a0(%rsp)
     30a:	48 c7 84 24 f8 02 00 00 01 00 00 00	movq	$0x1, 0x2f8(%rsp)
     316:	48 8d 8c 24 f0 02 00 00	leaq	0x2f0(%rsp), %rcx
     31e:	48 89 8c 24 a8 01 00 00	movq	%rcx, 0x1a8(%rsp)
     326:	48 8d 0d 00 00 00 00	leaq	_static_string_a8d4ace0dc8d360e(%rip), %rcx
     32d:	48 89 8c 24 d0 01 00 00	movq	%rcx, 0x1d0(%rsp)
     335:	48 89 8c 24 08 03 00 00	movq	%rcx, 0x308(%rsp)
     33d:	48 89 8c 24 10 03 00 00	movq	%rcx, 0x310(%rsp)
     345:	48 89 8c 24 f0 02 00 00	movq	%rcx, 0x2f0(%rsp)
     34d:	48 8d 8c 24 00 03 00 00	leaq	0x300(%rsp), %rcx
     355:	48 89 8c 24 b0 01 00 00	movq	%rcx, 0x1b0(%rsp)
     35d:	48 89 84 24 00 03 00 00	movq	%rax, 0x300(%rsp)
     365:	48 8d 8c 24 20 03 00 00	leaq	0x320(%rsp), %rcx
     36d:	48 89 8c 24 b8 01 00 00	movq	%rcx, 0x1b8(%rsp)
     375:	48 c7 84 24 20 03 00 00 01 00 00 00	movq	$0x1, 0x320(%rsp)
     381:	48 8d 8c 24 18 03 00 00	leaq	0x318(%rsp), %rcx
     389:	48 89 8c 24 c0 01 00 00	movq	%rcx, 0x1c0(%rsp)
     391:	48 8d 0d 00 00 00 00	leaq	_static_string_0308bb2145aa4faa(%rip), %rcx
     398:	48 89 8c 24 30 03 00 00	movq	%rcx, 0x330(%rsp)
     3a0:	48 89 8c 24 38 03 00 00	movq	%rcx, 0x338(%rsp)
     3a8:	48 89 8c 24 18 03 00 00	movq	%rcx, 0x318(%rsp)
     3b0:	48 8d 8c 24 28 03 00 00	leaq	0x328(%rsp), %rcx
     3b8:	48 89 8c 24 c8 01 00 00	movq	%rcx, 0x1c8(%rsp)
     3c0:	48 89 84 24 28 03 00 00	movq	%rax, 0x328(%rsp)
     3c8:	90	nop
     3c9:	48 8b 84 24 58 02 00 00	movq	0x258(%rsp), %rax
     3d1:	48 89 84 24 d8 01 00 00	movq	%rax, 0x1d8(%rsp)
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     3d9:	e8 00 00 00 00	callq	"_std::collections::list::List::__deinit__(::List[$0]$){conforms_to($0, ::AnyType & ::Deinitable)},T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>]"
     3de:	48 8b 84 24 d0 01 00 00	movq	0x1d0(%rsp), %rax
     3e6:	48 8b 94 24 d8 01 00 00	movq	0x1d8(%rsp), %rdx
     3ee:	48 89 94 24 40 03 00 00	movq	%rdx, 0x340(%rsp)
     3f6:	90	nop
     3f7:	90	nop
     3f8:	48 89 84 24 38 04 00 00	movq	%rax, 0x438(%rsp)
     400:	48 c7 84 24 40 04 00 00 01 00 00 00	movq	$0x1, 0x440(%rsp)
     40c:	48 c7 84 24 48 04 00 00 01 00 00 00	movq	$0x1, 0x448(%rsp)
     418:	48 89 84 24 48 03 00 00	movq	%rax, 0x348(%rsp)
     420:	48 89 84 24 50 03 00 00	movq	%rax, 0x350(%rsp)
     428:	48 89 84 24 50 04 00 00	movq	%rax, 0x450(%rsp)
     430:	48 89 84 24 58 04 00 00	movq	%rax, 0x458(%rsp)
     438:	48 c7 84 24 60 04 00 00 01 00 00 00	movq	$0x1, 0x460(%rsp)
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     444:	90	nop
     445:	90	nop
     446:	48 8d 05 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rax
     44d:	48 89 84 24 38 04 00 00	movq	%rax, 0x438(%rsp)
     455:	48 c7 84 24 40 04 00 00 01 00 00 00	movq	$0x1, 0x440(%rsp)
     461:	48 c7 84 24 48 04 00 00 01 00 00 00	movq	$0x1, 0x448(%rsp)
     46d:	48 8d 05 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rax
     474:	48 89 84 24 58 03 00 00	movq	%rax, 0x358(%rsp)
     47c:	48 8d 05 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rax
     483:	48 89 84 24 60 03 00 00	movq	%rax, 0x360(%rsp)
     48b:	48 8d 05 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rax
     492:	48 89 84 24 50 04 00 00	movq	%rax, 0x450(%rsp)
     49a:	48 8d 05 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rax
     4a1:	48 89 84 24 68 04 00 00	movq	%rax, 0x468(%rsp)
     4a9:	48 c7 84 24 70 04 00 00 01 00 00 00	movq	$0x1, 0x470(%rsp)
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     4b5:	48 8b b4 24 e8 01 00 00	movq	0x1e8(%rsp), %rsi
     4bd:	48 8b 8c 24 f0 01 00 00	movq	0x1f0(%rsp), %rcx
     4c5:	48 8d 3d 00 00 00 00	leaq	_static_string_bbe01a6a523daf15(%rip), %rdi
     4cc:	48 89 e0	movq	%rsp, %rax
     4cf:	48 89 84 24 e0 01 00 00	movq	%rax, 0x1e0(%rsp)
     4d7:	48 89 78 20	movq	%rdi, 0x20(%rax)
     4db:	48 8d 3d 00 00 00 00	leaq	_static_string_a8d4ace0dc8d360e(%rip), %rdi
     4e2:	48 89 78 10	movq	%rdi, 0x10(%rax)
     4e6:	48 89 50 08	movq	%rdx, 0x8(%rax)
     4ea:	48 8d 94 24 18 03 00 00	leaq	0x318(%rsp), %rdx
     4f2:	48 89 10	movq	%rdx, "_language_basics_minimal::main()"(%rax)
     4f5:	48 c7 40 38 01 00 00 00	movq	$0x1, 0x38(%rax)
     4fd:	c7 40 30 00 00 00 00	movl	$"_language_basics_minimal::main()", 0x30(%rax)
     504:	48 c7 40 28 01 00 00 00	movq	$0x1, 0x28(%rax)
     50c:	48 c7 40 18 01 00 00 00	movq	$0x1, 0x18(%rax)
     514:	48 8d bc 24 a0 02 00 00	leaq	0x2a0(%rsp), %rdi
     51c:	48 8d 94 24 c8 02 00 00	leaq	0x2c8(%rsp), %rdx
     524:	4c 8d 84 24 f0 02 00 00	leaq	0x2f0(%rsp), %r8
     52c:	4c 8d 8c 24 78 02 00 00	leaq	0x278(%rsp), %r9
     534:	e8 00 00 00 00	callq	"_std::io::io::print[KGENParamList[::Writable & ::AnyType],*::Writable & ::AnyType,LITImmOrigin,::Origin[::Bool(False), $2],::Bool,LITOrigin[$4._mlir_value],::Origin[$4, $5],::Bool,LITOrigin[$7._mlir_value],::Origin[$7, $8]](*$0,sep:::StringSpan[$4, $5, $6],end:::StringSpan[$7, $8, $9],flush:::Bool,file:::FileDescriptor$),Ts.values`=[[typevalue<#kgen.instref<\"std::collections::string::string::String\">>, struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>], [typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>], [typevalue<#kgen.instref<\"std::collections::string::string::String\">>, struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>], [typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>], [typevalue<#kgen.instref<\"std::collections::string::string::String\">>, struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>], [typevalue<#kgen.instref<\"std::collections::string::string::String\">>, struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>], [typevalue<#kgen.instref<\"std::collections::string::string::String\">>, struct<(pointer<none>, scalar<index>, scalar<index>) memoryOnly>], [typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=index,length=1\">>, scalar<index>]],sep.mut`4=false,end.mut`7=false"
     539:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     543:	48 23 84 24 28 03 00 00	andq	0x328(%rsp), %rax
     54b:	48 83 f8 00	cmpq	$0x0, %rax
     54f:	0f 84 92 01 00 00	je	0x6e7
     555:	48 8b 84 24 c0 01 00 00	movq	0x1c0(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     55d:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     560:	48 83 c0 f8	addq	$-0x8, %rax
     564:	48 89 84 24 28 01 00 00	movq	%rax, 0x128(%rsp)
     56c:	48 89 84 24 68 03 00 00	movq	%rax, 0x368(%rsp)
     574:	48 89 84 24 70 03 00 00	movq	%rax, 0x370(%rsp)
     57c:	90	nop
     57d:	48 8b 8c 24 28 01 00 00	movq	0x128(%rsp), %rcx
     585:	48 c7 84 24 78 04 00 00 01 00 00 00	movq	$0x1, 0x478(%rsp)
     591:	48 89 8c 24 78 03 00 00	movq	%rcx, 0x378(%rsp)
     599:	48 89 8c 24 80 04 00 00	movq	%rcx, 0x480(%rsp)
     5a1:	48 c7 c0 ff ff ff ff	movq	$-0x1, %rax
     5a8:	f0	lock
     5a9:	48 0f c1 01	xaddq	%rax, "_language_basics_minimal::main()"(%rcx)
     5ad:	48 89 84 24 88 04 00 00	movq	%rax, 0x488(%rsp)
     5b5:	48 89 84 24 20 01 00 00	movq	%rax, 0x120(%rsp)
     5bd:	48 8b 84 24 20 01 00 00	movq	0x120(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     5c5:	48 83 f8 01	cmpq	$0x1, %rax
     5c9:	0f 85 14 01 00 00	jne	0x6e3
     5cf:	eb 00	jmp	0x5d1
     5d1:	48 8b bc 24 28 01 00 00	movq	0x128(%rsp), %rdi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     5d9:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::__init__(unsafe_owned_ptr:::Pointer[::Bool(True), MutUntrackedOrigin, $0, *?, ::AddressSpace(::SIMDLength(0))]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     5de:	48 89 84 24 18 01 00 00	movq	%rax, 0x118(%rsp)
     5e6:	48 8b 8c 24 c8 01 00 00	movq	0x1c8(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     5ee:	48 b8 00 00 00 00 00 00 00 80	movabsq	$-0x8000000000000000, %rax
     5f8:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     5fb:	48 83 f8 00	cmpq	$0x0, %rax
     5ff:	74 0f	je	0x610
     601:	b8 17 00 00 00	movl	$0x17, %eax
     606:	48 89 84 24 10 01 00 00	movq	%rax, 0x110(%rsp)
     60e:	eb 60	jmp	0x670
     610:	48 8b 8c 24 c8 01 00 00	movq	0x1c8(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     618:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     622:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     625:	48 83 f8 00	cmpq	$0x0, %rax
     629:	0f 95 c0	setne	%al
     62c:	34 ff	xorb	$-0x1, %al
     62e:	a8 01	testb	$0x1, %al
     630:	75 02	jne	0x634
     632:	eb 15	jmp	0x649
     634:	48 8b 84 24 b8 01 00 00	movq	0x1b8(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     63c:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     63f:	48 89 84 24 08 01 00 00	movq	%rax, 0x108(%rsp)
     647:	eb 17	jmp	0x660
     649:	48 8b 84 24 c8 01 00 00	movq	0x1c8(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     651:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     654:	48 c1 e0 03	shlq	$0x3, %rax
     658:	48 89 84 24 08 01 00 00	movq	%rax, 0x108(%rsp)
     660:	48 8b 84 24 08 01 00 00	movq	0x108(%rsp), %rax
     668:	48 89 84 24 10 01 00 00	movq	%rax, 0x110(%rsp)
     670:	48 8b 84 24 10 01 00 00	movq	0x110(%rsp), %rax
     678:	48 89 84 24 00 01 00 00	movq	%rax, 0x100(%rsp)
     680:	48 8b bc 24 18 01 00 00	movq	0x118(%rsp), %rdi
     688:	48 8b b4 24 00 01 00 00	movq	0x100(%rsp), %rsi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     690:	48 83 c6 08	addq	$0x8, %rsi
     694:	48 89 f0	movq	%rsi, %rax
     697:	90	nop
     698:	48 89 b4 24 90 04 00 00	movq	%rsi, 0x490(%rsp)
     6a0:	90	nop
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     6a1:	48 89 b4 24 98 04 00 00	movq	%rsi, 0x498(%rsp)
     6a9:	48 c7 84 24 a0 04 00 00 01 00 00 00	movq	$0x1, 0x4a0(%rsp)
     6b5:	ba 01 00 00 00	movl	$0x1, %edx
     6ba:	48 89 84 24 a8 04 00 00	movq	%rax, 0x4a8(%rsp)
     6c2:	48 c7 84 24 b0 04 00 00 01 00 00 00	movq	$0x1, 0x4b0(%rsp)
     6ce:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::unsafe_with_layout(::ThinAllocation[$0]$,::Layout[$0]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     6d3:	48 89 c7	movq	%rax, %rdi
     6d6:	48 89 d6	movq	%rdx, %rsi
     6d9:	48 89 ca	movq	%rcx, %rdx
     6dc:	e8 00 00 00 00	callq	"_std::memory::alloc::dealloc[::AnyType](::Allocation[$0]$),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     6e1:	eb 02	jmp	0x6e5
     6e3:	eb 00	jmp	0x6e5
     6e5:	eb 02	jmp	0x6e9
     6e7:	eb 00	jmp	0x6e9
     6e9:	48 8b 8c 24 b0 01 00 00	movq	0x1b0(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     6f1:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     6fb:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     6fe:	48 83 f8 00	cmpq	$0x0, %rax
     702:	0f 84 92 01 00 00	je	0x89a
     708:	48 8b 84 24 a8 01 00 00	movq	0x1a8(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     710:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     713:	48 83 c0 f8	addq	$-0x8, %rax
     717:	48 89 84 24 f8 00 00 00	movq	%rax, 0xf8(%rsp)
     71f:	48 89 84 24 80 03 00 00	movq	%rax, 0x380(%rsp)
     727:	48 89 84 24 88 03 00 00	movq	%rax, 0x388(%rsp)
     72f:	90	nop
     730:	48 8b 8c 24 f8 00 00 00	movq	0xf8(%rsp), %rcx
     738:	48 c7 84 24 78 04 00 00 01 00 00 00	movq	$0x1, 0x478(%rsp)
     744:	48 89 8c 24 90 03 00 00	movq	%rcx, 0x390(%rsp)
     74c:	48 89 8c 24 80 04 00 00	movq	%rcx, 0x480(%rsp)
     754:	48 c7 c0 ff ff ff ff	movq	$-0x1, %rax
     75b:	f0	lock
     75c:	48 0f c1 01	xaddq	%rax, "_language_basics_minimal::main()"(%rcx)
     760:	48 89 84 24 88 04 00 00	movq	%rax, 0x488(%rsp)
     768:	48 89 84 24 f0 00 00 00	movq	%rax, 0xf0(%rsp)
     770:	48 8b 84 24 f0 00 00 00	movq	0xf0(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     778:	48 83 f8 01	cmpq	$0x1, %rax
     77c:	0f 85 14 01 00 00	jne	0x896
     782:	eb 00	jmp	0x784
     784:	48 8b bc 24 f8 00 00 00	movq	0xf8(%rsp), %rdi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     78c:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::__init__(unsafe_owned_ptr:::Pointer[::Bool(True), MutUntrackedOrigin, $0, *?, ::AddressSpace(::SIMDLength(0))]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     791:	48 89 84 24 e8 00 00 00	movq	%rax, 0xe8(%rsp)
     799:	48 8b 8c 24 b0 01 00 00	movq	0x1b0(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     7a1:	48 b8 00 00 00 00 00 00 00 80	movabsq	$-0x8000000000000000, %rax
     7ab:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     7ae:	48 83 f8 00	cmpq	$0x0, %rax
     7b2:	74 0f	je	0x7c3
     7b4:	b8 17 00 00 00	movl	$0x17, %eax
     7b9:	48 89 84 24 e0 00 00 00	movq	%rax, 0xe0(%rsp)
     7c1:	eb 60	jmp	0x823
     7c3:	48 8b 8c 24 b0 01 00 00	movq	0x1b0(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     7cb:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     7d5:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     7d8:	48 83 f8 00	cmpq	$0x0, %rax
     7dc:	0f 95 c0	setne	%al
     7df:	34 ff	xorb	$-0x1, %al
     7e1:	a8 01	testb	$0x1, %al
     7e3:	75 02	jne	0x7e7
     7e5:	eb 15	jmp	0x7fc
     7e7:	48 8b 84 24 a0 01 00 00	movq	0x1a0(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     7ef:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     7f2:	48 89 84 24 d8 00 00 00	movq	%rax, 0xd8(%rsp)
     7fa:	eb 17	jmp	0x813
     7fc:	48 8b 84 24 b0 01 00 00	movq	0x1b0(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     804:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     807:	48 c1 e0 03	shlq	$0x3, %rax
     80b:	48 89 84 24 d8 00 00 00	movq	%rax, 0xd8(%rsp)
     813:	48 8b 84 24 d8 00 00 00	movq	0xd8(%rsp), %rax
     81b:	48 89 84 24 e0 00 00 00	movq	%rax, 0xe0(%rsp)
     823:	48 8b 84 24 e0 00 00 00	movq	0xe0(%rsp), %rax
     82b:	48 89 84 24 d0 00 00 00	movq	%rax, 0xd0(%rsp)
     833:	48 8b bc 24 e8 00 00 00	movq	0xe8(%rsp), %rdi
     83b:	48 8b b4 24 d0 00 00 00	movq	0xd0(%rsp), %rsi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     843:	48 83 c6 08	addq	$0x8, %rsi
     847:	48 89 f0	movq	%rsi, %rax
     84a:	90	nop
     84b:	48 89 b4 24 90 04 00 00	movq	%rsi, 0x490(%rsp)
     853:	90	nop
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     854:	48 89 b4 24 98 04 00 00	movq	%rsi, 0x498(%rsp)
     85c:	48 c7 84 24 a0 04 00 00 01 00 00 00	movq	$0x1, 0x4a0(%rsp)
     868:	ba 01 00 00 00	movl	$0x1, %edx
     86d:	48 89 84 24 a8 04 00 00	movq	%rax, 0x4a8(%rsp)
     875:	48 c7 84 24 b0 04 00 00 01 00 00 00	movq	$0x1, 0x4b0(%rsp)
     881:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::unsafe_with_layout(::ThinAllocation[$0]$,::Layout[$0]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     886:	48 89 c7	movq	%rax, %rdi
     889:	48 89 d6	movq	%rdx, %rsi
     88c:	48 89 ca	movq	%rcx, %rdx
     88f:	e8 00 00 00 00	callq	"_std::memory::alloc::dealloc[::AnyType](::Allocation[$0]$),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     894:	eb 02	jmp	0x898
     896:	eb 00	jmp	0x898
     898:	eb 02	jmp	0x89c
     89a:	eb 00	jmp	0x89c
     89c:	48 8b 8c 24 98 01 00 00	movq	0x198(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     8a4:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     8ae:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     8b1:	48 83 f8 00	cmpq	$0x0, %rax
     8b5:	0f 84 92 01 00 00	je	0xa4d
     8bb:	48 8b 84 24 90 01 00 00	movq	0x190(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     8c3:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     8c6:	48 83 c0 f8	addq	$-0x8, %rax
     8ca:	48 89 84 24 c8 00 00 00	movq	%rax, 0xc8(%rsp)
     8d2:	48 89 84 24 98 03 00 00	movq	%rax, 0x398(%rsp)
     8da:	48 89 84 24 a0 03 00 00	movq	%rax, 0x3a0(%rsp)
     8e2:	90	nop
     8e3:	48 8b 8c 24 c8 00 00 00	movq	0xc8(%rsp), %rcx
     8eb:	48 c7 84 24 78 04 00 00 01 00 00 00	movq	$0x1, 0x478(%rsp)
     8f7:	48 89 8c 24 a8 03 00 00	movq	%rcx, 0x3a8(%rsp)
     8ff:	48 89 8c 24 80 04 00 00	movq	%rcx, 0x480(%rsp)
     907:	48 c7 c0 ff ff ff ff	movq	$-0x1, %rax
     90e:	f0	lock
     90f:	48 0f c1 01	xaddq	%rax, "_language_basics_minimal::main()"(%rcx)
     913:	48 89 84 24 88 04 00 00	movq	%rax, 0x488(%rsp)
     91b:	48 89 84 24 c0 00 00 00	movq	%rax, 0xc0(%rsp)
     923:	48 8b 84 24 c0 00 00 00	movq	0xc0(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     92b:	48 83 f8 01	cmpq	$0x1, %rax
     92f:	0f 85 14 01 00 00	jne	0xa49
     935:	eb 00	jmp	0x937
     937:	48 8b bc 24 c8 00 00 00	movq	0xc8(%rsp), %rdi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     93f:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::__init__(unsafe_owned_ptr:::Pointer[::Bool(True), MutUntrackedOrigin, $0, *?, ::AddressSpace(::SIMDLength(0))]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     944:	48 89 84 24 b8 00 00 00	movq	%rax, 0xb8(%rsp)
     94c:	48 8b 8c 24 98 01 00 00	movq	0x198(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     954:	48 b8 00 00 00 00 00 00 00 80	movabsq	$-0x8000000000000000, %rax
     95e:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     961:	48 83 f8 00	cmpq	$0x0, %rax
     965:	74 0f	je	0x976
     967:	b8 17 00 00 00	movl	$0x17, %eax
     96c:	48 89 84 24 b0 00 00 00	movq	%rax, 0xb0(%rsp)
     974:	eb 60	jmp	0x9d6
     976:	48 8b 8c 24 98 01 00 00	movq	0x198(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     97e:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     988:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     98b:	48 83 f8 00	cmpq	$0x0, %rax
     98f:	0f 95 c0	setne	%al
     992:	34 ff	xorb	$-0x1, %al
     994:	a8 01	testb	$0x1, %al
     996:	75 02	jne	0x99a
     998:	eb 15	jmp	0x9af
     99a:	48 8b 84 24 88 01 00 00	movq	0x188(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     9a2:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     9a5:	48 89 84 24 a8 00 00 00	movq	%rax, 0xa8(%rsp)
     9ad:	eb 17	jmp	0x9c6
     9af:	48 8b 84 24 98 01 00 00	movq	0x198(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     9b7:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     9ba:	48 c1 e0 03	shlq	$0x3, %rax
     9be:	48 89 84 24 a8 00 00 00	movq	%rax, 0xa8(%rsp)
     9c6:	48 8b 84 24 a8 00 00 00	movq	0xa8(%rsp), %rax
     9ce:	48 89 84 24 b0 00 00 00	movq	%rax, 0xb0(%rsp)
     9d6:	48 8b 84 24 b0 00 00 00	movq	0xb0(%rsp), %rax
     9de:	48 89 84 24 a0 00 00 00	movq	%rax, 0xa0(%rsp)
     9e6:	48 8b bc 24 b8 00 00 00	movq	0xb8(%rsp), %rdi
     9ee:	48 8b b4 24 a0 00 00 00	movq	0xa0(%rsp), %rsi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     9f6:	48 83 c6 08	addq	$0x8, %rsi
     9fa:	48 89 f0	movq	%rsi, %rax
     9fd:	90	nop
     9fe:	48 89 b4 24 90 04 00 00	movq	%rsi, 0x490(%rsp)
     a06:	90	nop
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     a07:	48 89 b4 24 98 04 00 00	movq	%rsi, 0x498(%rsp)
     a0f:	48 c7 84 24 a0 04 00 00 01 00 00 00	movq	$0x1, 0x4a0(%rsp)
     a1b:	ba 01 00 00 00	movl	$0x1, %edx
     a20:	48 89 84 24 a8 04 00 00	movq	%rax, 0x4a8(%rsp)
     a28:	48 c7 84 24 b0 04 00 00 01 00 00 00	movq	$0x1, 0x4b0(%rsp)
     a34:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::unsafe_with_layout(::ThinAllocation[$0]$,::Layout[$0]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     a39:	48 89 c7	movq	%rax, %rdi
     a3c:	48 89 d6	movq	%rdx, %rsi
     a3f:	48 89 ca	movq	%rcx, %rdx
     a42:	e8 00 00 00 00	callq	"_std::memory::alloc::dealloc[::AnyType](::Allocation[$0]$),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     a47:	eb 02	jmp	0xa4b
     a49:	eb 00	jmp	0xa4b
     a4b:	eb 02	jmp	0xa4f
     a4d:	eb 00	jmp	0xa4f
     a4f:	48 8b 8c 24 80 01 00 00	movq	0x180(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     a57:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     a61:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     a64:	48 83 f8 00	cmpq	$0x0, %rax
     a68:	0f 84 83 01 00 00	je	0xbf1
     a6e:	48 8b 84 24 78 01 00 00	movq	0x178(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     a76:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     a79:	48 83 c0 f8	addq	$-0x8, %rax
     a7d:	48 89 84 24 98 00 00 00	movq	%rax, 0x98(%rsp)
     a85:	48 89 84 24 b0 03 00 00	movq	%rax, 0x3b0(%rsp)
     a8d:	48 89 84 24 b8 03 00 00	movq	%rax, 0x3b8(%rsp)
     a95:	90	nop
     a96:	48 8b 8c 24 98 00 00 00	movq	0x98(%rsp), %rcx
     a9e:	48 c7 84 24 78 04 00 00 01 00 00 00	movq	$0x1, 0x478(%rsp)
     aaa:	48 89 8c 24 c0 03 00 00	movq	%rcx, 0x3c0(%rsp)
     ab2:	48 89 8c 24 80 04 00 00	movq	%rcx, 0x480(%rsp)
     aba:	48 c7 c0 ff ff ff ff	movq	$-0x1, %rax
     ac1:	f0	lock
     ac2:	48 0f c1 01	xaddq	%rax, "_language_basics_minimal::main()"(%rcx)
     ac6:	48 89 84 24 88 04 00 00	movq	%rax, 0x488(%rsp)
     ace:	48 89 84 24 90 00 00 00	movq	%rax, 0x90(%rsp)
     ad6:	48 8b 84 24 90 00 00 00	movq	0x90(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     ade:	48 83 f8 01	cmpq	$0x1, %rax
     ae2:	0f 85 05 01 00 00	jne	0xbed
     ae8:	eb 00	jmp	0xaea
     aea:	48 8b bc 24 98 00 00 00	movq	0x98(%rsp), %rdi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     af2:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::__init__(unsafe_owned_ptr:::Pointer[::Bool(True), MutUntrackedOrigin, $0, *?, ::AddressSpace(::SIMDLength(0))]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     af7:	48 89 84 24 88 00 00 00	movq	%rax, 0x88(%rsp)
     aff:	48 8b 8c 24 80 01 00 00	movq	0x180(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     b07:	48 b8 00 00 00 00 00 00 00 80	movabsq	$-0x8000000000000000, %rax
     b11:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     b14:	48 83 f8 00	cmpq	$0x0, %rax
     b18:	74 0f	je	0xb29
     b1a:	b8 17 00 00 00	movl	$0x17, %eax
     b1f:	48 89 84 24 80 00 00 00	movq	%rax, 0x80(%rsp)
     b27:	eb 57	jmp	0xb80
     b29:	48 8b 8c 24 80 01 00 00	movq	0x180(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     b31:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     b3b:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     b3e:	48 83 f8 00	cmpq	$0x0, %rax
     b42:	0f 95 c0	setne	%al
     b45:	34 ff	xorb	$-0x1, %al
     b47:	a8 01	testb	$0x1, %al
     b49:	75 02	jne	0xb4d
     b4b:	eb 12	jmp	0xb5f
     b4d:	48 8b 84 24 70 01 00 00	movq	0x170(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     b55:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     b58:	48 89 44 24 78	movq	%rax, 0x78(%rsp)
     b5d:	eb 14	jmp	0xb73
     b5f:	48 8b 84 24 80 01 00 00	movq	0x180(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     b67:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     b6a:	48 c1 e0 03	shlq	$0x3, %rax
     b6e:	48 89 44 24 78	movq	%rax, 0x78(%rsp)
     b73:	48 8b 44 24 78	movq	0x78(%rsp), %rax
     b78:	48 89 84 24 80 00 00 00	movq	%rax, 0x80(%rsp)
     b80:	48 8b 84 24 80 00 00 00	movq	0x80(%rsp), %rax
     b88:	48 89 44 24 70	movq	%rax, 0x70(%rsp)
     b8d:	48 8b bc 24 88 00 00 00	movq	0x88(%rsp), %rdi
     b95:	48 8b 74 24 70	movq	0x70(%rsp), %rsi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     b9a:	48 83 c6 08	addq	$0x8, %rsi
     b9e:	48 89 f0	movq	%rsi, %rax
     ba1:	90	nop
     ba2:	48 89 b4 24 90 04 00 00	movq	%rsi, 0x490(%rsp)
     baa:	90	nop
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     bab:	48 89 b4 24 98 04 00 00	movq	%rsi, 0x498(%rsp)
     bb3:	48 c7 84 24 a0 04 00 00 01 00 00 00	movq	$0x1, 0x4a0(%rsp)
     bbf:	ba 01 00 00 00	movl	$0x1, %edx
     bc4:	48 89 84 24 a8 04 00 00	movq	%rax, 0x4a8(%rsp)
     bcc:	48 c7 84 24 b0 04 00 00 01 00 00 00	movq	$0x1, 0x4b0(%rsp)
     bd8:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::unsafe_with_layout(::ThinAllocation[$0]$,::Layout[$0]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     bdd:	48 89 c7	movq	%rax, %rdi
     be0:	48 89 d6	movq	%rdx, %rsi
     be3:	48 89 ca	movq	%rcx, %rdx
     be6:	e8 00 00 00 00	callq	"_std::memory::alloc::dealloc[::AnyType](::Allocation[$0]$),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     beb:	eb 02	jmp	0xbef
     bed:	eb 00	jmp	0xbef
     bef:	eb 02	jmp	0xbf3
     bf1:	eb 00	jmp	0xbf3
     bf3:	48 8b 8c 24 68 01 00 00	movq	0x168(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     bfb:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     c05:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     c08:	48 83 f8 00	cmpq	$0x0, %rax
     c0c:	0f 84 65 01 00 00	je	0xd77
     c12:	48 8b 84 24 60 01 00 00	movq	0x160(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     c1a:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     c1d:	48 83 c0 f8	addq	$-0x8, %rax
     c21:	48 89 44 24 68	movq	%rax, 0x68(%rsp)
     c26:	48 89 84 24 c8 03 00 00	movq	%rax, 0x3c8(%rsp)
     c2e:	48 89 84 24 d0 03 00 00	movq	%rax, 0x3d0(%rsp)
     c36:	90	nop
     c37:	48 8b 4c 24 68	movq	0x68(%rsp), %rcx
     c3c:	48 c7 84 24 78 04 00 00 01 00 00 00	movq	$0x1, 0x478(%rsp)
     c48:	48 89 8c 24 d8 03 00 00	movq	%rcx, 0x3d8(%rsp)
     c50:	48 89 8c 24 80 04 00 00	movq	%rcx, 0x480(%rsp)
     c58:	48 c7 c0 ff ff ff ff	movq	$-0x1, %rax
     c5f:	f0	lock
     c60:	48 0f c1 01	xaddq	%rax, "_language_basics_minimal::main()"(%rcx)
     c64:	48 89 84 24 88 04 00 00	movq	%rax, 0x488(%rsp)
     c6c:	48 89 44 24 60	movq	%rax, 0x60(%rsp)
     c71:	48 8b 44 24 60	movq	0x60(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     c76:	48 83 f8 01	cmpq	$0x1, %rax
     c7a:	0f 85 f3 00 00 00	jne	0xd73
     c80:	eb 00	jmp	0xc82
     c82:	48 8b 7c 24 68	movq	0x68(%rsp), %rdi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     c87:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::__init__(unsafe_owned_ptr:::Pointer[::Bool(True), MutUntrackedOrigin, $0, *?, ::AddressSpace(::SIMDLength(0))]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     c8c:	48 89 44 24 58	movq	%rax, 0x58(%rsp)
     c91:	48 8b 8c 24 68 01 00 00	movq	0x168(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     c99:	48 b8 00 00 00 00 00 00 00 80	movabsq	$-0x8000000000000000, %rax
     ca3:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     ca6:	48 83 f8 00	cmpq	$0x0, %rax
     caa:	74 0c	je	0xcb8
     cac:	b8 17 00 00 00	movl	$0x17, %eax
     cb1:	48 89 44 24 50	movq	%rax, 0x50(%rsp)
     cb6:	eb 54	jmp	0xd0c
     cb8:	48 8b 8c 24 68 01 00 00	movq	0x168(%rsp), %rcx
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     cc0:	48 b8 00 00 00 00 00 00 00 40	movabsq	$0x4000000000000000, %rax
     cca:	48 23 01	andq	"_language_basics_minimal::main()"(%rcx), %rax
     ccd:	48 83 f8 00	cmpq	$0x0, %rax
     cd1:	0f 95 c0	setne	%al
     cd4:	34 ff	xorb	$-0x1, %al
     cd6:	a8 01	testb	$0x1, %al
     cd8:	75 02	jne	0xcdc
     cda:	eb 12	jmp	0xcee
     cdc:	48 8b 84 24 58 01 00 00	movq	0x158(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     ce4:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     ce7:	48 89 44 24 48	movq	%rax, 0x48(%rsp)
     cec:	eb 14	jmp	0xd02
     cee:	48 8b 84 24 68 01 00 00	movq	0x168(%rsp), %rax
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     cf6:	48 8b 00	movq	"_language_basics_minimal::main()"(%rax), %rax
     cf9:	48 c1 e0 03	shlq	$0x3, %rax
     cfd:	48 89 44 24 48	movq	%rax, 0x48(%rsp)
     d02:	48 8b 44 24 48	movq	0x48(%rsp), %rax
     d07:	48 89 44 24 50	movq	%rax, 0x50(%rsp)
     d0c:	48 8b 44 24 50	movq	0x50(%rsp), %rax
     d11:	48 89 44 24 40	movq	%rax, 0x40(%rsp)
     d16:	48 8b 7c 24 58	movq	0x58(%rsp), %rdi
     d1b:	48 8b 74 24 40	movq	0x40(%rsp), %rsi
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     d20:	48 83 c6 08	addq	$0x8, %rsi
     d24:	48 89 f0	movq	%rsi, %rax
     d27:	90	nop
     d28:	48 89 b4 24 90 04 00 00	movq	%rsi, 0x490(%rsp)
     d30:	90	nop
;     print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))
     d31:	48 89 b4 24 98 04 00 00	movq	%rsi, 0x498(%rsp)
     d39:	48 c7 84 24 a0 04 00 00 01 00 00 00	movq	$0x1, 0x4a0(%rsp)
     d45:	ba 01 00 00 00	movl	$0x1, %edx
     d4a:	48 89 84 24 a8 04 00 00	movq	%rax, 0x4a8(%rsp)
     d52:	48 c7 84 24 b0 04 00 00 01 00 00 00	movq	$0x1, 0x4b0(%rsp)
     d5e:	e8 00 00 00 00	callq	"_std::memory::alloc::ThinAllocation::unsafe_with_layout(::ThinAllocation[$0]$,::Layout[$0]),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     d63:	48 89 c7	movq	%rax, %rdi
     d66:	48 89 d6	movq	%rdx, %rsi
     d69:	48 89 ca	movq	%rcx, %rdx
     d6c:	e8 00 00 00 00	callq	"_std::memory::alloc::dealloc[::AnyType](::Allocation[$0]$),T=[typevalue<#kgen.instref<\"std::builtin::simd::SIMD,dtype=ui8,length=1\">>, scalar<ui8>]"
     d71:	eb 02	jmp	0xd75
     d73:	eb 00	jmp	0xd75
     d75:	eb 02	jmp	0xd79
     d77:	eb 00	jmp	0xd79
; def main():
     d79:	48 81 c4 b8 04 00 00	addq	$0x4b8, %rsp
     d80:	c3	retq
     d81:	66 2e 0f 1f 84 00 00 00 00 00	nopw	%cs:"_language_basics_minimal::main()"(%rax,%rax)
     d8b:	0f 1f 44 00 00	nopl	(%rax,%rax)

リスト7-2: language_basics_minimal.asm

7.3 リスト7-2 を段階的に読む

全体を段階的に解説します。 オフセットや命令列は、手元の objdump 結果と Mojo / LLVM の版によってわずかに変わり得ますが、リスト7-2 のダンプを前提に読み進めてください。 ニモニックは第5章 最小サンプル main のアセンブリを読む と同様に AT&T 記法です。

7.3.1 関数プロローグ

0: subq $0x4b8, %rsp

スタックに 1208 バイト0x4b8)を確保します。 第5章 最小サンプル main のアセンブリを読む296 バイトより大きいのは、複数の変数、文字列オブジェクト、引数用テーブルを すべてスタック上に載せるためです。

7.3.2 変数の初期化(コンパイル時定数の最適化)

; var n: Int = 42
7: movq $0x2a, 0x1e8(%rsp)

; var doubled = n * 2
13: movq $0x54, 0x1f0(%rsp)

注目点は、n * 2 の計算が コンパイル時に完了 していることです。 42 * 2 = 84 がそのまま即値として埋め込まれており、実行時に乗算命令は一切発生しません。 Mojo コンパイラ(LLVM)の 定数畳み込み最適化です。

7.3.3 List[Int] = [1, 2, 3] の構築

; 要素をスタックに配置
1f: movq $0x1, 0x1f8(%rsp)
2b: movq $0x2, 0x200(%rsp)
37: movq $0x3, 0x208(%rsp)

まず 3 つの整数をスタック上に並べます。

; 各要素へのポインタのテーブル(末尾から逆順に組み立て)
43: leaq 0x208(%rsp), %rax
4b: movq %rax, 0x220(%rsp)  ; &xs[2]
53: leaq 0x200(%rsp), %rax
5b: movq %rax, 0x218(%rsp)  ; &xs[1]
63: leaq 0x1f8(%rsp), %rax
6b: movq %rax, 0x210(%rsp)  ; &xs[0]

74: leaq 0x210(%rsp), %rax  ; ポインタテーブルの先頭(xs[0])
...
118: movl $0x3, %edi         ; 要素数 = 3

要素アドレスのテーブルを 末尾(xs[2])から逆順に組み立て、最後にテーブル先頭(xs[0])のアドレスを他のレジスタへ複製します。 Mojo の List は、内部で 要素を指すポインタ列を持つ形としてコードが生成されます。

List[Int] = [1, 2, 3] の構築プロセス

図7-1: List[Int] = [1, 2, 3] の構築プロセス(要素配置 → ポインタテーブル → 関数呼び出し)

7.3.4 List 構築(内部関数呼び出し)

List[Int] = [1, 2, 3] のリテラル構築は、アセンブリ上で次の関数呼び出し列として現れます。

135: callq "_std::collections::list::List::__init__(capacity:...),T=[...]"
        ; List のメモリ確保
14a: callq "_std::collections::list::List::_annotate_increase(::List[$0],...),T=[...]"
        ; 容量アノテーション(3 要素分)
167: callq "_std::collections::list::List::__init__[...]::init_elt::__storage::__init__(...)"
        ; 要素転送用の一時ハンドル(storage)を初期化
184: callq "_std::collections::list::def[T: Movable, //](idx: Int, var elt: T) -> None{1}_3::__init__(...)"
        ; 要素を 1 つずつ受け渡すための内部クロージャを初期化
1a1: callq "_std::builtin::variadics::VariadicList::consume_elements[...]"
        ; 実際の要素の格納
1ae: callq "_std::collections::list::def[...]::__deinit__(...)"
        ; 転送用クロージャの後始末

各呼び出しが何をするか、順に見ていきます。

List::__init__(capacity:)

List オブジェクト本体をヒープ上に確保します。 capacity として要素数(ここでは 3)が渡され、その分のメモリ領域を用意します。 この時点ではまだ要素は入っていません。

List::_annotate_increase(list, n)

確保済みの List に対して「要素が n 個増える」と知らせるアノテーション呼び出しです。 内部の size カウンタを更新し、List が「3 要素を持っている」状態になります。 実際の要素の中身はまだ移動していません。

③〜⑤ 要素転送用クロージャの初期化・実行・後始末

Mojo 1.0.0 では、consume_elements で要素を一括転送する前後に、転送作業を担う一時的な内部クロージャinit_elt)の初期化(③)と後始末(⑤)が挟まるようになりました。 これは要素の所有権を安全に移動させるための足場で、旧バージョンにはなかった呼び出しです。

VariadicList::consume_elements(...)

7.3.3 で構築したポインタテーブル(各要素 1, 2, 3 へのアドレス列)を受け取り、実際に List の内部バッファへ要素を転送します。 この呼び出しで初めて [1, 2, 3] という値が List の中に収まります。

Python では [1, 2, 3] と書くだけでリストが作られますが、Mojo ではコンパイラがこれらの段階に展開します。 「どこに置くか(スタック上の要素配置)→ どれだけ入るか(メモリ確保・容量宣言)→ 転送用の足場を用意する → 実際に移す(転送)→ 足場を片付ける」という順序は、安全なメモリ管理のために必要な手順です。

7.3.5 String("count") の構築

第5章 最小サンプル main のアセンブリを読むHello, Mojo と同型です。 文字列オブジェクトは データポインタ、長さ、タグビット、関数ポインタ 2 本 というワード列でスタック上に現れます。 "count" 以降の "n="" sum=" なども、同じレイアウトで繰り返し構築されます。

文字列オブジェクトの構築

図7-2: 文字列オブジェクトの構築(第5章より再掲)

7.3.6 print() の引数構築と呼び出し

print(String("n="), n, String(" sum="), doubled, String(" "), label, String("="), len(xs))

x86-64 System V ABI では引数を rdirsirdxrcxr8r9 の順に 6 本のレジスタで渡し、7 番目以降はスタックに積みます。 String はオブジェクトのアドレス(leaq)、Int は値そのもの(movq)として渡します。 8 引数の振り分けは次のとおりです。

順序

引数

渡し方

レジスタ / 場所

1

String("n=")

String

アドレス(leaq

rdi

2

n

Int

値(movq

rsi

3

String(" sum=")

String

アドレス(leaq

rdx

4

doubled

Int

値(movq

rcx

5

String(" ")

String

アドレス(leaq

r8

6

label

String

アドレス(leaq

r9

7

String("=")

String

アドレス → スタック

0x0(%rax)callq 直前の rax = rsp

8

len(xs)

Int

値 → スタック

0x8(%rax)

新規 String 4 本の構築 は 7.3.5 と同じ手順でスタック上に行われます。

アドレス範囲(目安)

構築している文字列

長さ

234297

"n="

2

297316

" sum="

5

316391

" "

1

3913c9

"="

1

len(xs) と List の早期解放 がこの節で注目すべき点です。 len(xs)xs への最後のアクセスです。 Mojo コンパイラはこれを検出し、①値を退避 → ② List::__deinit__ で即解放 → ③退避値を print() に渡す、という手順を取ります。 xs のメモリは print() を待たずに返却されます。 これが Mojo のスコープ最適化で、Python の GC と違い解放タイミングがコンパイル時に確定します。

3c9: movq 0x258(%rsp), %rax    ; xs の要素数を取得
3d1: movq %rax, 0x1d8(%rsp)    ; 値を退避
3d9: callq "List::__deinit__(...)"   ; xs を解放(print より前!)

引数のレジスタ設定とスタック配置callq 直前の命令群で行われます。 コンパイラは第1引数から順ではなく最適な順序で命令を並べます。

; Int 値をレジスタへ
4b5: movq 0x1e8(%rsp), %rsi   ; n = 42 → rsi(第2引数)
4bd: movq 0x1f0(%rsp), %rcx   ; doubled = 84 → rcx(第4引数)

; rax = rsp を基点に 7・8 番目をスタックへ配置
4cc: movq %rsp, %rax
4e6: movq %rdx, 0x8(%rax)     ; len(xs)(3e6 で退避した値)→ 0x8(%rax)(第8引数)
4ea: leaq 0x318(%rsp), %rdx
4f2: movq %rdx, (%rax)        ; &String("=") → 0x0(%rax)(第7引数)

; String アドレスをレジスタへ
514: leaq 0x2a0(%rsp), %rdi   ; String("n=") → rdi(第1引数)
51c: leaq 0x2c8(%rsp), %rdx   ; String(" sum=") → rdx(第3引数)
524: leaq 0x2f0(%rsp), %r8    ; String(" ") → r8(第5引数)
52c: leaq 0x278(%rsp), %r9    ; label → r9(第6引数)
534: callq "print(...)"

callq が return address を積むと rsp が 8 下がるため、呼び出し先からは 0x8(%rsp) = 第7引数、0x10(%rsp) = 第8引数として参照されます。

7.3.7 エラーチェックとデストラクタ処理(5 回繰り返し)

print() のあと、スタック上に作った文字列オブジェクトごとに、第1部第5章と同型の 後片付けパターンが繰り返されます(リスト上は次の開始位置から現れます)。

  • 555String("n=")

  • 6e9String(" sum=")

  • 89cString(" ")

  • a4fString("count")

  • bf3String("=")

各ブロックの内部でも、第1部第5章で見た「参照カウントのデクリメント」に続いて、ThinAllocation::__init__ → Layout の算出(アライメント確認と shlq $0x3 による要素サイズ計算) → ThinAllocation::unsafe_with_layoutdealloc という、1.0.0 の Layout ベースの解放経路(第5章 最小サンプル main のアセンブリを読む 5.9 節参照)を通ります。

各ブロックは、おおむね次の骨格です。

文字列オブジェクトの後片付けパターン

図7-3: 文字列オブジェクトの後片付けパターン(①〜⑤、5 回繰り返し)

同じ形が 5 回分 繰り返されるため、コードが非常に長くなります。

7.3.8 関数エピローグ

d79: addq $0x4b8, %rsp      ; スタック解放(1208 バイト)
d80: retq                   ; 呼び出し元へ戻る
d81: 66 2e 0f 1f 84 00 ...  ; nopw(マルチバイト NOP、アライメント用パディング)
d8b: 0f 1f 44 00 00         ; nopl(同上)

末尾のマルチバイト NOP は、次の関数の先頭を特定のバイト境界に合わせるためのパディングです。

7.3.9 全体の流れ(まとめ)

7.3.1〜7.3.8 で見てきた各ステップを概観します。 左側の注釈(定数畳み込み、List は複数段階の内部呼び出しで構築、スコープ最適化、後片付けパターン繰り返し)が、この章を通じて押さえてきたポイントです。

language_basics_minimal.mojo の実行フロー全体

図7-4: language_basics_minimal.mojo の実行フロー全体(STEP 1〜9)

第5章 最小サンプル main のアセンブリを読むHello, Mojo と比べると、同じ「文字列を組み立てる → 後片付けする」パターンが、引数の数だけ機械的に繰り返される点が大きな違いです。 Mojo が 文字列リテラルを含む引数ごとに独立したオブジェクトとして扱い、それぞれ参照カウントで管理する様子が、ダンプから追いやすくなっています。