性能検証

本項では、実際に生成されるコードを元に、性能検証を行います。

コンパイル結果のコード品質検証

やはり一番気になるのは性能面です。

VC++6.0 にて、コンパイルオプション /FAcs を指定してコンパイルを行い、 いくつかのケースでどのようなアセンブリコードが生成されるかを追跡してみました。

検証 1) 加算

▼ 検証用コード
	{
	    Vec4_t vecA(0,0,0,0);
	    Vec4_t vecB(1,2,3,4);
	    Vec4_t vecC(5,6,7,8);

	    int i ;
	    for( i=0 ; i<10000 ; i++ ){
	        vecA.xyzw() += vecB.xyzw() + vecC.xyzw() ;
	    }

	    test(
	        "   %f %f %f %f \n"
	    ,   vecA.x()
	    ,   vecA.y()
	    ,   vecA.z()
	    ,   vecA.w()
	    );
	}
▼ コンパイル結果
; 50   : 		{
; 51   : 			Vec4_t vecA(0,0,0,0);

  00014	d9 05 00 00 00
	00		 fld	 DWORD PTR __real@4@00000000000000000000
  0001a	83 c4 04	 add	 esp, 4
  0001d	c7 44 24 14 00
	00 00 00	 mov	 DWORD PTR _vecA$55484[esp+36], 0
  00025	c7 44 24 18 00
	00 00 00	 mov	 DWORD PTR _vecA$55484[esp+40], 0
  0002d	c7 44 24 1c 00
	00 00 00	 mov	 DWORD PTR _vecA$55484[esp+44], 0
  00035	b8 10 27 00 00	 mov	 eax, 10000		; 00002710H
$L55488:

; 52   : 			Vec4_t vecB(1,2,3,4);
; 53   : 			Vec4_t vecC(5,6,7,8);
; 54   : 
; 55   : 			int	i ;
; 56   : 			for( i=0 ; i<10000 ; i++ ){
; 57   : 				vecA.xyzw() += vecB.xyzw() + vecC.xyzw() ;

  0003a	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@4001c000000000000000
  00040	48		 dec	 eax
  00041	d9 54 24 00	 fst	 DWORD PTR _Result$57109[esp+32]
  00045	d9 44 24 14	 fld	 DWORD PTR _vecA$55484[esp+36]
  00049	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@40028000000000000000
  0004f	d9 5c 24 04	 fstp	 DWORD PTR _Result$57109[esp+36]
  00053	d9 44 24 18	 fld	 DWORD PTR _vecA$55484[esp+40]
  00057	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@4002a000000000000000
  0005d	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$57109[esp+36]
  00061	89 4c 24 14	 mov	 DWORD PTR _vecA$55484[esp+36], ecx
  00065	d9 5c 24 08	 fstp	 DWORD PTR _Result$57109[esp+40]
  00069	d9 44 24 1c	 fld	 DWORD PTR _vecA$55484[esp+44]
  0006d	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@4002c000000000000000
  00073	8b 54 24 08	 mov	 edx, DWORD PTR _Result$57109[esp+40]
  00077	89 54 24 18	 mov	 DWORD PTR _vecA$55484[esp+40], edx
  0007b	d9 5c 24 0c	 fstp	 DWORD PTR _Result$57109[esp+44]
  0007f	8b 4c 24 0c	 mov	 ecx, DWORD PTR _Result$57109[esp+44]
  00083	89 4c 24 1c	 mov	 DWORD PTR _vecA$55484[esp+44], ecx
  00087	75 b1		 jne	 SHORT $L55488

; 58   : 			}
; 59   : 
; 60   : 			test(
; 61   : 				"	%f %f %f %f \n"
; 62   : 			,	vecA.x()
; 63   : 			,	vecA.y()
; 64   : 			,	vecA.z()
; 65   : 			,	vecA.w()
; 66   : 			);

  00089	8b 44 24 08	 mov	 eax, DWORD PTR _Result$57109[esp+40]
  0008d	8b d1		 mov	 edx, ecx
  0008f	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$57109[esp+36]
  00093	52		 push	 edx
  00094	8b 54 24 04	 mov	 edx, DWORD PTR _Result$57109[esp+36]
  00098	50		 push	 eax
  00099	51		 push	 ecx
  0009a	52		 push	 edx
  0009b	68 00 00 00 00	 push	 OFFSET FLAT:??_C@_0P@HMKC@?7?...
  000a0	dd d8		 fstp	 ST(0)
  000a2	e8 00 00 00 00	 call	 ?test@@YAXPBDMMMM@Z	; test

; 67   : 		}
vecB , vecC の存在自体が最適化により消滅し、 vecB + vecC の結果が vecA に足しこまれる様子が確認できます。

検証 2) スカラ三重積

▼ 検証用コード
	{
	    Vec4_t  vecA(1,0,0,0);
	    Vec4_t  vecB(0,1,0,0);
	    Vec4_t  vecC(0,0,1,0);

	    float Temp = 0 ;

	    int i ;
	    for( i=0 ; i<10000 ; i++ ){
	        Temp += Dot( Cross( vecA.xyz() , vecB.xyz() ) , vecC.xyz() );
	    }

	    test(
	        "   %f \n"
	    ,   Temp
	    );
	}
▼ コンパイル結果
; 69   : 		{
; 70   : 			Vec4_t	vecA(1,0,0,0);
; 71   : 			Vec4_t	vecB(0,1,0,0);
; 72   : 			Vec4_t	vecC(0,0,1,0);
; 73   : 
; 74   : 			float Temp = 0 ;

  000a7	d9 05 00 00 00
	00		 fld	 DWORD PTR __real@4@00000000000000000000
  000ad	83 c4 14	 add	 esp, 20			; 00000014H
  000b0	b8 10 27 00 00	 mov	 eax, 10000		; 00002710H
$L55506:

; 75   : 
; 76   : 			int	i ;
; 77   : 			for( i=0 ; i<10000 ; i++ ){
; 78   : 				Temp += Dot( Cross( vecA.xyz() , vecB.xyz() ) , vecC.xyz() );

  000b5	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@3fff8000000000000000
  000bb	48		 dec	 eax
  000bc	75 f7		 jne	 SHORT $L55506
  000be	d9 5c 24 24	 fstp	 DWORD PTR _Temp$55504[esp+28]

; 79   : 			}
; 80   : 
; 81   : 			test(
; 82   : 				"	%f \n"
; 83   : 			,	Temp
; 84   : 			);

  000c2	8b 44 24 24	 mov	 eax, DWORD PTR _Temp$55504[esp+28]
  000c6	6a 00		 push	 0
  000c8	6a 00		 push	 0
  000ca	6a 00		 push	 0
  000cc	50		 push	 eax
  000cd	68 00 00 00 00	 push	 OFFSET FLAT:??_C@_05EEJL@?7?...
  000d2	e8 00 00 00 00	 call	 ?test@@YAXPBDMMMM@Z	; test

; 85   : 		}
vecA , vecB , vecC の存在自体が最適化により消滅し、 結果だけが Temp に足しこまれる様子が確認できます。

検証 3) ベクトルと行列の乗算

▼ 検証用コード
	{
	    float ParamA[4][4] = {
	        { 1, 2, 3, 4}
	    ,   { 5, 6, 7, 8}
	    ,   { 9,10,11,12}
	    ,   {13,14,15,16}
	    };
	    Mat4x4_t    matA( ParamA );

	    float ParamB[4][4] = {
	        {17,18,19,20}
	    ,   {21,22,23,24}
	    ,   {25,26,27,28}
	    ,   {29,30,31,32}
	    };
	    Mat4x4_t    matB( ParamB );

	    Vec4_t  vecB(1,2,3,4);
	    Vec4_t  vecA(0,0,0,0);

	    int i ;
	    for( i=0 ; i<10000 ; i++ ){
	        vecA += vecB * (matA * matB) ;
	    }

	    test(
	        "   %f %f %f %f \n"
	    ,   vecA.x()
	    ,   vecA.y()
	    ,   vecA.z()
	    ,   vecA.w()
	    );
	}
▼ コンパイル結果
; 89   : 		{
; 90   : 			float ParamA[4][4] = {
; 91   : 				{ 1, 2, 3, 4}
; 92   : 			,	{ 5, 6, 7, 8}
; 93   : 			,	{ 9,10,11,12}
; 94   : 			,	{13,14,15,16}
; 95   : 			};
; 96   : 			Mat4x4_t	matA( ParamA );
; 97   : 
; 98   : 			float ParamB[4][4] = {
; 99   : 				{17,18,19,20}
; 100  : 			,	{21,22,23,24}
; 101  : 			,	{25,26,27,28}
; 102  : 			,	{29,30,31,32}
; 103  : 			};
; 104  : 			Mat4x4_t	matB( ParamB );
; 105  : 
; 106  : 			Vec4_t	vecB(1,2,3,4);
; 107  : 			Vec4_t	vecA(0,0,0,0);

  000d7	d9 05 00 00 00
	00		 fld	 DWORD PTR __real@4@00000000000000000000
  000dd	83 c4 14	 add	 esp, 20			; 00000014H
  000e0	c7 44 24 14 00
	00 00 00	 mov	 DWORD PTR _vecA$55528[esp+36], 0
  000e8	c7 44 24 18 00
	00 00 00	 mov	 DWORD PTR _vecA$55528[esp+40], 0
  000f0	c7 44 24 1c 00
	00 00 00	 mov	 DWORD PTR _vecA$55528[esp+44], 0
  000f8	b8 10 27 00 00	 mov	 eax, 10000		; 00002710H
$L55530:

; 108  : 
; 109  : 			int	i ;
; 110  : 			for( i=0 ; i<10000 ; i++ ){
; 111  : 				vecA += vecB * (matA * matB) ;

  000fd	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@400c9a10000000000000
  00103	48		 dec	 eax
  00104	d9 54 24 00	 fst	 DWORD PTR _Result$83206[esp+32]
  00108	d9 44 24 14	 fld	 DWORD PTR _vecA$55528[esp+36]
  0010c	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@400ca0a0000000000000
  00112	d9 5c 24 04	 fstp	 DWORD PTR _Result$83206[esp+36]
  00116	d9 44 24 18	 fld	 DWORD PTR _vecA$55528[esp+40]
  0011a	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@400ca730000000000000
  00120	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$83206[esp+36]
  00124	89 4c 24 14	 mov	 DWORD PTR _vecA$55528[esp+36], ecx
  00128	d9 5c 24 08	 fstp	 DWORD PTR _Result$83206[esp+40]
  0012c	d9 44 24 1c	 fld	 DWORD PTR _vecA$55528[esp+44]
  00130	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@400cadc0000000000000
  00136	8b 54 24 08	 mov	 edx, DWORD PTR _Result$83206[esp+40]
  0013a	89 54 24 18	 mov	 DWORD PTR _vecA$55528[esp+40], edx
  0013e	d9 5c 24 0c	 fstp	 DWORD PTR _Result$83206[esp+44]
  00142	8b 4c 24 0c	 mov	 ecx, DWORD PTR _Result$83206[esp+44]
  00146	89 4c 24 1c	 mov	 DWORD PTR _vecA$55528[esp+44], ecx
  0014a	75 b1		 jne	 SHORT $L55530

; 112  : 			}
; 113  : 
; 114  : 			test(
; 115  : 				"	%f %f %f %f \n"
; 116  : 			,	vecA.x()
; 117  : 			,	vecA.y()
; 118  : 			,	vecA.z()
; 119  : 			,	vecA.w()
; 120  : 			);

  0014c	8b 44 24 08	 mov	 eax, DWORD PTR _Result$83206[esp+40]
  00150	8b d1		 mov	 edx, ecx
  00152	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$83206[esp+36]
  00156	52		 push	 edx
  00157	8b 54 24 04	 mov	 edx, DWORD PTR _Result$83206[esp+36]
  0015b	50		 push	 eax
  0015c	51		 push	 ecx
  0015d	52		 push	 edx
  0015e	68 00 00 00 00	 push	 OFFSET FLAT:??_C@_0P@HMKC@?7?...
  00163	dd d8		 fstp	 ST(0)
  00165	e8 00 00 00 00	 call	 ?test@@YAXPBDMMMM@Z	; test

; 121  : 		}
vecB matA matB の存在自体が最適化により消滅し、 結果だけが matA に足しこまれる様子が確認できます。

検証 4) ベクトルと行列の乗算(検証 3 よりも複雑)

▼ 検証用コード
	{
	    float ParamA[4][4] = {
	        { 1, 2, 3, 4}
	    ,   { 5, 6, 7, 8}
	    ,   { 9,10,11,12}
	    ,   {13,14,15,16}
	    };
	    Mat4x4_t    matA( ParamA );

	    float ParamB[4][4] = {
	        {17,18,19,20}
	    ,   {21,22,23,24}
	    ,   {25,26,27,28}
	    ,   {29,30,31,32}
	    };
	    Mat4x4_t    matB( ParamB );

	    Vec4_t  vecB(1,2,3,4);
	    Vec4_t  vecA(0,0,0,0);

	    int i ;
	    for( i=0 ; i<10000 ; i++ ){
	        vecA += vecB * (matA * matB * matA * matB * matA) ;
	    }

	    test(
	        "   %f %f %f %f \n"
	    ,   vecA.x()
	    ,   vecA.y()
	    ,   vecA.z()
	    ,   vecA.w()
	    );
	}
▼ コンパイル結果
; 124  : 		{
; 125  : 			float ParamA[4][4] = {
; 126  : 				{ 1, 2, 3, 4}
; 127  : 			,	{ 5, 6, 7, 8}
; 128  : 			,	{ 9,10,11,12}
; 129  : 			,	{13,14,15,16}
; 130  : 			};
; 131  : 			Mat4x4_t	matA( ParamA );
; 132  : 
; 133  : 			float ParamB[4][4] = {
; 134  : 				{17,18,19,20}
; 135  : 			,	{21,22,23,24}
; 136  : 			,	{25,26,27,28}
; 137  : 			,	{29,30,31,32}
; 138  : 			};
; 139  : 			Mat4x4_t	matB( ParamB );
; 140  : 
; 141  : 			Vec4_t	vecB(1,2,3,4);
; 142  : 			Vec4_t	vecA(0,0,0,0);

  0001a	d9 05 00 00 00
	00		 fld	 DWORD PTR __real@4@00000000000000000000
  00020	83 c4 04	 add	 esp, 4
  00023	c7 84 24 20 02
	00 00 00 00 80
	3f		 mov	 DWORD PTR _ParamA$55484[esp+800], 1065353216 ; 3f800000H
  0002e	c7 84 24 24 02
	00 00 00 00 00
	40		 mov	 DWORD PTR _ParamA$55484[esp+804], 1073741824 ; 40000000H
  00039	c7 84 24 28 02
	00 00 00 00 40

	(中略)

; 143  : 
; 144  : 			int	i ;
; 145  : 			for( i=0 ; i<10000 ; i++ ){
; 146  : 				vecA += vecB * (matA * matB * matA * matB * matA) ;

  002fb	c7 44 24 20 00
	00 7a 43	 mov	 DWORD PTR _Result$75224[esp+800], 1132068864 ; 437a0000H
  00303	c7 44 24 24 00
	00 82 43	 mov	 DWORD PTR _Result$75224[esp+804], 1132593152 ; 43820000H
  0030b	c7 44 24 28 00


	(中略)


  00833	b8 10 27 00 00	 mov	 eax, 10000		; 00002710H
$L55491:
  00838	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@401cfb651e8000000000
  0083e	48		 dec	 eax
  0083f	d9 54 24 00	 fst	 DWORD PTR _Result$140642[esp+800]
  00843	d9 44 24 14	 fld	 DWORD PTR _vecA$55489[esp+804]
  00847	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@401d8f282c8000000000
  0084d	d9 5c 24 04	 fstp	 DWORD PTR _Result$140642[esp+804]
  00851	d9 44 24 18	 fld	 DWORD PTR _vecA$55489[esp+808]
  00855	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@401da09dc9c000000000
  0085b	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$140642[esp+804]
  0085f	89 4c 24 14	 mov	 DWORD PTR _vecA$55489[esp+804], ecx
  00863	d9 5c 24 08	 fstp	 DWORD PTR _Result$140642[esp+808]
  00867	d9 44 24 1c	 fld	 DWORD PTR _vecA$55489[esp+812]
  0086b	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@401db213670000000000
  00871	8b 54 24 08	 mov	 edx, DWORD PTR _Result$140642[esp+808]
  00875	89 54 24 18	 mov	 DWORD PTR _vecA$55489[esp+808], edx
  00879	d9 5c 24 0c	 fstp	 DWORD PTR _Result$140642[esp+812]
  0087d	8b 4c 24 0c	 mov	 ecx, DWORD PTR _Result$140642[esp+812]
  00881	89 4c 24 1c	 mov	 DWORD PTR _vecA$55489[esp+812], ecx
  00885	75 b1		 jne	 SHORT $L55491

; 147  : 			}
; 148  : 
; 149  : 			test(
; 150  : 				"	%f %f %f %f \n"
; 151  : 			,	vecA.x()
; 152  : 			,	vecA.y()
; 153  : 			,	vecA.z()
; 154  : 			,	vecA.w()
; 155  : 			);

  00887	8b 44 24 08	 mov	 eax, DWORD PTR _Result$140642[esp+808]
  0088b	8b d1		 mov	 edx, ecx
  0088d	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$140642[esp+804]
  00891	52		 push	 edx
  00892	8b 54 24 04	 mov	 edx, DWORD PTR _Result$140642[esp+804]
  00896	50		 push	 eax
  00897	51		 push	 ecx
  00898	52		 push	 edx
  00899	68 00 00 00 00	 push	 OFFSET FLAT:??_C@_0P@HMKC@?7?$...
  0089e	dd d8		 fstp	 ST(0)
  008a0	e8 00 00 00 00	 call	 ?test@@YAXPBDMMMM@Z	; test

; 156  : 		}
行列の掛け算が 5 つ連続しています。 計算過程は消去されていますが、 行列の掛け算部分の中間値が残存している様子が確認できます。

中略とした部分には、定数の中間値が出力されていました。 行列の全要素分の、かなりの量の無駄なコードが出力されていました。

検証 5) クランプ

▼ 検証用コード
	{
	    Vec4_t  vecB(0,1,2,3);
	    Vec4_t  vecC(1,1,1,1);
	    Vec4_t  vecD(2,2,2,2);
	    Vec4_t  vecA(0,0,0,0);

	    int i ;
	    for( i=0 ; i<10000 ; i++ ){
	        vecA += Clamp( vecB , vecC , vecD );
	    }

	    test(
	        "   %f %f %f %f \n"
	    ,   vecA.x()
	    ,   vecA.y()
	    ,   vecA.z()
	    ,   vecA.w()
	    );
	}
▼ コンパイル結果
; 161  : 		{
; 162  : 			Vec4_t	vecB(0,1,2,3);
; 163  : 			Vec4_t	vecC(1,1,1,1);
; 164  : 			Vec4_t	vecD(2,2,2,2);
; 165  : 			Vec4_t	vecA(0,0,0,0);

  0016a	d9 05 00 00 00
	00		 fld	 DWORD PTR __real@4@00000000000000000000
  00170	83 c4 14	 add	 esp, 20			; 00000014H
  00173	c7 44 24 14 00
	00 00 00	 mov	 DWORD PTR _vecA$55557[esp+36], 0
  0017b	c7 44 24 18 00
	00 00 00	 mov	 DWORD PTR _vecA$55557[esp+40], 0
  00183	c7 44 24 1c 00
	00 00 00	 mov	 DWORD PTR _vecA$55557[esp+44], 0
  0018b	b8 10 27 00 00	 mov	 eax, 10000		; 00002710H
$L55559:

; 166  : 
; 167  : 			int	i ;
; 168  : 			for( i=0 ; i<10000 ; i++ ){
; 169  : 				vecA += Clamp( vecB , vecC , vecD );

  00190	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@3fff8000000000000000
  00196	48		 dec	 eax
  00197	d9 54 24 00	 fst	 DWORD PTR _Result$84659[esp+32]
  0019b	d9 44 24 14	 fld	 DWORD PTR _vecA$55557[esp+36]
  0019f	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@3fff8000000000000000
  001a5	d9 5c 24 04	 fstp	 DWORD PTR _Result$84659[esp+36]
  001a9	d9 44 24 18	 fld	 DWORD PTR _vecA$55557[esp+40]
  001ad	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@40008000000000000000
  001b3	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$84659[esp+36]
  001b7	89 4c 24 14	 mov	 DWORD PTR _vecA$55557[esp+36], ecx
  001bb	d9 5c 24 08	 fstp	 DWORD PTR _Result$84659[esp+40]
  001bf	d9 44 24 1c	 fld	 DWORD PTR _vecA$55557[esp+44]
  001c3	d8 05 00 00 00
	00		 fadd	 DWORD PTR __real@4@40008000000000000000
  001c9	8b 54 24 08	 mov	 edx, DWORD PTR _Result$84659[esp+40]
  001cd	89 54 24 18	 mov	 DWORD PTR _vecA$55557[esp+40], edx
  001d1	d9 5c 24 0c	 fstp	 DWORD PTR _Result$84659[esp+44]
  001d5	8b 4c 24 0c	 mov	 ecx, DWORD PTR _Result$84659[esp+44]
  001d9	89 4c 24 1c	 mov	 DWORD PTR _vecA$55557[esp+44], ecx
  001dd	75 b1		 jne	 SHORT $L55559

; 170  : 			}
; 171  : 
; 172  : 			test(
; 173  : 				"	%f %f %f %f \n"
; 174  : 			,	vecA.x()
; 175  : 			,	vecA.y()
; 176  : 			,	vecA.z()
; 177  : 			,	vecA.w()
; 178  : 			);

  001df	8b 44 24 08	 mov	 eax, DWORD PTR _Result$84659[esp+40]
  001e3	8b d1		 mov	 edx, ecx
  001e5	8b 4c 24 04	 mov	 ecx, DWORD PTR _Result$84659[esp+36]
  001e9	52		 push	 edx
  001ea	8b 54 24 04	 mov	 edx, DWORD PTR _Result$84659[esp+36]
  001ee	50		 push	 eax
  001ef	51		 push	 ecx
  001f0	52		 push	 edx
  001f1	68 00 00 00 00	 push	 OFFSET FLAT:??_C@_0P@HMKC@?7?...
  001f6	dd d8		 fstp	 ST(0)
  001f8	e8 00 00 00 00	 call	 ?test@@YAXPBDMMMM@Z	; test

; 179  : 		}
vecB , vecC , vecD の存在自体が最適化により消滅し、 結果だけが vecA に足しこまれる様子が確認できます。 内部的には分岐を伴う処理ですが、分岐のコード自体が消滅していました。

検証結果からわかること

  • swizzle 解決を行うコードは消去される
    swizzle 解決を行うコードは、最適化により完全に消去されています。

  • 計算過程を単純化する最適化が働いている
    演算過程で生じている中間値などが、 最適化により消去されています。 分岐なども、最適化により消去されています。

  • 定数を計算式で表記可能
    定数となるベクトルや行列の値を、 計算式で表記しておいても、 計算式部分はコンパイル段階で解決され、 アセンブリコードレベルでは定数になります。

  • 最適化には限度がある
    限度を越える冗長な式を書くと、 コンパイラの最適化が追いつかなくなり、 最適化の甘いコードが出力されます。