Lapack: 標準のindex-32ライブラリと一緒にindex-64ライブラリをインストールできるようにしますか?

作成日 2020年11月01日  ·  41コメント  ·  ソース: Reference-LAPACK/lapack

現在、debianにはblas64とcblas64用に(いくつかの)別々のヘッダーがあります(リファレンス実装からではありませんが)。

参照index64API(blisライブラリからのもの)に関して、それらが正しいかどうかはわかりません。

デフォルトでOFFに設定されているBUILD_INDEX64ようなオプションをcmakeに追加することは可能でしょうか。ただし、オンになっている場合は、インデックス64ライブラリが作成されます。
そのようなオプションのPRをした場合、それは可能性として楽しまれますか?

これを標準インストールと共存させるために私が念頭に置いていたいくつかのこと-ライブラリにlibblas64.so, libcblas64.so, liblapack64.so, liblapacke64.soという名前を付けます。これにより、ライブラリ名の間に競合がなくなります(もちろん、リンクすることはできません)。 libblasとlibblas64の両方を同時に使用します)。
また、ライブラリは2回コンパイルする必要があります。1回はindex32用、もう1回はindex64用です(ただし、これは完全に正常なシナリオであり、取引を妨げるものではありません)。
私が良い解決策を考えることができない唯一の衝突は、ヘッダーファイル名です。
debiansスタイルに従う場合は、64で終わるcヘッダーも呼び出すのが賢明かもしれません。
(私はGentooのためにこれを維持しており、エコシステムをDebianに非常に近づけて、開発者がシステムを切り替える際の問題を最小限に抑えたいと考えています)

私はPRをする前にどんな提案にもオープンです:heart:

ありがとう、
アイシャ

Build System Enhancement

全てのコメント41件

こんにちはアイシャ、それは私には完全に理にかなっていますが、他の人からのフィードバックがあるかどうか見てみましょう。 それでは、数日待ちましょう。 NS

間違いなく、それは良い計画のように聞こえます。

OMG @langou
あなたはとても速いです:heart:

完全を期すために、私はまだやらなければならないことを書き留めています。

  • 32ビットAPIが64ビットAPIと共存できるようにヘッダーに名前を付ける方法を理解する
  • printf / fprintfステートメントを修正して、印刷に正しい修飾子を使用するようにします。

最初のポイントを解決するための提案は大歓迎です。残念ながら、「クリーンな」ソリューションはありません。

ファイルの命名を処理するのに役立ついくつかの質問

  • cblas_f77.hcblas_test.h間に重複した定義がたくさんあるようです。 本当に必要ですか?
  • cblas_test.hをインストールする必要がありますか? その名前(およびそれが使用されるファイル)を考えると、テスト段階でのみ使用されると思います。 たぶん、このファイルをシステム全体のレベルでインストールするべきではありませんか?

こんにちは@ epsilon-0、

これを標準インストールと共存させるために私が念頭に置いていたいくつかのこと-ライブラリにlibblas64.so、libcblas64.so、liblapack64.so、liblapacke64.soという名前を付けます。これにより、ライブラリ名の間に競合がなくなります(もちろん、libblasとlibblas64の両方と同時にリンクすることはできません)。

あなたはPR#218を探しているかもしれません。 このPRの作成者は、FedoraProjectのBjörnEsserです。

こんにちは@ epsilon-0。 #462はこの問題を解決しましたか?

@weslleyspereiraいいえ、これはまだ完了していません。
ヘッダーの名前変更/処理をさらに行う必要があります。
私は次の数週間忙しいので、すぐにこれを行うことはできません。
基本概要

  • ヘッダーファイルは、他のヘッダーの場合と同様に、 cblas.hおよびcblas64.hと呼ばれる必要があります

    • これは、 *.cファイルが適切なヘッダーを含めるために若干の調整が必要になることを意味しますが、これはビルド時のみであるため、ハッキングされる可能性があります。

  • cmakeファイルはlapack64またはcblas64などの下にインストールする必要があります。

なるほど、分かりました。 迅速なフォローアップをありがとう!

pkgsrcでパッケージ化しようとすると同様の問題が発生します。 cblasとlapackeを使用して、リファレンスを完全にインストールしたいと思います。 同時にインストールされるさまざまな実装については、ヘッダーのライブラリ名とサブディレクトリを変えることにしました。たとえば、

/usr/lib/libopenblas.so
/usr/lib/libopenblas64.so
/usr/lib/libblas.so
/usr/lib/libcblas.so
/usr/lib/libblas64.so
/usr/lib/libcblas64.so
/usr/include/openblas/cblas.h
/usr/include/openblas64/cblas.h
/usr/include/netlib/cblas.h
/usr/include/netlib64/cblas.h
/usr/include/cblas.h -> netlib/cblas.h (for compatibility, having the default)

(など)

バイナリディストリビューションのようにランタイムスイッチングを考慮していないため、libopenblasの追加名のように、各cblas.h(およびlapacke.h)が一致するライブラリに固有である場合は問題ありません。 ビルド時の選択は、

BLAS_INCLUDES=-I/prefix/include/netlib64
BLAS_LIBS=-lblas64
CBLAS_LIBS=-lcblas64

(など)それは.pcファイルが言うことになっていることであり、別のヘッダーファイル名を伝達するよりもはるかに簡単です。 それらはまだ一貫していませんが、私はそれを修正しています。 これまでのところ、すべての参照ライブラリに煩わされている場合、人々はディストリビューションでそれをハッキングしたようです。

ただし、これらのヘッダーについて1つ質問があります。

私はcmakeビルドをハッキングして、各コンポーネントを個別にビルドし、他の修正を試みています(https://github.com/Reference-LAPACK/lapack/pull/556を参照)。 libblas.soライブラリとlibblas64.soライブラリが正常に構築され、ヘッダーdirが構成されていますが、インストールされているcblas.hとlapacke.hは、32ビットと64ビットのインデックスバージョンで同じです。 これはopenblasとは相容れません。そこで、netlibビルドでは見られない決定的な違いがあります。

diff -ruN /data/pkg/include/openblas/openblas_config.h /data/pkg/include/openblas64/openblas_config.h
--- /data/pkg/include/openblas/openblas_config.h    2021-06-03 19:03:53.000000000 +0200
+++ /data/pkg/include/openblas64/openblas_config.h  2021-06-03 19:13:36.000000000 +0200
@@ -44,6 +44,7 @@
 #define OPENBLAS_DLOCAL_BUFFER_SIZE 32768
 #define OPENBLAS_CLOCAL_BUFFER_SIZE 16384
 #define OPENBLAS_ZLOCAL_BUFFER_SIZE 12288
+#define OPENBLAS_USE64BITINT 
 #define OPENBLAS_GEMM_MULTITHREAD_THRESHOLD 4
 #define OPENBLAS_VERSION " OpenBLAS 0.3.15 "
 /*This is only for "make install" target.*/

参照ライブラリの場合、32ビットと64ビットのインデックスビルドのすべてのヘッダーは同一であり、明らかにユーザーは
-DWeirdNEC彼らの旗でcblas.hとするために(30年前に面白いだったかもしれない) -DLAPACK_ILP64 -DHAVE_LAPACK_CONFIG_H 。 人々は本番環境で最適化されたBLASライブラリを使用するため、事実上の標準はそれをユーザーに公開することではありません。 これらのフィードバック、IMHO、およびILP64ビルドからインストールされたヘッダーは、64ビットライブラリにリンクするときにアプリがクラッシュしないようにするためにファンキーなフラグを必要としないはずです。

ビルド時にヘッダーを変更して正しい整数を定義することが正しい解決策であることに同意しますか?

ところで、インストールされているcblas構成ファイルも、必要なdefへの参照を見逃しているため、64ビットのインデックスビルドでは壊れているようです。 しかし、実際には、これらをまったくインストールしないことを考えています。 それらは.pcファイルと重複しており、cmakeを使用して依存パッケージを使用してBLAS_LIBS etalを介してパッケージャーの選択を受け入れるように説得するのが困難になる可能性があります。

PS:インテル®MKLには、設定する中央スイッチ-DMKL_ILP64があります。 ささいな設定を想像します
include/intel-mkl64/cblas.h

#ifndef MKL_ILP64
#define MKL_ILP64
#endif
#include <mkl_cblas.h>

一般的なスキームに合うように。 奇妙なnetlib定義と同じように、定義をBLAS_INCLUDESに入れることもできます。 何が良いですか? Intelのようにやりたいですか、それともOpenBLASのようにしたいですか?

ビルド時にヘッダーを変更して正しい整数を定義することが正しい解決策であることに同意しますか?

はい。 私はそれに同意し、ヘッダー全体を複製しないソリューションを好みます。 きれいだと思います。

ところで、インストールされているcblas構成ファイルも、必要なdefへの参照を見逃しているため、64ビットのインデックスビルドでは壊れているようです。

右。 64ビットライブラリ(BUILD_INDEX64 = ON)をインストールしたところ、 WeirdNECLAPACK_ILP64またはHAVE_LAPACK_CONFIG_Hを使用するように指示するものが何も表示されません

はい。 私はそれに同意し、ヘッダー全体を複製しないソリューションを好みます。 きれいだと思います。

これは私にはあいまいです。 よりクリーンなソリューションはどれですか? 私が今準備しているのはそのようなものです:

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

CMakeFileは、HAVE_ILPを1または0に置き換え、結果のヘッダーが現在のビルドにインストールされます。

(ところで、Windowsではlongは機能しません。stdintを使用するすべてのプラットフォームでは、longは…またはint64_tです。)

右。 64ビットライブラリ(BUILD_INDEX64 = ON)をインストールしたところ、 WeirdNECLAPACK_ILP64またはHAVE_LAPACK_CONFIG_Hを使用するように指示するものが何も表示されません

私はあなたがする未来を想像しています

cc -I/foo/include/netlib64 -o bar bar.c -L/foo/lib -lcblas64

そして、物事はfoo / include / netlib64 / cblas.hで処理されます。それ以外の場合は、foo / include / netlib / cblas.h(foo / include / cblas.hにリンクされている可能性があります)によって処理されます。

私はこれがあなたの意図したものではないのではないかと疑っていますが、それがより良いことを納得させたいです;-)

/foo/include/cblas.hに 'the'ヘッダーを配置し、WeirdNECを定義するだけで、/ foo / include / netlib64 / cblas.hにヘッダーをインクルードさせることで、ヘッダーを複製しないようにすることができますが、これは64を意味します。ビットパッケージと32ビットパッケージは、その共通のヘッダーファイルを共有しますが、これはパッケージ化が面倒です。 それぞれがファイルを別々の場所/名前に配置する方がはるかに優れています。 #include <cblas.h>行を置き換えたくないので、名前はcblas.hのままにする必要があります。

編集:また、cblas.hに../cblas.hを含めること自体が面倒です。 また、cmakeの_one_ヘッダーインストールディレクトリを定義します。 デフォルトでは、/ foo / netlib64 / includeではなく/ foo / includeです。 このデフォルトを変更するつもりはありません。 パッケージャは次のようにサブディレクトリを指定する必要があります(BSD make in pkgsrc):

.if !empty(LAPACK_COMPONENT:M*64)
.  if empty(MACHINE_ARCH:M*64)
PKG_FAIL_REASON+=       "${LAPACK_COMPONENT} incompatible with non-64-bit platform"
.  endif
HEADERDIR=netlib64
.else
HEADERDIR=netlib
.endif

# Note: We patch the build to install both static and
# shared libraries.
CMAKE_ARGS=     -DBUILD_DEPRECATED=ON \
                -DBUILD_SHARED_LIBS=ON \
                -DBUILD_STATIC_LIBS=ON \
                -DCMAKE_INSTALL_INCLUDEDIR=${PREFIX}/include/${HEADERDIR} \
                ${LAPACK_COMPONENT_CMAKE_ARGS}

通常の場所にこの変更を加えた32ビットcblas.hの出荷/インストールの美しい側面は、元のメカニズムが引き続き機能することです。 64ビットバリアントのみがWeirdNECを適用します。 64ビットのものだけをプレフィックスにインストールし、エコシステムの他の部分はそのままにしておくことを決定できます。

ああ、さあ…CBLAS / cmake /cblas-config-install.cmake.inは-DCMAKE_INSTALL_INCLUDEDIRを忘れているようですね。

# Report lapacke header search locations.
set(CBLAS_INCLUDE_DIRS ${_CBLAS_PREFIX}/include)

(コメントは一番上の砂糖です。)

私は、CMakeビルドがかなり成熟していないと思うかもしれません。 プロジェクトはそれをプライマリビルドとして持つことに真剣に取り組んでいますか、それともこれは単なるドライブバイの貢献ですか? 私は本当に古いスタイルのMakefileを修正したいと思っています。 しかし、私は今、CMakeのものを修正することに多くの時間を費やしたので、とにかく嫌いです。 だから私はそれを乗り越えたいと思います。

今はあきらめなければなりません…上記のようにcblas.hをcblas.h.inに移動し、追加しました

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cblas.h.in cblas.h @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cblas_f77.h.in cblas_f77.h @ONLY)

CBLAS / include / CMakeLists.txtに送信し、トップレベルのCMakeLists.txtで@HAVE_ILP64@を1または0に定義しました。 しかし、私は一生の間、高レベルのCMakeLists.txtにあるインストールのものに、生成されたヘッダーをインストールさせる方法、または${LAPACK_BINARY_DIR}/includeからの同じものの奇妙なコピーを作成する方法を理解できません(本当に?Aソースツリー内にコピーしますか?)

マクロappend_subdir_filesは何をすることになっていますか? プレフィックスのコピーをヘッダーパスの前に追加しているようです。 ソースヘッダーファイルへのパスが足りないか、多すぎます。 ここからそこにヘッダーファイルをインストールしたいだけです。

知識のある人がここで助けてくれますか? 明日は理解できると思いますが、それが現実の世界で何かを壊して感情的な安堵をもたらさないのかどうかはわかりません。

はい。 私はそれに同意し、ヘッダー全体を複製しないソリューションを好みます。 きれいだと思います。

これは私にはあいまいです。 よりクリーンなソリューションはどれですか? 私が今準備しているのはそのようなものです:

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

CMakeFileは、HAVE_ILPを1または0に置き換え、結果のヘッダーが現在のビルドにインストールされます。

(ところで、Windowsではlongは機能しません。stdintを使用するすべてのプラットフォームでは、longは…またはint64_tです。)

右。 64ビットライブラリ(BUILD_INDEX64 = ON)をインストールしたところ、 WeirdNECLAPACK_ILP64またはHAVE_LAPACK_CONFIG_Hを使用するように指示するものが何も表示されません

私はあなたがする未来を想像しています

cc -I/foo/include/netlib64 -o bar bar.c -L/foo/lib -lcblas64

そして、物事はfoo / include / netlib64 / cblas.hで処理されます。それ以外の場合は、foo / include / netlib / cblas.h(foo / include / cblas.hにリンクされている可能性があります)によって処理されます。

私はこれがあなたの意図したものではないのではないかと疑っていますが、それがより良いことを納得させたいです;-)

申し訳ありませんが、説明させてください。 最初は、元のヘッダーcblas.hを保持し、 include/netlib64/cblas.hinclude/netlib/cblas.hを次のようなもので作成するというアイデアが気に入りました。

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include <cblas.h>

/foo/include/cblas.hに 'the'ヘッダーを配置し、WeirdNECを定義するだけで、/ foo / include / netlib64 / cblas.hにヘッダーをインクルードさせることで、ヘッダーを複製しないようにすることができますが、これは64を意味します。ビットパッケージと32ビットパッケージは、その共通のヘッダーファイルを共有しますが、これはパッケージ化が面倒です。 それぞれがファイルを別々の場所/名前に配置する方がはるかに優れています。 #include <cblas.h>行を置き換えたくないので、名前はcblas.hのままにする必要があります。

編集:また、cblas.hに../cblas.hを含めること自体が面倒です。 また、cmakeの_one_ヘッダーインストールディレクトリを定義します。

ただし、一方のヘッダーにもう一方のヘッダーが含まれている場合は、インクルードdirとしてinclude/netlib64includeを使用する必要があります。

デフォルトでは、/ foo / netlib64 / includeではなく/ foo / includeです。 このデフォルトを変更するつもりはありません。 パッケージャは次のようにサブディレクトリを指定する必要があります(BSD make in pkgsrc):

.if !empty(LAPACK_COMPONENT:M*64)
.  if empty(MACHINE_ARCH:M*64)
PKG_FAIL_REASON+=       "${LAPACK_COMPONENT} incompatible with non-64-bit platform"
.  endif
HEADERDIR=netlib64
.else
HEADERDIR=netlib
.endif

# Note: We patch the build to install both static and
# shared libraries.
CMAKE_ARGS=     -DBUILD_DEPRECATED=ON \
                -DBUILD_SHARED_LIBS=ON \
                -DBUILD_STATIC_LIBS=ON \
                -DCMAKE_INSTALL_INCLUDEDIR=${PREFIX}/include/${HEADERDIR} \
                ${LAPACK_COMPONENT_CMAKE_ARGS}

それは私には良さそうです。 したがって、コンパイラフラグを_推測_することなく、LAPACKをビルドするための代替手段を追加するだけです。 しかし、現在の方法も機能します。

(ところで、Windowsではlongは機能しません。stdintを使用するすべてのプラットフォームでは、longは…またはint64_tです。)

知っておくと良い。 BLAS ++およびLAPACK ++は、longlongの代わりにint64_tを使用します。

@weslleyspereiraだから、あなたは最初このアイデアが好きでした:

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include "../cblas.h"

/prefix/include/cblas.hと/prefix/include/netlib64/cblas.hを使用すると、後者が前者を見つけますか? しかし、64ビットビルドの場合、このようなヘッダーをインストールする方がより堅牢なソリューションであることに同意しますか?

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

(longとint64は別の問題ですが、BLAS ++と同じように、私はすべてその変更を行うことに賛成です)

ちなみに、 `#include" ... /cblas.h "が他のインデントされたヘッダーだけを見つけると仮定しても安全かどうかさえわかりません。 C標準では、検索順序は実装によって定義されていると言われているようで、必ずしも現在のヘッダーに関連しているとは限りません。 パッケージャとしての私の主な問題は、その共通ヘッダー用に別のパッケージが必要であるか、64ビットパッケージをそのためだけに32ビットパッケージに依存させることです。 これは最悪だ。

後でアップストリームコードの変更を解決するために、pkgsrcのこのような変更を今すぐ進めたいと思います。 32ビットインデックスまたは64ビットインデックスを任意のヘッダー( -DNETLIB_INDEX_BITS=64 ?)で明示的に強制する新しいシンボルについて説明します。デフォルトでは、ライブラリの構築に使用されます。

意図した解決策がこれであることに同意できますか?

lib/libcblas64.so
include/optional_subdir64/cblas.h

lib/libcblas.so
include/optional_subdir/cblas.h

LAPACKコードをビルドするたびに、ユーザーが何も定義しなくても、少なくともデフォルトで、インストールされているライブラリと一致するヘッダーが作成されます。 わかった?

その後、pkgsrcの次のリリース(締め切り間近)の前にこれを挿入することができ、その実装の詳細についてさらに話し合うことができるので、ここで何かをマージした後、新しいLAPACKリリースでパッチを削除できます。 この変更により、プレーンなMakefileビルドも修正する必要がありますが、CMakeビルドを使用するだけの場合は、_my_パッチではまだ修正する必要はありません。

(その奇妙なCMakeビルドを提出に打ち負かそうとするときは、どういうわけか私の気性をチェックする必要があります。ビルドディレクトリの周りのヘッダーコピーをシャッフルしてから、インストールするためにそれらを見つけることができません。たぶんインストールからそれらをドロップするだけです…私たちはpkg-configを手に入れました!)

なんでも? これは私たちが使用する主要な実装であるopenblasによって設定された例であるため、実際には別のソリューションの可能性はあまりないことを認めなければなりません。 Intelに64ビット/ 32ビットのインデックスヘッダー用のサブディレクトリを用意して、mkl_cblas.hとmkl_lapacke.hをラップするよう説得することも想像できます。 それ以外の場合は、それらを提供するだけの単純なパッケージを作成します。

include/mkl-blas/cblas.h
include/mkl-blas64/cblas.h

現在、私はpkgsrcに機械を追加して、ビルドに面白い-DWeirdNEC -DHAVE_LAPACK_CONFIG_H -DLAPACK_ILP64行を提供し、cblasとcblas64の両方が同一のヘッダーをインストールしています。 そのままにしておくこともできますが、ビルドABIと一致するようにヘッダーを設定することは理にかなっていると思います。

@weslleyspereiraだから、あなたは最初このアイデアが好きでした:

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include "../cblas.h"

/prefix/include/cblas.hと/prefix/include/netlib64/cblas.hを使用すると、後者が前者を見つけますか? しかし、64ビットビルドの場合、このようなヘッダーをインストールする方がより堅牢なソリューションであることに同意しますか?

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

はい、それだけです。 32ビットおよび64ビットヘッダー用のサブフォルダーを用意するというソリューションに同意します。 私はこれについて@langou

(longとint64は別の問題ですが、BLAS ++と同じように、私はすべてその変更を行うことに賛成です)

右。 これは別の問題で対処する必要があります。

後でアップストリームコードの変更を解決するために、pkgsrcのこのような変更を今すぐ進めたいと思います。 32ビットインデックスまたは64ビットインデックスを任意のヘッダー( -DNETLIB_INDEX_BITS=64 ?)で明示的に強制する新しいシンボルについて説明します。デフォルトでは、ライブラリの構築に使用されます。

意図した解決策がこれであることに同意できますか?

lib/libcblas64.so
include/optional_subdir64/cblas.h

lib/libcblas.so
include/optional_subdir/cblas.h

はい。 今後もPRを提案していただけると思いますので、よろしくお願いします! 個人的には、 NETLIB_INDEX_BITSような新しいシンボルは完全に理にかなっていると思います。 デフォルト値が32のままであり、 -DWeirdNEC-DNETLIB_INDEX_BITS=64意味することを確認します。

LAPACKコードをビルドするたびに、ユーザーが何も定義しなくても、少なくともデフォルトで、インストールされているライブラリと一致するヘッダーが作成されます。 わかった?

私にはいいですね。

その後、pkgsrcの次のリリース(締め切り間近)の前にこれを挿入することができ、その実装の詳細についてさらに話し合うことができるので、ここで何かをマージした後、新しいLAPACKリリースでパッチを削除できます。 この変更により、プレーンなMakefileビルドも修正する必要がありますが、CMakeビルドを使用するだけの場合は、_my_パッチではまだ修正する必要はありません。

Ok! おそらく2021年の2学期にLAPACKがリリースされるでしょう。そうです、Makefileはそれに応じて調整する必要があり、私はそれを喜んでお手伝いします。

これは多少関連しています。 netlib CBLASのヘッダーはnetlibによって提供されるだけではないことを忘れてはなりません…NumPyは常に独自のヘッダーを使用します:

https://github.com/numpy/numpy/blob/main/numpy/core/src/common/npy_cblas.h

また、このヘッダーでは、インデックスの指定に使用される整数型とは異なり、 CBLAS_INDEX=size_tを設定します。 これは、一部の関数の戻り値にのみ使用されます。

$ grep CBLAS_INDEX ./numpy/core/src/common/npy_cblas_base.h                                                                                                                                  
CBLAS_INDEX BLASNAME(cblas_isamax)(const BLASINT N, const float  *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_idamax)(const BLASINT N, const double *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_icamax)(const BLASINT N, const void   *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_izamax)(const BLASINT N, const void   *X, const BLASINT incX);

違い:

$ grep cblas_isamax ./numpy/core/src/common/npy_cblas_base.h  /data/pkg/include/cblas.h                                                                                                      
./numpy/core/src/common/npy_cblas_base.h:CBLAS_INDEX BLASNAME(cblas_isamax)(const BLASINT N, const float  *X, const BLASINT incX);
/data/pkg/include/cblas.h:CBLAS_INDEX cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);

それが問題を引き起こしているのではないかと思います。 Netlibの場合、インデックスのタイプは1つだけですが、他の実装では、インデックス関数に異なる戻り値タイプを使用します。 OpenBLASがその例を示しています。 isamaxはunsignedsize_tを返すと言われていますが、Cラッパーは実際には符号付き整数を返すFortran関数を呼び出します(編集:64上の符号なし64ビット変数への渡された参照に符号付き32ビットまたは64ビット整数値を書き込むサブルーチンビットシステム)。

リファレンス実装はこれについて意見を持っていますか? size_t値は、isamax()からの負でないリターンを常に保持できるため、実際の問題はありません。 しかし、それは臭いがします。 (編集:size_tが32ビットの32ビットシステムで64ビットインデックスを使用してビルドできますか?そうするとオーバーフローします。 size_t *int *にキャストすることの不安に加えて。)

最適化された実装はそこでsize_tを決定したように見えるので、参照はその事実を受け入れて従う必要がありますか?

そして、実際には、numpyを参照cblaとリンクすることはどれほど危険ですか?

OpenBLASがその例を示しています。 (...)
最適化された実装はそこでsize_tを決定したように見えるので、参照はその事実を受け入れて従う必要がありますか?

私は確かにnumpy(またはそのことについてはmklなど)について話すことはできませんが、OpenBLASが何らかの形で規範的であると主張することを躊躇します。 。

もちろん。 OpenBLASまたはMKLが実際に使用されているものであり、どちらも定着しているようです。

#define CBLAS_INDEX size_t  /* this may vary between platforms */
#ifdef MKL_ILP64
#define MKL_INT MKL_INT64
#else
#define MKL_INT int
#endif
CBLAS_INDEX cblas_isamax(const MKL_INT N, const float  *X, const MKL_INT incX);

または同様に

#ifdef OPENBLAS_USE64BITINT
typedef BLASLONG blasint;
#else
typedef int blasint;
#endif
#define CBLAS_INDEX size_t
CBLAS_INDEX cblas_isamax(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);

対参照

#ifdef WeirdNEC
   #define CBLAS_INDEX long
#else
   #define CBLAS_INDEX int
#endif
CBLAS_INDEX cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);

なぜ彼らはここでの参照から逸脱するのですか? それについてのコミュニケーションはありましたか? また…MKLとOpenBLASが、リファレンスCBLASの一部でもない関数のホストを定義しているのがわかります。

CBLAS_INDEX cblas_isamin(const MKL_INT N, const float  *X, const MKL_INT incX);
CBLAS_INDEX cblas_idamin(const MKL_INT N, const double *X, const MKL_INT incX);
CBLAS_INDEX cblas_icamin(const MKL_INT N, const void   *X, const MKL_INT incX);
CBLAS_INDEX cblas_izamin(const MKL_INT N, const void   *X, const MKL_INT incX);

CBLAS_INDEX cblas_isamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

CBLAS_INDEX cblas_ismax(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

CBLAS_INDEX cblas_ismin(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

したがって、標準を拡張することは1つのことですが、 size_tintは、64ビットシステムでは深刻な問題のようです。 これは何らかの方法で解決する必要があります。 Netlibの方法が賢明であるように私には思えます:インデックスに使用されるものと同じタイプ。 最終的にはすべてこのようなFortranルーチンを呼び出すので

c     isamaxsub.f
c
c     The program is a fortran wrapper for isamax.
c     Witten by Keita Teranishi.  2/11/1998
c
      subroutine isamaxsub(n,x,incx,iamax)
c
      external isamax
      integer  isamax,iamax
      integer n,incx
      real x(*)
c
      iamax=isamax(n,x,incx)
      return
      end

…iamaxにsize_tのアドレスを渡すと、それは間違っているように見えます。 OpenBLASソースで、このリファレンス以外の実装は見つかりませんでした。 彼らはそのような外部タイプを変更するのは愚かですか、それとも私は非常に基本的なものを見落としていますか? 誰かが実際にこれらの機能を使用していますか?

こんにちは、リファレンスBLAS、リファレンスCBLAS、リファレンスLAPACK、これらのプロジェクトの主な目的の2つは、(1)数値アルゴリズムと(2)共通インターフェースの定義、リファレンス実装、およびこれを実現するテストスイートです。 これらのプロジェクトに関係するすべての人は、ソフトウェアエンジニアリング、ソフトウェアを展開するためのベストプラクティスなどについて、他のプロジェクト(OpenBLAS、MKLなど)から見て喜んで学ぶことができると思います。これらのプロジェクトから学ぶことはたくさんあります。 (そして、他の数値線形代数プロジェクトからも多くのことを学びます!)とにかく:リファレンスBLAS、CBLAS、LAPACKは、CMakeパッケージング、インターフェースにいくつかの改善を使用できます。私たち、まあ、私はすべてこのモデルに向かって動くことに賛成です。

コンテキストを追加するために、CBLASは、1996年から2000年にかけてBLASの再検討に取り組んだ委員会(Basic Linear Algebra Subprograms Technical Forum)から生まれました。その一環として、CBLASはBLASのCインターフェイスを定義しました。 見る:
http://www.netlib.org/blas/blast-forum/
特に参照してください:
http://www.netlib.org/blas/blast-forum/cinterface.pdf
LAPACKが提供するCBLASは、25年前にBasic Linear Algebra Subprograms TechnicalForumで定義されたインターフェイスの実装であると思います。

CBLASを改善するための提案がある場合は、それらを一緒に送信してください。 これをさまざまな利害関係者に伝えようと思うことができます。

ポインタをありがとう。 したがって、関連する部分はその仕様ではB.2.2のようです。つまり、 BLAS_INDEXは通常size_tですが、に使用される(符号付き)Fortran整数型と同じになるように選択される場合もあります。インデックス作成。 それは実装次第です。

したがって、一般的な最適化された実装はsize_tを選択し、NetlibリファレンスはFortranに使用するのと同じ整数を選択したようです。 libを使用するさまざまなプロジェクト(numpyのように、外部libのヘッダーを出荷する)のあちこちにcblas.hのコピーがあり、その行があります

#define CBLAS_INDEX size_t  /* this may vary between platforms */

https://github.com/LuaDist/gsl/blob/master/cblas/gsl_cblas.hでは、これに付随するものがあります

/* This is a copy of the CBLAS standard header.
 * We carry this around so we do not have to
 * break our model for flexible BLAS functionality.
 */

これはリファレンス実装に端を発しているように聞こえますが、その後変更されましたか? 41779680d1f233928b67f5f66c0b239aecb42774を見ると…WeirdNECを使用したCBLAS_INDEXスイッチは、64ビットビルドの前に存在していたことがわかります。 うわー、このコミットは最近ですか。 size_tは2015年まで参照cblas.hにあり、83fc0b48afd1f9a6d6f8dddb16e69ed7ed0e7242がそれを変更し、WeirdNEC定義を導入したことがわかります。 これがこんなに最近だとは思いもしませんでした! 非常に紛らわしい。

また、以前のバージョンのcblas.hがintをFortran呼び出しに渡し、現在はCBLAS_INDEXいることもわかります。 これは現在正しいようです。整数型としてCBLAS_INDEXを一貫して使用し、Fortran部分で32ビットまたは64ビットに切り替えています。

しかし、古いバージョンのcblas.hをsize_tで継承したが、参照からの現在のCBLASコードとソースを同期する最適化されたライブラリには、すばらしいバグが発生している可能性がありますか? 彼らは64ビットシステムの32ビットの場合にこのようなことをしていませんか?

#include <stdio.h>
#include <stdlib.h>


void ia_max(int a, void *b)
{
    int *ib = (int*)b;
    *ib = a*2;
}


int main(int argc, char **argv)
{
    int i = atoi(argv[1]);
    size_t maxi;
    ia_max(i, &maxi);
    printf("in %d out %ld\n", i, (long)maxi);
    return 0;
}

これにより、

$ gcc -O -o t t.c
$ ./t 42
in 42 out 140724603453524

size_t値をゼロに初期化すると役立ちますが、おそらくリトルエンディアンの場合のみです。 誰もこれに悩まされませんか? 私は何かが欠けている必要があります。

結論として:

  1. 参照CBLASは、最初に戻り値としてsize_tを持っていました。
  2. ただし、Fortranの実際の呼び出しではintを使用していました。
  3. ダウンストリーム(最適化されたBLAS、CBLASユーザー)は、古いバージョンのヘッダーで実行されます。
  4. リファレンスCBLASは、特定のシステムにWeirdNECハックを導入し、size_tをintまたはlongに置き換えます(Fortran側と一致しますか?!)
  5. 64ビットリファレンスCBLASインターフェイスは、Fortranのデフォルト整数にCBLAS_INDEXを使用して、その上に構築されます。
  6. ダウンストリームは64ビットをサポートして独自のことを行いましたが、常にsize_tであるCBLAS_INDEXから分離しました。
  7. ダウンストリームは、デフォルトの整数を期待するFortranを呼び出すためにCBLAS_INDEXを使用するCBLASラッパーを継承します。

結果として、これは素晴らしい破損のように聞こえます。 ヘッダーとコードが分岐しました。 なぜ誰もまだ問題に気づいていないのですか? または、isamaxとその仲間の参照CBLASラッパーコードが実際に使用されていない部分を見逃しましたか?

OpenBLASは、少なくともReference-LAPACKのCBLASラッパーコードを使用しません(使用したことはありません。ソースはありますが、ビルドされません)

@ martin-frbg知っておくと良い。 たとえば、size_tがcblas_isamax()の実際の計算にどのように渡されるかを示すx86-64のコードパスを指摘できますか? 特定のカーネル実装を見つけましたが、一般的なケースについてはよくわかりません。

誰も実際に(size_t*)をFortranインターフェースに渡さないことを知っておくとよいでしょう。

確かに、プロジェクトがただ想定するのは良くありません

size_t cblas_isamax(…)

実際のライブラリが戻り値としてintまたはlong(またはint64_t)を提供する可能性がある場合。 ほとんどの場合、64ビットレジスタの値で機能する可能性がありますが、それは良くありません。 実装でこれを修正できますか? 人々は過去5年間、 CBLAS_INDEX一貫した使用についてNetlibの例を取り上げません

関連するコードはOpenBLAS / interfaceにあります。たとえば、CBLASが定義されるとinterface / imax.cはcblas_isamax()にコンパイルされ、その呼び出しグラフにはFortranコードは含まれません。

あぁ、いいね。 したがって、実際に問題となる1つのケースは、ライブラリに適合しないcblas.hのコピーを使用するプロジェクトに依存することです。

NumPy(およびSciPy)でcblas_isamax()とその友人の実際の使用法が見つからないため、これは理論上の問題にすぎない可能性があります。 それでも修正する必要があります。 そう:

  1. 他のものは、int32_t / int64_tを使用するNetlibの例に従います(その間は明示的にしましょう;-)サイズの戻り値とインデックス引数の両方にBLAS_INDEX。
  2. Netlibは陥没し、他のようにそれらのリターンのためにsize_tに戻ります。

これは別の問題ですか? ただし、32ビットまたは64ビットライブラリの選択に関係します。

PS:APIの列挙型が(関数の引数と構造体のメンバーの実際のデータ型として)良いアイデアかどうかはまだわかりません。それらの下で使用される整数を変更するコンパイラオプションがあるからです。 実際にはそれほど関係はありませんが、それでも私は不安になります。

これについて考えれば考えるほど、オプション2に傾倒します。APIにsize_tが非常に長い間存在していました。 次に、Netlibはそのsize_tをintまたはlongに変更しました。 何がFortranコードとよりよく一致するか、またはより一貫性があるかどうかに関係なく、size_tはAPIを確立し、Netlibリファレンスはそれを破りました。

物事を変えることについてのPRを開くべきですか

size_t cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);
size_t cblas_idamax(const CBLAS_INDEX N, const double *X, const CBLAS_INDEX incX);
size_t cblas_icamax(const CBLAS_INDEX N, const void   *X, const CBLAS_INDEX incX);
size_t cblas_izamax(const CBLAS_INDEX N, const void   *X, const CBLAS_INDEX incX);

また? 過去と未来のどこでも常にsize_tであることを強調するために、この位置にマクロはもう存在しないはずです。

https://github.com/numpy/numpy/issues/19243では、基本的に「Screw Netlib、size_tは他のすべての人に有効です」になりました。

size_tを使用する理由は3つあります。

  1. すべてのCおよびC ++標準ライブラリ関数は、この値を受け入れて返します。たとえば、 void* malloc(size_t)size_t strlen() 、またはstd::size_t std::vector<T>::size() (C ++)です。 size_tを使用すると、値の切り捨てや符号付き/符号なしの変換を回避できます。
  2. size_tは、行列の次元など、負の値にできない表現量としてよく使用されます。
  3. CおよびC ++標準では、任意の配列のサイズをsize_t格納でき、すべての要素にsize_tでインデックスを付けることができることが保証されています。 cppference.com:size_t

編集:size_tが32ビットである32ビットシステムで64ビットインデックスを使用して構築できますか? その後、オーバーフローしました。

いいえ。32ビットシステムには4GBを超える仮想メモリがある場合がありますが(Linuxはこれをサポートしています)、単一の32ビットプロセスが4GBを超えることにアクセスすることはできません。 つまり、64ビットインデックスの上位32ビットは使用されません。

_64ビットLinuxOSで実行される32ビットプロセスへのメモリ制限_

また、size_tを維持することは正しいことだと思います。なぜなら、それからの変更はABIの中断であり、Netlibが他の世界と同期しなくなったからです。

しかし、私はあなたの議論をあざ笑うことを余儀なくされていると感じています;-)

1. All of the C and C++ standard library functions accept and return this value

これを調べたところ、C ++コンテナインデックスに符号なしの型を使用することは歴史的な誤りであり、size()メソッドの戻り型でさえも、すぐに符号付きと符号なしの数値が混在してしまうため、歴史的な誤りであると認めました。なんらかの方法で。 Netlibの現在の状態はそれ自体と一貫性があり、サイズとインデックスに常に符号付きの型を使用しますが、もちろんmalloc()とは矛盾します。これには、に収まるすべてのメモリを実際にアドレス指定できるようにするための符号なしサイズの要件があります。 32ビット(または理論的には64ビット)。

私が書いたコードでは、最終的に関数呼び出しのオフセットとしてインデックスを渡す場所で、それについて自分自身が正しいのだろうかと思っています。 インデックスは符号なし、オフセットは符号付きです。 コンパイラ(MSVC)が-unsigned_valueによって混乱していることを除けば、これは、変換で発生する可能性のあるオーバーフローについて常に心配する必要があることを意味します。

しかし、とにかく、malloc()やその仲間に渡すメモリサイズを計算するだけの場合、size_tは自然なことであり、以前はCBLASにありました。

コードの現在の状態で発生する可能性のある問題について、ビルドでベンダーのcblas.hと一致しない:

いいえ。32ビットシステムには4GBを超える仮想メモリがある場合がありますが(Linuxはこれをサポートしています)、単一の32ビットプロセスが4GBを超えることにアクセスすることはできません。 つまり、64ビットインデックスの上位32ビットは使用されません。

そうです、 size_tは32ビットのままです。 cblas_isamax()をビルドして64ビット整数を返す場合、ビルドをハッキングしてlong使用せず、 int64_t後、もちろん、本当にそのような使用法で起こりますか?

size_t cblas_isamax(); // really int64_t cblas_isamax()!
size_t value = cblas_isamax(…);

x86呼び出し規約は、64ビット値をEAXおよびEDXに入れる可能性があります。 または、ポインタリターンといくつかのバッファで動作する可能性があります。 しかし、他のアーキテクチャは何をしますか? したがって、破損することはないかもしれませんが、確かに間違った値です。 最良のケースは、上位32ビットが無視されることです。

ここで、ビッグエンディアンの32ビットシステム(何らかの形式のARM)を想像してみてください…値の必要な半分が返されることを確認しますか?

確かに、32ビットプログラムで64ビットインデックスを必要とする非スパースデータを実際に処理することはできませんでした。 しかし、_at_least_が間違った結果をもたらす、一致しない関数呼び出しを実行できることは、不健康に思えます。

私はいくつかの簡単なテストを行いました…x86Linux(x86-64システムではgcc -m32 )では、上位32ビットを削除するだけです。

より興味深いケース…64ビットsize_t:

size_t cblas_isamax(); // really int32_t cblas_isamax()!
size_t value = cblas_isamax(…);

繰り返しになりますが、x86-64では、64ビットRAXと32ビットEAXの間の特殊な関係により、共有レジスタで32ビット操作を実行すると、上位32ビットをサイレントにゼロにすることもできます。 しかし、少し奇妙な関数定義を使用するのは楽しいことです。

$ cat ret32.c 
#include <stdint.h>

int32_t ret64(int64_t a)
{
    a += 1LL<<32;
    return a;
}
$ gcc -m64  -g -c -o ret32.o ret32.c 
$ LANG=C objdump -S ret32.o 
[…]
   8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    a += 1LL<<32;
   c:   48 b8 00 00 00 00 01    movabs $0x100000000,%rax
  13:   00 00 00 
  16:   48 01 45 f8             add    %rax,-0x8(%rbp)
    return a;
  1a:   48 8b 45 f8             mov    -0x8(%rbp),%rax

コンパイラが完全な64ビットレジスタで動作し、32ビット値を返すことが期待される関数の上位32ビットをクリアしないままにするのが賢明かどうかを議論することができますが、呼び出し元のみに依存する場合は完全に合法です。下位32ビットを使用していると思います。

$ cat call.c 
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

INDEX ret64(int64_t);

int main(int argc, char **argv)
{
    if(argc < 2)
        return 1;
    int64_t a = (int64_t)strtoll(argv[1], NULL, 10);
    INDEX  s = ret64(a);
    printf("%lld\n", (long long)s);
    return 0;
}
$ gcc -m64 -g -DINDEX=int32_t -c -o call32_64.o call.c
$ gcc -m64 -g -DINDEX=size_t -c -o call64_64.o call.c
$ ./call32_64 1
1
$ ./call64_64 1
4294967297

楽しい。 32ビットで可能な以上のものを提供する32ビットの戻り値。 これは、(原則として)NetlibCBLASの現在の状態がsize_tを期待するコードにリンクされている場合に発生する可能性があることです。 実際のコードでは、RAXの上位32ビットはゼロになると思います。 しかし、誰が知っているのか…コンパイラは、呼び出し元がどのプラットフォームでも下位32ビットを超えて使用しないことを期待しています…そこにガベージを格納することもできます。

それで…Netlibを戻り値としてsize_tに戻すことに同意しますか?

これらすべての貴重なコメントをありがとう!

このトピックについては@langouと少し話し合いました。 ここでの議論に基づいて、私の提案は次のとおりです。

別のPRで:

  1. 2つの整数定義を使用するcblas.h戻ります。たとえば、CBLAS_INDEXとCBLAS_INTです。 これが、MKL(CBLAS_INDEXおよびMKL_INT)およびOpenBLAS(CBLAS_INDEXおよびblasint)で発生することです。 CBLAS_INDEXは、 i*amaxのリターンでのみ使用されます。 これで、他のBLASと互換性のあるABIを復元します。
  2. さらに、CBLAS_INDEXのデフォルト値をsize_tし、コミュニティから意見を収集します。

これは、このスレッドでの最近の議論の背後にある考え方と一致している(または同じかもしれない)と思います。
@drhpcが指摘したように、
https://github.com/Reference-LAPACK/lapack/commit/83fc0b48afd1f9a6d6f8dddb16e69ed7ed0e7242は、CBLAS_INDEXのデフォルト値を変更し、
https://github.com/Reference-LAPACK/lapack/commit/41779680d1f233928b67f5f66c0b239aecb42774はCBLAS_INDEXの使用を変更しました。

補強するためだけに:

  • OpenBLAS、MKL、GNU Scientific Library、およびNumpyはすべて、デフォルトでsize_tを使用します。
  • BLASのCインターフェース(https://www.netlib.org/blas/blast-forum/cinterface.pdf)は、通常、 CBLAS_INDEX = size_tことを示しています。

同意しますか? もしそうなら、私はPRを開くことができます。 あるいは、 @ drhpc

同意します。 そして、PRを進めてください。

@ mgates3は、スレートGoogleグループに関する議論について私に言及しました。
https://groups.google.com/a/icl.utk.edu/g/slate-user/c/f5y6gt0aoLs/m/oQyyhikwCgAJ
議論は「CBLAS_INDEX」がどうあるべきかではなく、「CBLAS_INT」がどうあるべきかについてです。 CBLAS_INTはsize_tまたは符号付き整数などである必要がありますか? 参加者の方が良い点を挙げていると思いますので、お伝えします。

#588をご覧ください。

そうです、 size_tは32ビットのままです。 long使用せずにint64_t使用するようにビルドをハッキングした後、64ビット整数を返すようにcblas_isamax()をビルドした場合、もちろん、本当にそのような使用法で起こりますか?

size_t cblas_isamax(); // really int64_t cblas_isamax()!
size_t value = cblas_isamax(…);

x86呼び出し規約は、64ビット値をEAXおよびEDXに入れる可能性があります。 または、ポインタリターンといくつかのバッファで動作する可能性があります。 しかし、他のアーキテクチャは何をしますか? したがって、破損することはないかもしれませんが、確かに間違った値です。 最良のケースは、上位32ビットが無視されることです。

ここで、ビッグエンディアンの32ビットシステム(何らかの形式のARM)を想像してみてください…値の必要な半分が返されることを確認しますか?

これはゲームオーバーです。 32ビットArmCPUでは、4つの32ビット値をレジスタに渡して返すことができます。64ビット値は2つの連続するレジスタを占有します。_Armアーキテクチャの手順呼び出し標準_のセクション6.1.1.1を参照してください。 呼び出し先は、1つのレジスタに書き込む代わりに、64ビット整数で2つのレジスタを乱雑にします。 これは明らかに問題です。 呼び出し元がパラメーターのレジスターを使い果たすとすぐに、スタックが使用されます。 スタックアラインメントは32ビットですが、32ビットの読み取りまたは書き込みの代わりに、呼び出し先は64ビットを書き込みます。 繰り返しますが、これはゲームオーバーであり、この問題(スタックの読み取り/書き込みサイズの不一致)は、ある時点ですべての命令セットアーキテクチャで問題を引き起こすはずです。

私が書いたコードでは、最終的に関数呼び出しのオフセットとしてインデックスを渡す場所で、それについて自分自身が正しいのだろうかと思っています。 インデックスは符号なし、オフセットは符号付きです。 コンパイラ(MSVC)が-unsigned_valueによって混乱していることを除けば、これは、変換で発生する可能性のあるオーバーフローについて常に心配する必要があることを意味します。

いいえ、CおよびC ++の背後にある標準委員会は、この場合、コードを明白な方法で動作させます。 uが符号なしの値で、 sが符号付きの値である場合、 u少なくともsと同じ数のビットがある場合、 u + sオーバーフローまたはアンダーフローしない限り、 u + sは数学的に正しい結果を生成します。 アンダーフロー/オーバーフローの場合、結果はラップアラウンドします。つまり、 (u + s) mod 2^b 。ここで、 bは、 usのビット数です。 一方、符号付き型が符号なし型のすべての値を表すことができる場合、符号なし値は符号なし型に変換されます。

C11標準ドラフトの関連条項は次のとおりです。

  • 6.2.5.9:符号なしオペランドのみの二項演算はオーバーフローできません。 結果はMAX + 1法として取得されます。ここで、 MAXは表現可能な最大値です。
  • 6.3.1.3は:符号付きの値が与えられるs 、それは符号なしの値に変換さをs場合s >= 0 、そうでない場合は、に変換されるs + MAX + 1
  • 6.3.1.8:[同じサイズの]符号付きおよび符号なしオペランドが符号なしに変換されます。 符号付き型が符号なし型のすべての値を表すことができる場合、符号なしオペランドは符号付き型に変換されます

したがって、 u + s (C構文)は次のように評価されます。

  • (u + s) mod (M + 1) if s >= 0
  • それ以外の場合は(u + s + M + 1) mod (M + 1)

オーバーフローまたはアンダーフローがない場合、この式はu + sと評価されます。これは、直感的に望ましい結果です。

これを調べたところ、C ++コンテナインデックスに符号なしの型を使用することは歴史的な誤りであり、size()メソッドの戻り型でさえも、すぐに符号付きと符号なしの数値が混在してしまうため、歴史的な誤りであると認めました。なんらかの方法で。

どこでも符号付き整数を使用することを提案しているC ++プログラマー(C ++の発明者を含む)がいます。C++コアガイドラインを参照してください。 「どこでも符号付き整数」ポリシーの問題は次のとおりです。

  • 最小値のチェック:符号なし整数の場合、最小値をチェックする必要がない場合が多く、符号付き整数の場合は必須です。 これはエラーが発生しやすく、セキュリティの問題を引き起こす可能性があります。たとえば、 CWE-839_最小チェックなしの数値範囲比較_を参照してください。
  • オーバーフロー:符号なしオーバーフローは明確に定義された結果をもたらしますが、符号付き整数オーバーフローは未定義の動作を構成します。

a + b < aを使用して符号付きオーバーフローをチェックすることはできますが、コンパイラは警告なしに最適化する可能性があります。たとえば、2007年のa符号なし、 b a符号付きの可能性があり、 bは最大でa同じ数のビットを持ちます)。 2020年の記事_OptOut–コンパイラの未定義動作の最適化_を見ると、GCCの動作は明らかに変更されていません。

このページは役に立ちましたか?
0 / 5 - 0 評価

関連する問題

hokb picture hokb  ·  16コメント

JHenneberg picture JHenneberg  ·  10コメント

5tefan picture 5tefan  ·  3コメント

Dichloromethane picture Dichloromethane  ·  11コメント

christoph-conrads picture christoph-conrads  ·  26コメント