35257


Visual
C++を使用して簡単な多倍長整数の加算処理を行うDLLを作ろうとしているのですが、以下のようなコードをビルドしようとすると内部エラーとなってしまいます。(実際のコードはもっと複雑なのですが、問題が再現可能な短いコードを掲載しています)

後述するように正常にビルドできるようになる回避方法はあるのですが、果たして対処方法として正しいのか確信が持てません。  
解決方法をご存知の方がおられましたら教えていただけませんでしょうか。

**【ソースコード(抜粋)】**

[code]

    __declspec(dllexport) char __stdcall Statement_ADX(char carry, unsigned __int32 x, unsigned __int32 y, unsigned __int32* z_high, unsigned __int32* z_low)
    {
        carry = _addcarryx_u32(carry, x, y, z_low);
        carry = _addcarryx_u32(carry, 0, 0, z_high);
        return (carry);
    }
    
[/code]

**【ビルドログ抜粋(パス名は一部省略)】**

> \------ ビルド開始: プロジェクト: CppBug, 構成: Release Win32 ------  
>  Add.c  
>  ライブラリ ********\Release\CppBug.lib とオブジェクト********\Release\CppBug.exp を作成中  
>  コード生成しています。  
>  ********\cppbug\add.c(13): fatal error C1001: コンパイラで内部エラーが発生しました。  
>  (コンパイラ ファイル 'f:\dd\vctools\compiler\utc\src\p2\main.c'、行 255)  
>  この問題を回避するには、上記の場所付近のプログラムを単純化するか変更してください。  
>  詳細については、Visual C++ ヘルプ メニューのサポート情報コマンドを  
>  選択してください。またはサポート情報 ヘルプ ファイルを参照してください。  
>  プロジェクト "CppBug.vcxproj" のビルドが終了しました -- 失敗。

ログ中のadd.cは上記のソースコードのファイル名で、13行目は関数の終わりの `}` がある行です。

**【発生条件/試行してみたこと】**

  * 構成がReleaseかつプラットフォームがWin32の場合に発生します。(DEBUGまたはx64では発生しません)
  * _addcarryx_u32を_addcarry_u32に置き換えると正常にビルドできました。
  * 試しに、2つ目の_addcarryx_u32がある行をコメントアウトすると正常にビルドできました。
  * carryを2つの_addcarryx_u32の間で引き継いでいることが関係しているのかもしれないと考えて、試しに2つの_addcarryx_u32の呼び出しを以下のように変更してみましたが、改善されず同様のエラーが発生しました。

`carry = _addcarryx_u32(0, x, y, z_low);`  
`carry = _addcarryx_u32(0, 0, 0, z_high);`

**【使用したC/C++プロジェクトについて】**  
使用したプロジェクトは Visual
C++の「Win32プロジェクト」で、アプリケーションの種類に「DLL」、追加のオプションに「空のプロジェクト」を指定しています。共通ヘッダーは追加していません。  
プロジェクトの設定は、既定の設定から以下の点を変更しています。

  * すべての構成とすべてのプラットフォームに対し、C/C++の全般の設定「警告をエラーとして扱う」を「はい(/WX)」に変更。

**【動作環境】**  
\- CPU: Intel Core i7 7700K  
\- OS: Windows10 Pro 64bit  
\- IDE: Visual Studio Community 2017

**【プロジェクトの格納場所】**  
<https://github.com/rougemeilland/palmtreemath/tree/master/CppBug>


CC BY-SA 3.0
2017-06-03T18:06:58.177
35255
2017-06-04T03:44:37.463
2017-06-04T00:10:30.333
4236
23553
question
c visual-studio x86 assembly
Visual C++でビルド時にエラーC1001(内部エラー)発生


> 試しに、2つ目の_addcarryx_u32がある行をコメントアウトすると正常にビルドできました。

惜しいです。試しに1つ目の_addcarryx_u32をコメントアウトしてもinternal errorが発生します。つまり原因は

[code]

    carry = _addcarryx_u32(carry, 0, 0, z_high);
    
[/code]

単独の問題です。

組み込み関数は多くの場合、特定のアセンブリ命令に対応し引数はレジスターが必要です。しかし今回、引数に定数値の`0`と`0`を与えられたためにinternal
errorが発生したようです。実際この引数で意味する処理は

[code]

    *z_high = 0 + 0 + (carray ? 1 : 0); carry = (0 + 0 + !!carrayが桁あふれしたかどうか);
    
[/code]

つまり

[code]

    *z_high = !!carray;
    carry = 0;  // 桁あふれはあり得ない
    
[/code]

と加算`ADCX`はそもそも必要ありません。Cコンパイラーのバグといえばバグでしょうが、このように不毛な処理なので修正を求める意義があるかは疑問です。

* * *

１例に対して反論する意味はないかもしれませんが

>
[code]

>     __declspec(dllexport) char __stdcall Statement_ADX(char carry, unsigned
> __int32 x, unsigned __int32 y, unsigned __int32* z_high, unsigned __int32*
> z_low)
>     {
>         carry = _addcarryx_u32(carry, x, y, z_low);
>         carry = _addcarryx_u32(carry, 0, 0, z_high);
>         return (carry);
>     }
>  
[/code]

と同じ結果を得るコードとしては

[code]

    __declspec(dllexport) char __stdcall Statement_ADX(char carry, unsigned __int32 x, unsigned __int32 y, unsigned __int32* z_high, unsigned __int32* z_low)
    {
        *z_high = _addcarryx_u32(carry, x, y, z_low);
        return 0;
    }
    
[/code]

です。生成されるアセンブリは

[code]

    mov    al, BYTE PTR _carry$[ebp]
    mov    ecx, DWORD PTR _x$[ebp]
    add    al, 255                  ; 000000ffH
    mov    edx, DWORD PTR _z_low$[ebp]
    adcx   ecx, DWORD PTR _y$[ebp]
    setb   al
    mov    DWORD PTR [edx], ecx
    movzx  ecx, al
    mov    eax, DWORD PTR _z_high$[ebp]
    mov    DWORD PTR [eax], ecx
    
[/code]

と`ADCX`及び`SETB`を確認できました。

蛇足ですが、`ADCX`は入力に１つのレジスタ、もう１つのオペランド及びフラグレジスタの`CF`ビットを使用します。ところがC言語の引数にフラグレジスタを使用できないため

[code]

    mov    al, BYTE PTR _carry$[ebp]
    add    al, 255                  ; 000000ffH
    
[/code]

と２命令を使用しています。これは`ADD AL,
255`によってフラグレジスタの`CF`ビットを設定しています。つまり、`ADCX`命令を使用する準備に`ADD`することになっていて本末転倒、目的を見失っているように見受けられます。

生成されるアセンブリコードを踏まえてCソースコードを見直すことをお勧めします。


CC BY-SA 3.0
2017-06-04T00:04:43.797
35257
2017-06-04T03:44:37.463
2017-06-04T03:44:37.463
4236
4236
35255
answer