2025-07-09 06:47:20 +08:00
###############################################################################
# Copyright (c) 2025, The OpenBLAS Project
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name of the OpenBLAS project nor the names of
# its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###############################################################################
2015-01-31 03:47:40 +08:00
# Functions to help with the OpenBLAS build
# Reads string from getarch into CMake vars. Format of getarch vars is VARNAME=VALUE
function ( ParseGetArchVars GETARCH_IN )
string ( REGEX MATCHALL "[0-9_a-zA-Z]+=[0-9_a-zA-Z]+" GETARCH_RESULT_LIST "${GETARCH_IN}" )
foreach ( GETARCH_LINE ${ GETARCH_RESULT_LIST } )
# split the line into var and value, then assign the value to a CMake var
string ( REGEX MATCHALL "[0-9_a-zA-Z]+" SPLIT_VAR "${GETARCH_LINE}" )
list ( GET SPLIT_VAR 0 VAR_NAME )
list ( GET SPLIT_VAR 1 VAR_VALUE )
set ( ${ VAR_NAME } ${ VAR_VALUE } PARENT_SCOPE )
endforeach ( )
endfunction ( )
2015-02-18 11:36:23 +08:00
# Reads a Makefile into CMake vars.
2015-02-18 12:09:41 +08:00
macro ( ParseMakefileVars MAKEFILE_IN )
2015-02-18 11:36:23 +08:00
message ( STATUS "Reading vars from ${MAKEFILE_IN}..." )
2021-11-25 04:07:28 +08:00
set ( C_COMPILER ${ CMAKE_C_COMPILER_ID } )
2025-01-23 02:51:43 +08:00
set ( OSNAME ${ CMAKE_SYSTEM_NAME } )
if ( ${ C_COMPILER } MATCHES Clang )
set ( C_COMPILER CLANG )
endif ( )
if ( ${ OSNAME } STREQUAL Windows )
set ( OSNAME WINNT )
endif ( )
message ( STATUS OS ${ OSNAME } COMPILER ${ C_COMPILER } )
2021-11-25 04:07:28 +08:00
set ( IfElse 0 )
set ( ElseSeen 0 )
set ( SkipIfs 0 )
set ( SkipElse 0 )
2015-02-18 11:36:23 +08:00
file ( STRINGS ${ MAKEFILE_IN } makefile_contents )
foreach ( makefile_line ${ makefile_contents } )
2021-11-25 04:07:28 +08:00
#message(STATUS "parsing ${makefile_line}")
# Skip the entire scope of the else statement given that the if statement that precedes it has the valid condition.
# The variable SkipIfs is used to identify which endif statement closes the scope of the else statement.
if ( ${ SkipElse } EQUAL 1 )
#message(STATUS "skipping ${makefile_line}")
string ( REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
MATH ( EXPR SkipIfs "${SkipIfs}+1" )
endif ( )
string ( REGEX MATCH "endif[ \t]*" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
if ( ${ SkipIfs } EQUAL 0 )
set ( SkipElse 0 )
else ( )
MATH ( EXPR SkipIfs "${SkipIfs}-1" )
endif ( )
endif ( )
continue ( )
endif ( )
# The variable IfElse is greater than 0 if and only if the previously parsed line is an if statement.
2020-04-27 21:20:03 +08:00
if ( ${ IfElse } GREATER 0 )
2021-11-25 04:07:28 +08:00
# If the current scope is the one that has to be skipped, the if/endif/else statements
# along with it till the endif that closes the current scope have to be ignored as well.
string ( REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
if ( ( ${ IfElse } EQUAL 2 AND ${ ElseSeen } EQUAL 0 ) OR ( ${ IfElse } EQUAL 1 AND ${ ElseSeen } EQUAL 1 ) )
#message(STATUS "skipping ${makefile_line}")
MATH ( EXPR SkipIfs "${SkipIfs}+1" )
continue ( )
endif ( )
endif ( )
2020-04-27 21:20:03 +08:00
string ( REGEX MATCH "endif[ \t]*" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
2021-11-25 04:07:28 +08:00
if ( ${ SkipIfs } EQUAL 0 )
#message(STATUS "ENDIF ${makefile_line}")
set ( IfElse 0 )
set ( ElseSeen 0 )
else ( )
#message(STATUS "skipping ${makefile_line}")
MATH ( EXPR SkipIfs "${SkipIfs}-1" )
endif ( )
2020-04-27 21:20:03 +08:00
continue ( )
endif ( )
string ( REGEX MATCH "else[ \t]*" line_match "${makefile_line}" )
2021-11-25 04:07:28 +08:00
if ( NOT "${line_match}" STREQUAL "" )
if ( ${ SkipIfs } EQUAL 0 )
#message(STATUS "ELSE ${makefile_line}")
set ( ElseSeen 1 )
else ( )
#message(STATUS "skipping ${makefile_line}")
endif ( )
continue ( )
endif ( )
# Skip the lines that are not part of the path that has to be taken.
if ( ( ${ IfElse } EQUAL 2 AND ${ ElseSeen } EQUAL 0 ) OR ( ${ IfElse } EQUAL 1 AND ${ ElseSeen } EQUAL 1 ) OR ( ${ SkipIfs } GREATER 0 ) )
#message(STATUS "skipping ${makefile_line}")
continue ( )
2020-04-27 21:20:03 +08:00
endif ( )
2021-11-25 04:07:28 +08:00
endif ( )
# Skip commented lines (the ones that start with '#')
string ( REGEX MATCH "[ \t]*\\#.*$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "skipping ${makefile_line}")
continue ( )
endif ( )
2023-05-20 14:13:49 +08:00
# Example 1: SBGEMM_SMALL_M_PERMIT =
# Unset the variable
string ( REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
set ( var_name ${ CMAKE_MATCH_1 } )
unset ( ${ var_name } )
endif ( )
2015-02-18 11:36:23 +08:00
string ( REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*(.+)$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
2021-11-25 04:07:28 +08:00
#message(STATUS "match on ${line_match}")
2015-02-18 11:36:23 +08:00
set ( var_name ${ CMAKE_MATCH_1 } )
2021-11-25 04:07:28 +08:00
#set(var_value ${CMAKE_MATCH_2})
2020-05-09 19:42:33 +08:00
string ( STRIP ${ CMAKE_MATCH_2 } var_value )
2015-02-19 02:23:17 +08:00
# check for Makefile variables in the string, e.g. $(TSUFFIX)
string ( REGEX MATCHALL "\\$\\(([0-9_a-zA-Z]+)\\)" make_var_matches ${ var_value } )
foreach ( make_var ${ make_var_matches } )
# strip out Makefile $() markup
string ( REGEX REPLACE "\\$\\(([0-9_a-zA-Z]+)\\)" "\\1" make_var ${ make_var } )
# now replace the instance of the Makefile variable with the value of the CMake variable (note the double quote)
string ( REPLACE "$(${make_var})" "${${make_var}}" var_value ${ var_value } )
endforeach ( )
2015-02-18 12:09:41 +08:00
set ( ${ var_name } ${ var_value } )
2021-11-25 04:07:28 +08:00
continue ( )
endif ( )
# Include a new file to be parsed
string ( REGEX MATCH "include \\$\\(KERNELDIR\\)/(.+)$" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "match on include ${line_match}")
ParseMakefileVars ( ${ KERNELDIR } / ${ CMAKE_MATCH_1 } )
continue ( )
endif ( )
# The if statement that precedes this else has the path taken
# Thus, this else statement has to be skipped.
string ( REGEX MATCH "else[ \t]*" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "skipping ${makefile_line}")
set ( SkipElse 1 )
continue ( )
endif ( )
# Example 1: ifdef HAVE_MSA
# Example 2: ifndef ZNRM2KERNEL
string ( REGEX MATCH "(ifdef|ifndef) ([0-9_A-Z]+)" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "${CMAKE_MATCH_1} first: ${CMAKE_MATCH_2}")
set ( ElseSeen 0 )
2022-01-10 06:31:59 +08:00
if ( ${ CMAKE_MATCH_2 } )
2021-11-25 04:07:28 +08:00
if ( ${ CMAKE_MATCH_1 } STREQUAL "ifdef" )
#message (STATUS "condition is true")
set ( IfElse 1 )
else ( )
set ( IfElse 2 )
endif ( )
2020-04-27 21:20:03 +08:00
else ( )
2021-11-25 04:07:28 +08:00
if ( ${ CMAKE_MATCH_1 } STREQUAL "ifdef" )
set ( IfElse 2 )
else ( )
#message (STATUS "condition is true")
set ( IfElse 1 )
endif ( )
endif ( )
continue ( )
endif ( )
# Example 1: ifeq ($(SGEMM_UNROLL_M), 16)
# Example 2: ifeq ($(SGEMM_UNROLL_M)x$(SGEMM_UNROLL_N), 8x8)
# Example 3: ifeq ($(__BYTE_ORDER__)$(ELF_VERSION),__ORDER_BIG_ENDIAN__2)
# Ignore the second group since (?:...) does not work on cmake
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}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "IFEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4} fourth: ${CMAKE_MATCH_5}")
if ( DEFINED ${ CMAKE_MATCH_1 } )
if ( DEFINED ${ CMAKE_MATCH_4 } )
set ( STR ${ ${CMAKE_MATCH_1 } } ${ CMAKE_MATCH_3 } ${ ${CMAKE_MATCH_4 } } )
2020-04-27 21:20:03 +08:00
else ( )
2021-11-25 04:07:28 +08:00
set ( STR ${ ${CMAKE_MATCH_1 } } )
endif ( )
if ( ${ STR } STREQUAL ${ CMAKE_MATCH_5 } )
#message (STATUS "condition is true")
set ( IfElse 1 )
continue ( )
endif ( )
endif ( )
set ( IfElse 2 )
continue ( )
endif ( )
# Example 1 (Group 3): ifneq ($(SGEMM_UNROLL_M), $(SGEMM_UNROLL_N))
# Example 2 (Group 4): ifneq ($(C_COMPILER), PGI)
string ( REGEX MATCH "ifneq \\(\\$\\(([0-9_A-Z]+)\\),[ \t]*(\\$\\(([0-9_A-Z]+)\\)|([0-9_A-Z]+))\\)" line_match "${makefile_line}" )
if ( NOT "${line_match}" STREQUAL "" )
#message(STATUS "IFNEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4}")
set ( ElseSeen 0 )
set ( HasValidGroup 0 )
if ( DEFINED ${ CMAKE_MATCH_3 } )
set ( HasValidGroup 1 )
set ( STR ${ ${CMAKE_MATCH_3 } } )
elseif ( NOT ${ CMAKE_MATCH_4 } STREQUAL "" )
set ( HasValidGroup 1 )
set ( STR ${ CMAKE_MATCH_4 } )
endif ( )
2024-05-16 02:58:31 +08:00
if ( DEFINED CMAKE_MATCH_1 AND ${ HasValidGroup } EQUAL 1 )
if ( NOT ( CMAKE_MATCH_1 STREQUAL ${ STR } ) )
2021-11-25 04:07:28 +08:00
#message (STATUS "condition is true")
set ( IfElse 1 )
continue ( )
2020-04-27 21:20:03 +08:00
endif ( )
2015-02-18 12:09:41 +08:00
endif ( )
2021-11-25 04:07:28 +08:00
set ( IfElse 2 )
continue ( )
2015-02-18 11:36:23 +08:00
endif ( )
2021-11-25 04:07:28 +08:00
#message(STATUS "unmatched line ${line_match}")
2015-02-18 11:36:23 +08:00
endforeach ( )
2015-02-18 12:09:41 +08:00
endmacro ( )
2015-02-18 11:36:23 +08:00
2015-01-31 03:47:40 +08:00
# Returns all combinations of the input list, as a list with colon-separated combinations
# E.g. input of A B C returns A B C A:B A:C B:C
# 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}")).
2015-02-05 23:23:47 +08:00
# #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.
2015-02-05 23:02:54 +08:00
# @returns LIST_OUT a list of combinations
# 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
2015-02-05 23:23:47 +08:00
function ( AllCombinations list_in absent_codes_in )
2015-01-31 03:47:40 +08:00
list ( LENGTH list_in list_count )
set ( num_combos 1 )
# subtract 1 since we will iterate from 0 to num_combos
math ( EXPR num_combos "(${num_combos} << ${list_count}) - 1" )
set ( LIST_OUT "" )
2015-02-05 23:17:18 +08:00
set ( CODES_OUT "" )
2015-01-31 03:47:40 +08:00
foreach ( c RANGE 0 ${ num_combos } )
2015-02-05 23:02:54 +08:00
2015-01-31 03:47:40 +08:00
set ( current_combo "" )
2015-02-05 23:02:54 +08:00
set ( current_code "" )
2015-01-31 03:47:40 +08:00
# this is a little ridiculous just to iterate through a list w/ indices
math ( EXPR last_list_index "${list_count} - 1" )
foreach ( list_index RANGE 0 ${ last_list_index } )
math ( EXPR bit "1 << ${list_index}" )
math ( EXPR combo_has_bit "${c} & ${bit}" )
list ( GET list_in ${ list_index } list_elem )
if ( combo_has_bit )
if ( current_combo )
set ( current_combo "${current_combo}:${list_elem}" )
else ( )
set ( current_combo ${ list_elem } )
endif ( )
2015-02-05 23:02:54 +08:00
string ( SUBSTRING ${ list_elem } 0 1 code_char )
else ( )
2015-02-05 23:23:47 +08:00
list ( GET absent_codes_in ${ list_index } code_char )
2015-01-31 03:47:40 +08:00
endif ( )
2015-02-05 23:02:54 +08:00
set ( current_code "${current_code}${code_char}" )
2015-01-31 03:47:40 +08:00
endforeach ( )
2015-02-05 23:02:54 +08:00
if ( current_combo STREQUAL "" )
list ( APPEND LIST_OUT " " ) # Empty set is a valid combination, but CMake isn't appending the empty string for some reason, use a space
else ( )
list ( APPEND LIST_OUT ${ current_combo } )
endif ( )
list ( APPEND CODES_OUT ${ current_code } )
2015-01-31 03:47:40 +08:00
endforeach ( )
2015-02-05 23:02:54 +08:00
set ( LIST_OUT ${ LIST_OUT } PARENT_SCOPE )
set ( CODES_OUT ${ CODES_OUT } PARENT_SCOPE )
2015-01-31 03:47:40 +08:00
endfunction ( )
2019-04-30 05:03:56 +08:00
# generates object files for each of the sources, using the BLAS naming scheme to pass the function name as a preprocessor definition
2015-02-05 00:37:34 +08:00
# @param sources_in the source files to build from
# @param defines_in (optional) preprocessor definitions that will be applied to all objects
2015-02-05 00:52:19 +08:00
# @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.
# e.g. with DOUBLE set, "i*max" will generate the name "idmax", and "max" will be "dmax"
2015-02-06 00:49:11 +08:00
# @param replace_last_with replaces the last character in the filename with this string (e.g. symm_k should be symm_TU)
2015-02-05 23:02:54 +08:00
# @param append_with appends the filename with this string (e.g. trmm_R should be trmm_RTUU or some other combination of characters)
2015-02-16 07:44:37 +08:00
# @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
2015-02-18 03:12:30 +08:00
# @param complex_filename_scheme some routines have separate source files for complex and non-complex float types.
2015-02-18 00:30:28 +08:00
# 0 - compiles for all types
# 1 - compiles the sources for non-complex types only (SINGLE/DOUBLE)
# 2 - compiles for complex types only (COMPLEX/DOUBLE COMPLEX)
# 3 - compiles for all types, but changes source names for complex by prepending z (e.g. axpy.c becomes zaxpy.c)
2015-08-11 03:10:44 +08:00
# 4 - compiles for complex types only, but changes source names for complex by prepending z (e.g. hemv.c becomes zhemv.c)
2015-02-18 11:36:23 +08:00
# STRING - compiles only the given type (e.g. DOUBLE)
2015-02-12 00:54:14 +08:00
function ( GenerateNamedObjects sources_in )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 1 )
2015-02-16 07:44:37 +08:00
set ( defines_in ${ ARGV1 } )
2015-02-12 00:54:14 +08:00
endif ( )
2015-02-07 06:52:19 +08:00
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 2 AND NOT "${ARGV2}" STREQUAL "" )
2015-02-16 07:44:37 +08:00
set ( name_in ${ ARGV2 } )
2015-02-19 02:23:17 +08:00
# strip off extension for kernel files that pass in the object name.
get_filename_component ( name_in ${ name_in } NAME_WE )
2015-02-07 06:52:19 +08:00
endif ( )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 3 )
2015-02-16 07:44:37 +08:00
set ( use_cblas ${ ARGV3 } )
else ( )
2015-02-18 03:12:30 +08:00
set ( use_cblas false )
2015-02-07 06:52:19 +08:00
endif ( )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 4 )
2015-02-16 07:44:37 +08:00
set ( replace_last_with ${ ARGV4 } )
2015-02-07 06:52:19 +08:00
endif ( )
2015-02-05 23:39:40 +08:00
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 5 )
2015-02-16 07:44:37 +08:00
set ( append_with ${ ARGV5 } )
2015-02-05 23:39:40 +08:00
endif ( )
2021-08-12 00:08:34 +08:00
if ( ${ ARGC } GREATER 6 )
2015-02-16 07:44:37 +08:00
set ( no_float_type ${ ARGV6 } )
else ( )
set ( no_float_type false )
endif ( )
2015-02-18 11:36:23 +08:00
if ( no_float_type )
set ( float_list "DUMMY" ) # still need to loop once
else ( )
set ( float_list "${FLOAT_TYPES}" )
endif ( )
2015-02-18 00:30:28 +08:00
set ( real_only false )
set ( complex_only false )
set ( mangle_complex_sources false )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 7 AND NOT "${ARGV7}" STREQUAL "" )
2015-02-18 00:30:28 +08:00
if ( ${ ARGV7 } EQUAL 1 )
set ( real_only true )
elseif ( ${ ARGV7 } EQUAL 2 )
set ( complex_only true )
elseif ( ${ ARGV7 } EQUAL 3 )
set ( mangle_complex_sources true )
2015-08-11 03:10:44 +08:00
elseif ( ${ ARGV7 } EQUAL 4 )
set ( mangle_complex_sources true )
set ( complex_only true )
2015-02-18 11:36:23 +08:00
elseif ( NOT ${ ARGV7 } EQUAL 0 )
set ( float_list ${ ARGV7 } )
2015-02-18 00:30:28 +08:00
endif ( )
endif ( )
2015-02-18 11:36:23 +08:00
if ( complex_only )
list ( REMOVE_ITEM float_list "SINGLE" )
list ( REMOVE_ITEM float_list "DOUBLE" )
2020-10-12 06:07:37 +08:00
list ( REMOVE_ITEM float_list "BFLOAT16" )
2015-02-18 11:36:23 +08:00
elseif ( real_only )
list ( REMOVE_ITEM float_list "COMPLEX" )
list ( REMOVE_ITEM float_list "ZCOMPLEX" )
2015-02-05 23:39:40 +08:00
endif ( )
2015-02-05 23:02:54 +08:00
2015-02-20 03:53:29 +08:00
set ( float_char "" )
2015-02-05 00:37:34 +08:00
set ( OBJ_LIST_OUT "" )
2015-02-16 07:44:37 +08:00
foreach ( float_type ${ float_list } )
foreach ( source_file ${ sources_in } )
2015-02-05 00:37:34 +08:00
2015-02-16 07:44:37 +08:00
if ( NOT no_float_type )
string ( SUBSTRING ${ float_type } 0 1 float_char )
string ( TOLOWER ${ float_char } float_char )
2025-10-07 21:24:36 +08:00
if ( ${ float_type } STREQUAL "BFLOAT16" AND NOT "${defines_in}" MATCHES "BGEM" )
set ( float_char "sb" )
endif ( )
if ( ${ float_type } STREQUAL "HFLOAT16" AND NOT "${defines_in}" MATCHES "HGEM" )
set ( float_char "sh" )
endif ( )
2015-02-16 07:44:37 +08:00
endif ( )
2015-02-05 00:37:34 +08:00
2015-02-16 07:44:37 +08:00
if ( NOT name_in )
get_filename_component ( source_name ${ source_file } NAME_WE )
set ( obj_name "${float_char}${source_name}" )
2015-02-05 00:52:19 +08:00
else ( )
2015-02-16 07:44:37 +08:00
# replace * with float_char
if ( ${ name_in } MATCHES "\\*" )
string ( REPLACE "*" ${ float_char } obj_name ${ name_in } )
else ( )
set ( obj_name "${float_char}${name_in}" )
endif ( )
2015-02-05 00:52:19 +08:00
endif ( )
2015-02-05 00:37:34 +08:00
2015-02-16 07:44:37 +08:00
if ( replace_last_with )
string ( REGEX REPLACE ".$" ${ replace_last_with } obj_name ${ obj_name } )
else ( )
set ( obj_name "${obj_name}${append_with}" )
endif ( )
2015-02-05 23:02:54 +08:00
2015-02-16 07:44:37 +08:00
# now add the object and set the defines
set ( obj_defines ${ defines_in } )
2015-02-05 01:30:15 +08:00
2021-06-16 18:17:25 +08:00
list ( FIND obj_defines "RC" def_idx )
if ( ${ def_idx } GREATER -1 )
# list(REMOVE_AT ${obj_defines} ${def_idx})
list ( REMOVE_ITEM obj_defines "RC" )
list ( APPEND obj_defines "RC=RC" )
endif ( )
list ( FIND obj_defines "CR" def_idx )
if ( ${ def_idx } GREATER -1 )
# list(REMOVE_AT ${obj_defines} ${def_idx})
list ( REMOVE_ITEM obj_defines "CR" )
list ( APPEND obj_defines "CR=CR" )
endif ( )
2015-02-16 07:44:37 +08:00
if ( use_cblas )
set ( obj_name "cblas_${obj_name}" )
list ( APPEND obj_defines "CBLAS" )
2017-08-08 01:38:44 +08:00
elseif ( NOT "${obj_name}" MATCHES "${ARCH_SUFFIX}" )
set ( obj_name "${obj_name}${ARCH_SUFFIX}" )
2015-02-16 07:44:37 +08:00
endif ( )
2015-02-05 01:30:15 +08:00
2015-02-16 07:44:37 +08:00
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}\"")
if ( ${ float_type } STREQUAL "DOUBLE" OR ${ float_type } STREQUAL "ZCOMPLEX" )
list ( APPEND obj_defines "DOUBLE" )
endif ( )
2020-10-12 06:07:37 +08:00
if ( ${ float_type } STREQUAL "BFLOAT16" )
list ( APPEND obj_defines "BFLOAT16" )
2025-09-28 04:19:23 +08:00
endif ( )
if ( ${ float_type } STREQUAL "HFLOAT16" )
list ( APPEND obj_defines "HFLOAT16" )
2020-04-18 02:35:17 +08:00
endif ( )
2015-02-16 07:44:37 +08:00
if ( ${ float_type } STREQUAL "COMPLEX" OR ${ float_type } STREQUAL "ZCOMPLEX" )
list ( APPEND obj_defines "COMPLEX" )
2015-02-18 00:30:28 +08:00
if ( mangle_complex_sources )
# add a z to the filename
get_filename_component ( source_name ${ source_file } NAME )
get_filename_component ( source_dir ${ source_file } DIRECTORY )
string ( REPLACE ${ source_name } "z${source_name}" source_file ${ source_file } )
endif ( )
2015-02-16 07:44:37 +08:00
endif ( )
2015-02-05 01:30:15 +08:00
2015-02-25 02:26:33 +08:00
if ( VERBOSE_GEN )
message ( STATUS "${obj_name}:${source_file}" )
message ( STATUS "${obj_defines}" )
endif ( )
# create a copy of the source to avoid duplicate obj filename problem with ar.exe
get_filename_component ( source_extension ${ source_file } EXT )
2017-08-02 18:44:34 +08:00
set ( new_source_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${obj_name}${source_extension}" )
2015-02-25 02:26:33 +08:00
if ( IS_ABSOLUTE ${ source_file } )
set ( old_source_file ${ source_file } )
else ( )
set ( old_source_file "${CMAKE_CURRENT_LIST_DIR}/${source_file}" )
endif ( )
2015-02-05 00:37:34 +08:00
2015-02-25 02:26:33 +08:00
string ( REPLACE ";" "\n#define " define_source "${obj_defines}" )
string ( REPLACE "=" " " define_source "${define_source}" )
2017-08-01 13:32:00 +08:00
file ( WRITE ${ new_source_file } .tmp "#define ${define_source}\n#include \" ${ old_source_file } \"")
configure_file ( ${ new_source_file } .tmp ${ new_source_file } COPYONLY )
file ( REMOVE ${ new_source_file } .tmp )
2015-02-25 02:26:33 +08:00
list ( APPEND SRC_LIST_OUT ${ new_source_file } )
2021-07-22 18:00:03 +08:00
message ( STATUS ${ new_source_file } )
if ( DEFINED HAVE_FMA3 )
2021-07-22 23:24:15 +08:00
if ( ${ new_source_file } MATCHES "(s|d?)rot_k.*c" )
2021-07-22 18:00:03 +08:00
set_source_files_properties ( ${ new_source_file } PROPERTIES COMPILE_OPTIONS "-mfma" )
endif ( )
2021-07-22 23:24:15 +08:00
if ( ${ new_source_file } MATCHES "dgemv_t_k.*c" )
2021-07-22 18:00:03 +08:00
set_source_files_properties ( ${ new_source_file } PROPERTIES COMPILE_OPTIONS "-mfma" )
endif ( )
endif ( )
2015-02-16 07:44:37 +08:00
endforeach ( )
2015-02-05 00:37:34 +08:00
endforeach ( )
2015-02-10 02:28:09 +08:00
2015-02-25 02:26:33 +08:00
list ( APPEND OPENBLAS_SRC ${ SRC_LIST_OUT } )
set ( OPENBLAS_SRC ${ OPENBLAS_SRC } PARENT_SCOPE )
2015-02-05 00:37:34 +08:00
endfunction ( )
2015-02-05 23:02:54 +08:00
# generates object files for each of the sources for each of the combinations of the preprocessor definitions passed in
# @param sources_in the source files to build from
# @param defines_in the preprocessor definitions that will be combined to create the object files
# @param all_defines_in (optional) preprocessor definitions that will be applied to all objects
2015-02-06 00:49:11 +08:00
# @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.
# If 0, it will simply append the code, e.g. symm_L.c with TRANS and UNIT will be symm_LTU.
# If 2, it will append the code with an underscore, e.g. symm.c with TRANS and UNIT will be symm_TU.
# 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).
2015-02-07 03:42:20 +08:00
# If 4, it will insert the code before the last underscore. E.g. trtri_U_parallel with TRANS will be trtri_UT_parallel
2015-02-06 02:22:48 +08:00
# @param alternate_name replaces the source name as the object name (define codes are still appended)
2015-02-16 07:44:37 +08:00
# @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
2015-02-18 03:12:30 +08:00
# @param complex_filename_scheme see GenerateNamedObjects
2015-02-16 07:44:37 +08:00
function ( GenerateCombinationObjects sources_in defines_in absent_codes_in all_defines_in replace_scheme )
2015-02-21 07:03:33 +08:00
set ( alternate_name_in "" )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 5 )
2015-02-21 07:03:33 +08:00
set ( alternate_name_in ${ ARGV5 } )
2015-02-16 07:44:37 +08:00
endif ( )
2015-02-05 23:02:54 +08:00
2015-02-21 07:03:33 +08:00
set ( no_float_type false )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 6 )
2015-02-16 07:44:37 +08:00
set ( no_float_type ${ ARGV6 } )
2015-02-06 02:22:48 +08:00
endif ( )
2015-02-21 07:03:33 +08:00
set ( complex_filename_scheme "" )
2021-08-12 00:00:07 +08:00
if ( ${ ARGC } GREATER 7 )
2015-02-18 03:12:30 +08:00
set ( complex_filename_scheme ${ ARGV7 } )
endif ( )
2015-02-05 23:23:47 +08:00
AllCombinations ( "${defines_in}" "${absent_codes_in}" )
2015-02-05 23:02:54 +08:00
set ( define_combos ${ LIST_OUT } )
set ( define_codes ${ CODES_OUT } )
list ( LENGTH define_combos num_combos )
math ( EXPR num_combos "${num_combos} - 1" )
foreach ( c RANGE 0 ${ num_combos } )
list ( GET define_combos ${ c } define_combo )
list ( GET define_codes ${ c } define_code )
foreach ( source_file ${ sources_in } )
2015-02-21 07:03:33 +08:00
set ( alternate_name ${ alternate_name_in } )
2015-02-05 23:02:54 +08:00
# replace colon separated list with semicolons, this turns it into a CMake list that we can use foreach with
string ( REPLACE ":" ";" define_combo ${ define_combo } )
# now add the object and set the defines
set ( cur_defines ${ define_combo } )
if ( "${cur_defines}" STREQUAL " " )
set ( cur_defines ${ all_defines_in } )
else ( )
list ( APPEND cur_defines ${ all_defines_in } )
endif ( )
2015-02-06 00:49:11 +08:00
set ( replace_code "" )
set ( append_code "" )
if ( replace_scheme EQUAL 1 )
set ( replace_code ${ define_code } )
2015-02-05 23:02:54 +08:00
else ( )
2015-02-06 00:49:11 +08:00
if ( replace_scheme EQUAL 2 )
set ( append_code "_${define_code}" )
elseif ( replace_scheme EQUAL 3 )
2015-02-21 07:03:33 +08:00
if ( "${alternate_name}" STREQUAL "" )
string ( REGEX MATCH "[a-zA-Z]\\." last_letter ${ source_file } )
else ( )
string ( REGEX MATCH "[a-zA-Z]$" last_letter ${ alternate_name } )
endif ( )
2015-02-06 00:49:11 +08:00
# first extract the last letter
string ( SUBSTRING ${ last_letter } 0 1 last_letter ) # remove period from match
# break the code up into the first letter and the remaining (should only be 2 anyway)
string ( SUBSTRING ${ define_code } 0 1 define_code_first )
string ( SUBSTRING ${ define_code } 1 -1 define_code_second )
set ( replace_code "${define_code_first}${last_letter}${define_code_second}" )
2015-02-07 03:42:20 +08:00
elseif ( replace_scheme EQUAL 4 )
# insert code before the last underscore and pass that in as the alternate_name
2015-02-21 07:03:33 +08:00
if ( "${alternate_name}" STREQUAL "" )
get_filename_component ( alternate_name ${ source_file } NAME_WE )
endif ( )
2015-02-07 03:42:20 +08:00
set ( extra_underscore "" )
# check if filename has two underscores, insert another if not (e.g. getrs_parallel needs to become getrs_U_parallel not getrsU_parallel)
string ( REGEX MATCH "_[a-zA-Z]+_" underscores ${ alternate_name } )
string ( LENGTH "${underscores}" underscores )
if ( underscores EQUAL 0 )
set ( extra_underscore "_" )
endif ( )
string ( REGEX REPLACE "(.+)(_[^_]+)$" "\\1${extra_underscore}${define_code}\\2" alternate_name ${ alternate_name } )
else ( )
2015-02-06 00:49:11 +08:00
set ( append_code ${ define_code } ) # replace_scheme should be 0
2015-02-05 23:17:18 +08:00
endif ( )
2015-02-05 23:02:54 +08:00
endif ( )
2015-02-23 07:49:28 +08:00
GenerateNamedObjects ( "${source_file}" "${cur_defines}" "${alternate_name}" false "${replace_code}" "${append_code}" "${no_float_type}" "${complex_filename_scheme}" )
2015-02-05 23:02:54 +08:00
endforeach ( )
endforeach ( )
2015-02-25 02:26:33 +08:00
set ( OPENBLAS_SRC ${ OPENBLAS_SRC } PARENT_SCOPE )
2015-02-05 23:02:54 +08:00
endfunction ( )
2015-02-05 23:17:18 +08:00