You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.cmake 25 kB

2 months ago
2 months ago
5 years ago
8 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. ###############################################################################
  2. # Copyright (c) 2025, The OpenBLAS Project
  3. # All rights reserved.
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are
  6. # met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in
  11. # the documentation and/or other materials provided with the
  12. # distribution.
  13. # 3. Neither the name of the OpenBLAS project nor the names of
  14. # its contributors may be used to endorse or promote products
  15. # derived from this software without specific prior written permission.
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. # ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE
  20. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. # POSSIBILITY OF SUCH DAMAGE.
  27. ###############################################################################
  28. # Functions to help with the OpenBLAS build
  29. # Reads string from getarch into CMake vars. Format of getarch vars is VARNAME=VALUE
  30. function(ParseGetArchVars GETARCH_IN)
  31. string(REGEX MATCHALL "[0-9_a-zA-Z]+=[0-9_a-zA-Z]+" GETARCH_RESULT_LIST "${GETARCH_IN}")
  32. foreach (GETARCH_LINE ${GETARCH_RESULT_LIST})
  33. # split the line into var and value, then assign the value to a CMake var
  34. string(REGEX MATCHALL "[0-9_a-zA-Z]+" SPLIT_VAR "${GETARCH_LINE}")
  35. list(GET SPLIT_VAR 0 VAR_NAME)
  36. list(GET SPLIT_VAR 1 VAR_VALUE)
  37. set(${VAR_NAME} ${VAR_VALUE} PARENT_SCOPE)
  38. endforeach ()
  39. endfunction ()
  40. # Reads a Makefile into CMake vars.
  41. macro(ParseMakefileVars MAKEFILE_IN)
  42. message(STATUS "Reading vars from ${MAKEFILE_IN}...")
  43. set (C_COMPILER ${CMAKE_C_COMPILER_ID})
  44. set (OSNAME ${CMAKE_SYSTEM_NAME})
  45. if (${C_COMPILER} MATCHES Clang)
  46. set (C_COMPILER CLANG)
  47. endif ()
  48. if (${OSNAME} STREQUAL Windows)
  49. set (OSNAME WINNT)
  50. endif ()
  51. message(STATUS OS ${OSNAME} COMPILER ${C_COMPILER})
  52. set (IfElse 0)
  53. set (ElseSeen 0)
  54. set (SkipIfs 0)
  55. set (SkipElse 0)
  56. file(STRINGS ${MAKEFILE_IN} makefile_contents)
  57. foreach (makefile_line ${makefile_contents})
  58. #message(STATUS "parsing ${makefile_line}")
  59. # Skip the entire scope of the else statement given that the if statement that precedes it has the valid condition.
  60. # The variable SkipIfs is used to identify which endif statement closes the scope of the else statement.
  61. if (${SkipElse} EQUAL 1)
  62. #message(STATUS "skipping ${makefile_line}")
  63. string(REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}")
  64. if (NOT "${line_match}" STREQUAL "")
  65. MATH(EXPR SkipIfs "${SkipIfs}+1")
  66. endif ()
  67. string(REGEX MATCH "endif[ \t]*" line_match "${makefile_line}")
  68. if (NOT "${line_match}" STREQUAL "")
  69. if (${SkipIfs} EQUAL 0)
  70. set (SkipElse 0)
  71. else ()
  72. MATH(EXPR SkipIfs "${SkipIfs}-1")
  73. endif ()
  74. endif ()
  75. continue ()
  76. endif ()
  77. # The variable IfElse is greater than 0 if and only if the previously parsed line is an if statement.
  78. if (${IfElse} GREATER 0)
  79. # If the current scope is the one that has to be skipped, the if/endif/else statements
  80. # along with it till the endif that closes the current scope have to be ignored as well.
  81. string(REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}")
  82. if (NOT "${line_match}" STREQUAL "")
  83. if ((${IfElse} EQUAL 2 AND ${ElseSeen} EQUAL 0) OR (${IfElse} EQUAL 1 AND ${ElseSeen} EQUAL 1))
  84. #message(STATUS "skipping ${makefile_line}")
  85. MATH(EXPR SkipIfs "${SkipIfs}+1")
  86. continue ()
  87. endif ()
  88. endif ()
  89. string(REGEX MATCH "endif[ \t]*" line_match "${makefile_line}")
  90. if (NOT "${line_match}" STREQUAL "")
  91. if (${SkipIfs} EQUAL 0)
  92. #message(STATUS "ENDIF ${makefile_line}")
  93. set (IfElse 0)
  94. set (ElseSeen 0)
  95. else ()
  96. #message(STATUS "skipping ${makefile_line}")
  97. MATH(EXPR SkipIfs "${SkipIfs}-1")
  98. endif ()
  99. continue ()
  100. endif ()
  101. string(REGEX MATCH "else[ \t]*" line_match "${makefile_line}")
  102. if (NOT "${line_match}" STREQUAL "")
  103. if (${SkipIfs} EQUAL 0)
  104. #message(STATUS "ELSE ${makefile_line}")
  105. set (ElseSeen 1)
  106. else ()
  107. #message(STATUS "skipping ${makefile_line}")
  108. endif ()
  109. continue ()
  110. endif()
  111. # Skip the lines that are not part of the path that has to be taken.
  112. if ((${IfElse} EQUAL 2 AND ${ElseSeen} EQUAL 0) OR (${IfElse} EQUAL 1 AND ${ElseSeen} EQUAL 1) OR (${SkipIfs} GREATER 0))
  113. #message(STATUS "skipping ${makefile_line}")
  114. continue ()
  115. endif ()
  116. endif ()
  117. # Skip commented lines (the ones that start with '#')
  118. string(REGEX MATCH "[ \t]*\\#.*$" line_match "${makefile_line}")
  119. if (NOT "${line_match}" STREQUAL "")
  120. #message(STATUS "skipping ${makefile_line}")
  121. continue ()
  122. endif ()
  123. # Example 1: SBGEMM_SMALL_M_PERMIT =
  124. # Unset the variable
  125. string(REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*$" line_match "${makefile_line}")
  126. if (NOT "${line_match}" STREQUAL "")
  127. set(var_name ${CMAKE_MATCH_1})
  128. unset(${var_name})
  129. endif()
  130. string(REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*(.+)$" line_match "${makefile_line}")
  131. if (NOT "${line_match}" STREQUAL "")
  132. #message(STATUS "match on ${line_match}")
  133. set(var_name ${CMAKE_MATCH_1})
  134. #set(var_value ${CMAKE_MATCH_2})
  135. string(STRIP ${CMAKE_MATCH_2} var_value)
  136. # check for Makefile variables in the string, e.g. $(TSUFFIX)
  137. string(REGEX MATCHALL "\\$\\(([0-9_a-zA-Z]+)\\)" make_var_matches ${var_value})
  138. foreach (make_var ${make_var_matches})
  139. # strip out Makefile $() markup
  140. string(REGEX REPLACE "\\$\\(([0-9_a-zA-Z]+)\\)" "\\1" make_var ${make_var})
  141. # now replace the instance of the Makefile variable with the value of the CMake variable (note the double quote)
  142. string(REPLACE "$(${make_var})" "${${make_var}}" var_value ${var_value})
  143. endforeach ()
  144. set(${var_name} ${var_value})
  145. continue ()
  146. endif ()
  147. # Include a new file to be parsed
  148. string(REGEX MATCH "include \\$\\(KERNELDIR\\)/(.+)$" line_match "${makefile_line}")
  149. if (NOT "${line_match}" STREQUAL "")
  150. #message(STATUS "match on include ${line_match}")
  151. ParseMakefileVars(${KERNELDIR}/${CMAKE_MATCH_1})
  152. continue ()
  153. endif ()
  154. # The if statement that precedes this else has the path taken
  155. # Thus, this else statement has to be skipped.
  156. string(REGEX MATCH "else[ \t]*" line_match "${makefile_line}")
  157. if (NOT "${line_match}" STREQUAL "")
  158. #message(STATUS "skipping ${makefile_line}")
  159. set (SkipElse 1)
  160. continue()
  161. endif()
  162. # Example 1: ifdef HAVE_MSA
  163. # Example 2: ifndef ZNRM2KERNEL
  164. string(REGEX MATCH "(ifdef|ifndef) ([0-9_A-Z]+)" line_match "${makefile_line}")
  165. if (NOT "${line_match}" STREQUAL "")
  166. #message(STATUS "${CMAKE_MATCH_1} first: ${CMAKE_MATCH_2}")
  167. set (ElseSeen 0)
  168. if (${CMAKE_MATCH_2})
  169. if (${CMAKE_MATCH_1} STREQUAL "ifdef")
  170. #message (STATUS "condition is true")
  171. set (IfElse 1)
  172. else ()
  173. set (IfElse 2)
  174. endif ()
  175. else ()
  176. if (${CMAKE_MATCH_1} STREQUAL "ifdef")
  177. set (IfElse 2)
  178. else ()
  179. #message (STATUS "condition is true")
  180. set (IfElse 1)
  181. endif ()
  182. endif ()
  183. continue ()
  184. endif ()
  185. # Example 1: ifeq ($(SGEMM_UNROLL_M), 16)
  186. # Example 2: ifeq ($(SGEMM_UNROLL_M)x$(SGEMM_UNROLL_N), 8x8)
  187. # Example 3: ifeq ($(__BYTE_ORDER__)$(ELF_VERSION),__ORDER_BIG_ENDIAN__2)
  188. # Ignore the second group since (?:...) does not work on cmake
  189. string(REGEX MATCH "ifeq \\(\\$\\(([0-9_A-Z]+)\\)(([0-9_A-Za-z]*)\\$\\(([0-9_A-Z]+)\\))?,[ \t]*([0-9_A-Za-z]+)\\)" line_match "${makefile_line}")
  190. if (NOT "${line_match}" STREQUAL "")
  191. #message(STATUS "IFEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4} fourth: ${CMAKE_MATCH_5}")
  192. if (DEFINED ${CMAKE_MATCH_1})
  193. if (DEFINED ${CMAKE_MATCH_4})
  194. set (STR ${${CMAKE_MATCH_1}}${CMAKE_MATCH_3}${${CMAKE_MATCH_4}})
  195. else ()
  196. set (STR ${${CMAKE_MATCH_1}})
  197. endif ()
  198. if (${STR} STREQUAL ${CMAKE_MATCH_5})
  199. #message (STATUS "condition is true")
  200. set (IfElse 1)
  201. continue ()
  202. endif ()
  203. endif ()
  204. set (IfElse 2)
  205. continue ()
  206. endif ()
  207. # Example 1 (Group 3): ifneq ($(SGEMM_UNROLL_M), $(SGEMM_UNROLL_N))
  208. # Example 2 (Group 4): ifneq ($(C_COMPILER), PGI)
  209. string(REGEX MATCH "ifneq \\(\\$\\(([0-9_A-Z]+)\\),[ \t]*(\\$\\(([0-9_A-Z]+)\\)|([0-9_A-Z]+))\\)" line_match "${makefile_line}")
  210. if (NOT "${line_match}" STREQUAL "")
  211. #message(STATUS "IFNEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4}")
  212. set (ElseSeen 0)
  213. set (HasValidGroup 0)
  214. if (DEFINED ${CMAKE_MATCH_3})
  215. set (HasValidGroup 1)
  216. set (STR ${${CMAKE_MATCH_3}})
  217. elseif (NOT ${CMAKE_MATCH_4} STREQUAL "")
  218. set (HasValidGroup 1)
  219. set (STR ${CMAKE_MATCH_4})
  220. endif ()
  221. if (DEFINED CMAKE_MATCH_1 AND ${HasValidGroup} EQUAL 1)
  222. if (NOT (CMAKE_MATCH_1 STREQUAL ${STR}))
  223. #message (STATUS "condition is true")
  224. set (IfElse 1)
  225. continue ()
  226. endif ()
  227. endif ()
  228. set (IfElse 2)
  229. continue ()
  230. endif ()
  231. #message(STATUS "unmatched line ${line_match}")
  232. endforeach ()
  233. endmacro ()
  234. # Returns all combinations of the input list, as a list with colon-separated combinations
  235. # E.g. input of A B C returns A B C A:B A:C B:C
  236. # N.B. The input is meant to be a list, and to past a list to a function in CMake you must quote it (e.g. AllCombinations("${LIST_VAR}")).
  237. # #param absent_codes codes to use when an element is absent from a combination. For example, if you have TRANS;UNIT;UPPER you may want the code to be NNL when nothing is present.
  238. # @returns LIST_OUT a list of combinations
  239. # CODES_OUT a list of codes corresponding to each combination, with N meaning the item is not present, and the first letter of the list item meaning it is presen
  240. function(AllCombinations list_in absent_codes_in)
  241. list(LENGTH list_in list_count)
  242. set(num_combos 1)
  243. # subtract 1 since we will iterate from 0 to num_combos
  244. math(EXPR num_combos "(${num_combos} << ${list_count}) - 1")
  245. set(LIST_OUT "")
  246. set(CODES_OUT "")
  247. foreach (c RANGE 0 ${num_combos})
  248. set(current_combo "")
  249. set(current_code "")
  250. # this is a little ridiculous just to iterate through a list w/ indices
  251. math(EXPR last_list_index "${list_count} - 1")
  252. foreach (list_index RANGE 0 ${last_list_index})
  253. math(EXPR bit "1 << ${list_index}")
  254. math(EXPR combo_has_bit "${c} & ${bit}")
  255. list(GET list_in ${list_index} list_elem)
  256. if (combo_has_bit)
  257. if (current_combo)
  258. set(current_combo "${current_combo}:${list_elem}")
  259. else ()
  260. set(current_combo ${list_elem})
  261. endif ()
  262. string(SUBSTRING ${list_elem} 0 1 code_char)
  263. else ()
  264. list(GET absent_codes_in ${list_index} code_char)
  265. endif ()
  266. set(current_code "${current_code}${code_char}")
  267. endforeach ()
  268. if (current_combo STREQUAL "")
  269. list(APPEND LIST_OUT " ") # Empty set is a valid combination, but CMake isn't appending the empty string for some reason, use a space
  270. else ()
  271. list(APPEND LIST_OUT ${current_combo})
  272. endif ()
  273. list(APPEND CODES_OUT ${current_code})
  274. endforeach ()
  275. set(LIST_OUT ${LIST_OUT} PARENT_SCOPE)
  276. set(CODES_OUT ${CODES_OUT} PARENT_SCOPE)
  277. endfunction ()
  278. # generates object files for each of the sources, using the BLAS naming scheme to pass the function name as a preprocessor definition
  279. # @param sources_in the source files to build from
  280. # @param defines_in (optional) preprocessor definitions that will be applied to all objects
  281. # @param name_in (optional) if this is set this name will be used instead of the filename. Use a * to indicate where the float character should go, if no star the character will be prepended.
  282. # e.g. with DOUBLE set, "i*max" will generate the name "idmax", and "max" will be "dmax"
  283. # @param replace_last_with replaces the last character in the filename with this string (e.g. symm_k should be symm_TU)
  284. # @param append_with appends the filename with this string (e.g. trmm_R should be trmm_RTUU or some other combination of characters)
  285. # @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
  286. # @param complex_filename_scheme some routines have separate source files for complex and non-complex float types.
  287. # 0 - compiles for all types
  288. # 1 - compiles the sources for non-complex types only (SINGLE/DOUBLE)
  289. # 2 - compiles for complex types only (COMPLEX/DOUBLE COMPLEX)
  290. # 3 - compiles for all types, but changes source names for complex by prepending z (e.g. axpy.c becomes zaxpy.c)
  291. # 4 - compiles for complex types only, but changes source names for complex by prepending z (e.g. hemv.c becomes zhemv.c)
  292. # STRING - compiles only the given type (e.g. DOUBLE)
  293. function(GenerateNamedObjects sources_in)
  294. if (${ARGC} GREATER 1)
  295. set(defines_in ${ARGV1})
  296. endif ()
  297. if (${ARGC} GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
  298. set(name_in ${ARGV2})
  299. # strip off extension for kernel files that pass in the object name.
  300. get_filename_component(name_in ${name_in} NAME_WE)
  301. endif ()
  302. if (${ARGC} GREATER 3)
  303. set(use_cblas ${ARGV3})
  304. else ()
  305. set(use_cblas false)
  306. endif ()
  307. if (${ARGC} GREATER 4)
  308. set(replace_last_with ${ARGV4})
  309. endif ()
  310. if (${ARGC} GREATER 5)
  311. set(append_with ${ARGV5})
  312. endif ()
  313. if (${ARGC} GREATER 6)
  314. set(no_float_type ${ARGV6})
  315. else ()
  316. set(no_float_type false)
  317. endif ()
  318. if (no_float_type)
  319. set(float_list "DUMMY") # still need to loop once
  320. else ()
  321. set(float_list "${FLOAT_TYPES}")
  322. endif ()
  323. set(real_only false)
  324. set(complex_only false)
  325. set(mangle_complex_sources false)
  326. if (${ARGC} GREATER 7 AND NOT "${ARGV7}" STREQUAL "")
  327. if (${ARGV7} EQUAL 1)
  328. set(real_only true)
  329. elseif (${ARGV7} EQUAL 2)
  330. set(complex_only true)
  331. elseif (${ARGV7} EQUAL 3)
  332. set(mangle_complex_sources true)
  333. elseif (${ARGV7} EQUAL 4)
  334. set(mangle_complex_sources true)
  335. set(complex_only true)
  336. elseif (NOT ${ARGV7} EQUAL 0)
  337. set(float_list ${ARGV7})
  338. endif ()
  339. endif ()
  340. if (complex_only)
  341. list(REMOVE_ITEM float_list "SINGLE")
  342. list(REMOVE_ITEM float_list "DOUBLE")
  343. list(REMOVE_ITEM float_list "BFLOAT16")
  344. elseif (real_only)
  345. list(REMOVE_ITEM float_list "COMPLEX")
  346. list(REMOVE_ITEM float_list "ZCOMPLEX")
  347. endif ()
  348. set(float_char "")
  349. set(OBJ_LIST_OUT "")
  350. foreach (float_type ${float_list})
  351. foreach (source_file ${sources_in})
  352. if (NOT no_float_type)
  353. string(SUBSTRING ${float_type} 0 1 float_char)
  354. string(TOLOWER ${float_char} float_char)
  355. if (${float_type} STREQUAL "BFLOAT16" AND NOT "${defines_in}" MATCHES "BGEMM")
  356. set (float_char "sb")
  357. endif ()
  358. endif ()
  359. if (NOT name_in)
  360. get_filename_component(source_name ${source_file} NAME_WE)
  361. set(obj_name "${float_char}${source_name}")
  362. else ()
  363. # replace * with float_char
  364. if (${name_in} MATCHES "\\*")
  365. string(REPLACE "*" ${float_char} obj_name ${name_in})
  366. else ()
  367. set(obj_name "${float_char}${name_in}")
  368. endif ()
  369. endif ()
  370. if (replace_last_with)
  371. string(REGEX REPLACE ".$" ${replace_last_with} obj_name ${obj_name})
  372. else ()
  373. set(obj_name "${obj_name}${append_with}")
  374. endif ()
  375. # now add the object and set the defines
  376. set(obj_defines ${defines_in})
  377. list(FIND obj_defines "RC" def_idx)
  378. if (${def_idx} GREATER -1)
  379. # list(REMOVE_AT ${obj_defines} ${def_idx})
  380. list (REMOVE_ITEM obj_defines "RC")
  381. list(APPEND obj_defines "RC=RC")
  382. endif ()
  383. list(FIND obj_defines "CR" def_idx)
  384. if (${def_idx} GREATER -1)
  385. # list(REMOVE_AT ${obj_defines} ${def_idx})
  386. list (REMOVE_ITEM obj_defines "CR")
  387. list(APPEND obj_defines "CR=CR")
  388. endif ()
  389. if (use_cblas)
  390. set(obj_name "cblas_${obj_name}")
  391. list(APPEND obj_defines "CBLAS")
  392. elseif (NOT "${obj_name}" MATCHES "${ARCH_SUFFIX}")
  393. set(obj_name "${obj_name}${ARCH_SUFFIX}")
  394. endif ()
  395. list(APPEND obj_defines "ASMNAME=${FU}${obj_name};ASMFNAME=${FU}${obj_name}${BU};NAME=${obj_name}${BU};CNAME=${obj_name};CHAR_NAME=\"${obj_name}${BU}\";CHAR_CNAME=\"${obj_name}\"")
  396. if (${float_type} STREQUAL "DOUBLE" OR ${float_type} STREQUAL "ZCOMPLEX")
  397. list(APPEND obj_defines "DOUBLE")
  398. endif ()
  399. if (${float_type} STREQUAL "BFLOAT16")
  400. list(APPEND obj_defines "BFLOAT16")
  401. endif ()
  402. if (${float_type} STREQUAL "COMPLEX" OR ${float_type} STREQUAL "ZCOMPLEX")
  403. list(APPEND obj_defines "COMPLEX")
  404. if (mangle_complex_sources)
  405. # add a z to the filename
  406. get_filename_component(source_name ${source_file} NAME)
  407. get_filename_component(source_dir ${source_file} DIRECTORY)
  408. string(REPLACE ${source_name} "z${source_name}" source_file ${source_file})
  409. endif ()
  410. endif ()
  411. if (VERBOSE_GEN)
  412. message(STATUS "${obj_name}:${source_file}")
  413. message(STATUS "${obj_defines}")
  414. endif ()
  415. # create a copy of the source to avoid duplicate obj filename problem with ar.exe
  416. get_filename_component(source_extension ${source_file} EXT)
  417. set(new_source_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${obj_name}${source_extension}")
  418. if (IS_ABSOLUTE ${source_file})
  419. set(old_source_file ${source_file})
  420. else ()
  421. set(old_source_file "${CMAKE_CURRENT_LIST_DIR}/${source_file}")
  422. endif ()
  423. string(REPLACE ";" "\n#define " define_source "${obj_defines}")
  424. string(REPLACE "=" " " define_source "${define_source}")
  425. file(WRITE ${new_source_file}.tmp "#define ${define_source}\n#include \"${old_source_file}\"")
  426. configure_file(${new_source_file}.tmp ${new_source_file} COPYONLY)
  427. file(REMOVE ${new_source_file}.tmp)
  428. list(APPEND SRC_LIST_OUT ${new_source_file})
  429. message (STATUS ${new_source_file})
  430. if (DEFINED HAVE_FMA3)
  431. if ( ${new_source_file} MATCHES "(s|d?)rot_k.*c")
  432. set_source_files_properties(${new_source_file} PROPERTIES COMPILE_OPTIONS "-mfma")
  433. endif ()
  434. if ( ${new_source_file} MATCHES "dgemv_t_k.*c")
  435. set_source_files_properties(${new_source_file} PROPERTIES COMPILE_OPTIONS "-mfma")
  436. endif ()
  437. endif ()
  438. endforeach ()
  439. endforeach ()
  440. list(APPEND OPENBLAS_SRC ${SRC_LIST_OUT})
  441. set(OPENBLAS_SRC ${OPENBLAS_SRC} PARENT_SCOPE)
  442. endfunction ()
  443. # generates object files for each of the sources for each of the combinations of the preprocessor definitions passed in
  444. # @param sources_in the source files to build from
  445. # @param defines_in the preprocessor definitions that will be combined to create the object files
  446. # @param all_defines_in (optional) preprocessor definitions that will be applied to all objects
  447. # @param replace_scheme If 1, replace the "k" in the filename with the define combo letters. E.g. symm_k.c with TRANS and UNIT defined will be symm_TU.
  448. # If 0, it will simply append the code, e.g. symm_L.c with TRANS and UNIT will be symm_LTU.
  449. # If 2, it will append the code with an underscore, e.g. symm.c with TRANS and UNIT will be symm_TU.
  450. # If 3, it will insert the code *around* the last character with an underscore, e.g. symm_L.c with TRANS and UNIT will be symm_TLU (required by BLAS level2 objects).
  451. # If 4, it will insert the code before the last underscore. E.g. trtri_U_parallel with TRANS will be trtri_UT_parallel
  452. # @param alternate_name replaces the source name as the object name (define codes are still appended)
  453. # @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
  454. # @param complex_filename_scheme see GenerateNamedObjects
  455. function(GenerateCombinationObjects sources_in defines_in absent_codes_in all_defines_in replace_scheme)
  456. set(alternate_name_in "")
  457. if (${ARGC} GREATER 5)
  458. set(alternate_name_in ${ARGV5})
  459. endif ()
  460. set(no_float_type false)
  461. if (${ARGC} GREATER 6)
  462. set(no_float_type ${ARGV6})
  463. endif ()
  464. set(complex_filename_scheme "")
  465. if (${ARGC} GREATER 7)
  466. set(complex_filename_scheme ${ARGV7})
  467. endif ()
  468. AllCombinations("${defines_in}" "${absent_codes_in}")
  469. set(define_combos ${LIST_OUT})
  470. set(define_codes ${CODES_OUT})
  471. list(LENGTH define_combos num_combos)
  472. math(EXPR num_combos "${num_combos} - 1")
  473. foreach (c RANGE 0 ${num_combos})
  474. list(GET define_combos ${c} define_combo)
  475. list(GET define_codes ${c} define_code)
  476. foreach (source_file ${sources_in})
  477. set(alternate_name ${alternate_name_in})
  478. # replace colon separated list with semicolons, this turns it into a CMake list that we can use foreach with
  479. string(REPLACE ":" ";" define_combo ${define_combo})
  480. # now add the object and set the defines
  481. set(cur_defines ${define_combo})
  482. if ("${cur_defines}" STREQUAL " ")
  483. set(cur_defines ${all_defines_in})
  484. else ()
  485. list(APPEND cur_defines ${all_defines_in})
  486. endif ()
  487. set(replace_code "")
  488. set(append_code "")
  489. if (replace_scheme EQUAL 1)
  490. set(replace_code ${define_code})
  491. else ()
  492. if (replace_scheme EQUAL 2)
  493. set(append_code "_${define_code}")
  494. elseif (replace_scheme EQUAL 3)
  495. if ("${alternate_name}" STREQUAL "")
  496. string(REGEX MATCH "[a-zA-Z]\\." last_letter ${source_file})
  497. else ()
  498. string(REGEX MATCH "[a-zA-Z]$" last_letter ${alternate_name})
  499. endif ()
  500. # first extract the last letter
  501. string(SUBSTRING ${last_letter} 0 1 last_letter) # remove period from match
  502. # break the code up into the first letter and the remaining (should only be 2 anyway)
  503. string(SUBSTRING ${define_code} 0 1 define_code_first)
  504. string(SUBSTRING ${define_code} 1 -1 define_code_second)
  505. set(replace_code "${define_code_first}${last_letter}${define_code_second}")
  506. elseif (replace_scheme EQUAL 4)
  507. # insert code before the last underscore and pass that in as the alternate_name
  508. if ("${alternate_name}" STREQUAL "")
  509. get_filename_component(alternate_name ${source_file} NAME_WE)
  510. endif ()
  511. set(extra_underscore "")
  512. # check if filename has two underscores, insert another if not (e.g. getrs_parallel needs to become getrs_U_parallel not getrsU_parallel)
  513. string(REGEX MATCH "_[a-zA-Z]+_" underscores ${alternate_name})
  514. string(LENGTH "${underscores}" underscores)
  515. if (underscores EQUAL 0)
  516. set(extra_underscore "_")
  517. endif ()
  518. string(REGEX REPLACE "(.+)(_[^_]+)$" "\\1${extra_underscore}${define_code}\\2" alternate_name ${alternate_name})
  519. else()
  520. set(append_code ${define_code}) # replace_scheme should be 0
  521. endif ()
  522. endif ()
  523. GenerateNamedObjects("${source_file}" "${cur_defines}" "${alternate_name}" false "${replace_code}" "${append_code}" "${no_float_type}" "${complex_filename_scheme}")
  524. endforeach ()
  525. endforeach ()
  526. set(OPENBLAS_SRC ${OPENBLAS_SRC} PARENT_SCOPE)
  527. endfunction ()