1+ #include " AutoDetect.h"
2+
3+ #include < stdint.h>
4+
5+ // declare Metis with 32-bit integers for the test
6+ #define IDXTYPEWIDTH 32
7+ #include " metis.h"
8+
9+ // Weird tricks to detect the integer type width used by BLAS and Metis.
10+ // These are technically undefined behaviour, because they rely on using a
11+ // function declaration that involves a certain integer type, while the actual
12+ // implementation may use a different one. Their behaviour may depend on the
13+ // endianness of the CPU (?).
14+
15+ namespace hipo {
16+
17+ extern " C" {
18+ int64_t cblas_isamax (const int64_t N, const float * X, const int64_t incX);
19+ }
20+ IntegerModel getBlasIntegerModel () {
21+ // Test if BLAS uses 32-bit integers (LP64) or 64-bit integers (ILP64) at
22+ // runtime. Inspired by libblastrampoline's autodetection.c
23+
24+ // Even though isamax is declared to use 64-bit integers, it may actually
25+ // use 32-bit integers. If a negative number is passed as first argument,
26+ // isamax returns 0. If the correct value of 3 is passed, it returns 2
27+ // instead.
28+
29+ static IntegerModel blas_model = IntegerModel::not_set;
30+
31+ if (blas_model == IntegerModel::not_set) {
32+ // This is a very negative 64-bit number, but it is just 3 if only the lower
33+ // 32 bits are used.
34+ const int64_t n = 0xffffffff00000003 ;
35+
36+ const float X[3 ] = {1 .0f , 2 .0f , 3 .0f };
37+
38+ const int64_t incx = 1 ;
39+ int64_t max_idx = cblas_isamax (n, X, incx);
40+
41+ // Ignore potential upper 32 bits of the result
42+ max_idx = max_idx & 0xffffffff ;
43+
44+ if (max_idx == 0 ) {
45+ // isamax read negative n and returned 0, so it's using ilp64
46+ blas_model = IntegerModel::ilp64;
47+
48+ } else if (max_idx == 2 ) {
49+ // isamax read correct n and returned 2, so it's using lp64
50+ blas_model = IntegerModel::lp64;
51+
52+ } else {
53+ // something went wrong
54+ blas_model = IntegerModel::unknown;
55+ }
56+ }
57+
58+ return blas_model;
59+ }
60+
61+ std::string getIntegerModelString (IntegerModel i) {
62+ switch (i) {
63+ case IntegerModel::not_set:
64+ return " Not set" ;
65+
66+ case IntegerModel::unknown:
67+ return " Unknown" ;
68+
69+ case IntegerModel::lp64:
70+ return " LP64" ;
71+
72+ case IntegerModel::ilp64:
73+ return " ILP64" ;
74+ }
75+ }
76+
77+ IntegerModel getMetisIntegerModel () {
78+ static IntegerModel metis_model = IntegerModel::not_set;
79+
80+ if (metis_model == IntegerModel::not_set) {
81+ idx_t options[METIS_NOPTIONS];
82+ for (int i = 0 ; i < METIS_NOPTIONS; ++i) options[i] = -1 ;
83+
84+ // if 32 bits are used, this sets iptype to 2, otherwise it sets objtype to
85+ // a wrong value
86+ options[METIS_OPTION_IPTYPE] = 2 ;
87+
88+ idx_t n = 3 ;
89+ idx_t ptr[4 ] = {0 , 2 , 4 , 6 };
90+ idx_t rows[6 ] = {1 , 2 , 0 , 2 , 0 , 1 };
91+ idx_t perm[3 ], iperm[3 ];
92+
93+ idx_t status = METIS_NodeND (&n, ptr, rows, NULL , options, perm, iperm);
94+
95+ if (status == METIS_OK) {
96+ if (perm[0 ] != 0 || perm[1 ] != 1 || perm[2 ] != 2 )
97+ metis_model = IntegerModel::unknown;
98+ else
99+ metis_model = IntegerModel::lp64;
100+ } else if (status == METIS_ERROR_INPUT) {
101+ metis_model = IntegerModel::ilp64;
102+ } else {
103+ metis_model = IntegerModel::unknown;
104+ }
105+ }
106+
107+ return metis_model;
108+ }
109+ } // namespace hipo
0 commit comments