1## Copyright 2020 Intel Corporation
2## SPDX-License-Identifier: BSD-3-Clause
3
4###############################################################################
5## Generic ISPC macros/options ################################################
6###############################################################################
7
8option(BUILD_GPU "Build GPU code paths?" ON)
9
10set(ISPC_INCLUDE_DIR "")
11macro (include_directories_ispc)
12  list(APPEND ISPC_INCLUDE_DIR ${ARGN})
13endmacro ()
14
15set(ISPC_DEFINITIONS "")
16macro (add_definitions_ispc)
17  list(APPEND ISPC_DEFINITIONS ${ARGN})
18endmacro ()
19
20###############################################################################
21## CPU specific macros/options ################################################
22###############################################################################
23
24## Find ISPC ##
25find_program(ISPC_EXECUTABLE ispc HINTS ${ISPC_DIR_HINT} DOC "Path to the ISPC executable.")
26if (NOT ISPC_EXECUTABLE)
27  message(FATAL_ERROR "Could not find ISPC. Exiting.")
28else()
29  message(STATUS "Found Intel(r) Implicit SPMD Compiler (Intel(r) ISPC): ${ISPC_EXECUTABLE}")
30endif()
31
32## ISPC config options ##
33
34option(ISPC_FAST_MATH "enable ISPC fast-math optimizations" OFF)
35mark_as_advanced(ISPC_FAST_MATH)
36
37set(ISPC_ADDRESSING 32 CACHE STRING "32 vs 64 bit addressing in ispc")
38set_property(CACHE ISPC_ADDRESSING PROPERTY STRINGS 32 64)
39mark_as_advanced(ISPC_ADDRESSING)
40
41macro(define_ispc_isa_options ISA_NAME)
42  set(ISPC_TARGET_${ISA_NAME} ${ARGV1} CACHE STRING "ispc target used for ${ISA_NAME} ISA")
43  set_property(CACHE ISPC_TARGET_${ISA_NAME} PROPERTY STRINGS ${ARGN} NONE)
44  #mark_as_advanced(ISPC_TARGET_${ISA_NAME})
45endmacro()
46
47# TODO: query ISPC for available targets to be added here
48define_ispc_isa_options(SSE4 sse4-i32x4 sse4-i32x8 sse4-i16x8 sse4-i8x16)
49define_ispc_isa_options(AVX avx1-i32x8 avx1-i32x4 avx1-i32x16 avx1-i64x4)
50define_ispc_isa_options(AVX2 avx2-i32x8 avx2-i32x4 avx2-i32x16 avx2-i64x4)
51define_ispc_isa_options(AVX512KNL avx512knl-i32x16)
52define_ispc_isa_options(AVX512SKX avx512skx-i32x16 avx512skx-i32x8)
53
54macro(append_ispc_target_list ISA_NAME)
55  set(_TARGET_NAME ISPC_TARGET_${ISA_NAME})
56  if (NOT ${_TARGET_NAME} STREQUAL "NONE")
57    list(APPEND ISPC_TARGET_LIST ${${_TARGET_NAME}})
58  endif()
59  unset(_TARGET_NAME)
60endmacro()
61
62unset(ISPC_TARGET_LIST)
63append_ispc_target_list(SSE4)
64append_ispc_target_list(AVX)
65append_ispc_target_list(AVX2)
66append_ispc_target_list(AVX512KNL)
67append_ispc_target_list(AVX512SKX)
68
69## Macros ##
70
71macro (ispc_compile)
72  set(ISPC_ADDITIONAL_ARGS "")
73  # Check if CPU target is passed externally
74  if (NOT ISPC_TARGET_CPU)
75    set(ISPC_TARGETS ${ISPC_TARGET_LIST})
76  else()
77    set(ISPC_TARGETS ${ISPC_TARGET_CPU})
78  endif()
79
80  set(ISPC_TARGET_EXT ${CMAKE_CXX_OUTPUT_EXTENSION})
81  string(REPLACE ";" "," ISPC_TARGET_ARGS "${ISPC_TARGETS}")
82
83  set(ISPC_ARCHITECTURE "x86-64")
84
85  set(ISPC_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR})
86  include_directories(${ISPC_TARGET_DIR})
87
88  if(ISPC_INCLUDE_DIR)
89    string(REPLACE ";" ";-I;" ISPC_INCLUDE_DIR_PARMS "${ISPC_INCLUDE_DIR}")
90    set(ISPC_INCLUDE_DIR_PARMS "-I" ${ISPC_INCLUDE_DIR_PARMS})
91  endif()
92
93  #CAUTION: -O0/1 -g with ispc seg faults
94  set(ISPC_FLAGS_DEBUG "-g" CACHE STRING "ISPC Debug flags")
95  mark_as_advanced(ISPC_FLAGS_DEBUG)
96  set(ISPC_FLAGS_RELEASE "-O3" CACHE STRING "ISPC Release flags")
97  mark_as_advanced(ISPC_FLAGS_RELEASE)
98  set(ISPC_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "ISPC Release with Debug symbols flags")
99  mark_as_advanced(ISPC_FLAGS_RELWITHDEBINFO)
100  if (WIN32 OR "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
101    set(ISPC_OPT_FLAGS ${ISPC_FLAGS_RELEASE})
102  elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
103    set(ISPC_OPT_FLAGS ${ISPC_FLAGS_DEBUG})
104  else()
105    set(ISPC_OPT_FLAGS ${ISPC_FLAGS_RELWITHDEBINFO})
106  endif()
107
108  # turn space sparated list into ';' separated list
109  string(REPLACE " " ";" ISPC_OPT_FLAGS "${ISPC_OPT_FLAGS}")
110
111  if (NOT WIN32)
112    list(APPEND ISPC_ADDITIONAL_ARGS --pic)
113  endif()
114
115  if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
116    list(APPEND ISPC_ADDITIONAL_ARGS --opt=disable-assertions)
117  endif()
118
119  if (ISPC_FAST_MATH)
120    list(APPEND ISPC_ADDITIONAL_ARGS --opt=fast-math)
121  endif()
122
123  set(ISPC_OBJECTS "")
124
125  foreach(src ${ARGN})
126    get_filename_component(fname ${src} NAME_WE)
127
128    set(outdir "${ISPC_TARGET_DIR}/local_ispc")
129    set(input ${CMAKE_CURRENT_SOURCE_DIR}/${src})
130
131    set(deps "")
132    if (EXISTS ${outdir}/${fname}.dev.idep)
133      file(READ ${outdir}/${fname}.dev.idep contents)
134      string(REPLACE " " ";"     contents "${contents}")
135      string(REPLACE ";" "\\\\;" contents "${contents}")
136      string(REPLACE "\n" ";"    contents "${contents}")
137      foreach(dep ${contents})
138        if (EXISTS ${dep})
139          set(deps ${deps} ${dep})
140        endif (EXISTS ${dep})
141      endforeach(dep ${contents})
142    endif ()
143
144    set(results "${outdir}/${fname}.dev${ISPC_TARGET_EXT}")
145    # if we have multiple targets add additional object files
146    list(LENGTH ISPC_TARGETS NUM_TARGETS)
147    if (NUM_TARGETS GREATER 1)
148      foreach(target ${ISPC_TARGETS})
149        string(REPLACE "-i8x16"  "" target ${target})
150        string(REPLACE "-i32x4"  "" target ${target})
151        string(REPLACE "-i32x8"  "" target ${target})
152        string(REPLACE "-i32x16" "" target ${target})
153        string(REPLACE "-i64x4"  "" target ${target})
154        string(REPLACE "-i64x8"  "" target ${target})
155        string(REPLACE "avx1" "avx" target ${target})
156        list(APPEND results "${outdir}/${fname}.dev_${target}${ISPC_TARGET_EXT}")
157      endforeach()
158    endif()
159
160    add_custom_command(
161      OUTPUT ${results} ${ISPC_TARGET_DIR}/${fname}_ispc.h
162      COMMAND ${CMAKE_COMMAND} -E make_directory ${outdir}
163      COMMAND ${ISPC_EXECUTABLE}
164      ${ISPC_DEFINITIONS}
165      -I ${CMAKE_CURRENT_SOURCE_DIR}
166      ${ISPC_INCLUDE_DIR_PARMS}
167      --arch=${ISPC_ARCHITECTURE}
168      --addressing=${ISPC_ADDRESSING}
169      ${ISPC_OPT_FLAGS}
170      --target=${ISPC_TARGET_ARGS}
171      --woff
172      ${ISPC_ADDITIONAL_ARGS}
173      -h ${ISPC_TARGET_DIR}/${fname}_ispc.h
174      -MMM  ${outdir}/${fname}.dev.idep
175      -o ${outdir}/${fname}.dev${ISPC_TARGET_EXT}
176      ${input}
177      DEPENDS ${input} ${deps}
178      COMMENT "Building ISPC object ${outdir}/${fname}.dev${ISPC_TARGET_EXT}"
179    )
180
181    set(ISPC_OBJECTS ${ISPC_OBJECTS} ${results})
182  endforeach()
183endmacro()
184
185function(ispc_target_add_sources name)
186  ## Split-out C/C++ from ISPC files ##
187
188  set(ISPC_SOURCES "")
189  set(OTHER_SOURCES "")
190
191  foreach(src ${ARGN})
192    get_filename_component(ext ${src} EXT)
193    if (ext STREQUAL ".ispc")
194      set(ISPC_SOURCES ${ISPC_SOURCES} ${src})
195    else()
196      set(OTHER_SOURCES ${OTHER_SOURCES} ${src})
197    endif()
198  endforeach()
199
200  ## Get existing target definitions and include dirs ##
201
202  # NOTE(jda) - This needs work: BUILD_INTERFACE vs. INSTALL_INTERFACE isn't
203  #             handled automatically.
204
205  #get_property(TARGET_DEFINITIONS TARGET ${name} PROPERTY COMPILE_DEFINITIONS)
206  #get_property(TARGET_INCLUDES TARGET ${name} PROPERTY INCLUDE_DIRECTORIES)
207
208  #set(ISPC_DEFINITIONS ${TARGET_DEFINITIONS})
209  #set(ISPC_INCLUDE_DIR ${TARGET_INCLUDES})
210
211  ## Compile ISPC files ##
212
213  ispc_compile(${ISPC_SOURCES})
214
215  ## Set final sources on target ##
216
217  get_property(TARGET_SOURCES TARGET ${name} PROPERTY SOURCES)
218  list(APPEND TARGET_SOURCES ${ISPC_OBJECTS} ${OTHER_SOURCES})
219  set_target_properties(${name} PROPERTIES SOURCES "${TARGET_SOURCES}")
220endfunction()
221
222
223###############################################################################
224## GPU specific macros/options ################################################
225###############################################################################
226
227find_program(ISPC_EXECUTABLE_GPU ispc-gpu DOC "Path to GEN enabled ISPC.")
228
229define_ispc_isa_options(GEN genx-x8 genx-x16)
230
231set(ISPC_GENX_ADDITIONAL_ARGS "" CACHE STRING "extra arguments to pass to ISPC for GEN targets")
232
233macro (ispc_compile_gpu parent_target output_prefix)
234  if(ISPC_INCLUDE_DIR)
235    string(REPLACE ";" ";-I;" ISPC_INCLUDE_DIR_PARMS "${ISPC_INCLUDE_DIR}")
236    set(ISPC_INCLUDE_DIR_PARMS "-I" ${ISPC_INCLUDE_DIR_PARMS})
237  endif()
238
239  # Check If GPU target is passed externally
240  if (NOT ISPC_TARGET_GEN)
241    set(ISPC_TARGET_GEN "genx-x8")
242  endif()
243
244  foreach(src ${ARGN})
245    get_filename_component(fname ${src} NAME_WE)
246    get_filename_component(dir ${src} PATH)
247
248    message(STATUS "ISPC-GPU source file to be compiled: ${src}")
249
250    set(input ${CMAKE_CURRENT_LIST_DIR}/${dir}/${fname}.ispc)
251
252    if (NOT ISPC_TARGET_DIR)
253      set(ISPC_TARGET_DIR ${CMAKE_BINARY_DIR})
254    endif()
255
256    set(outdir ${ISPC_TARGET_DIR})
257
258    set(ISPC_PROGRAM_COUNT 16)
259    if ("${ISPC_TARGET_GEN}" STREQUAL "genx-x8")
260      set(ISPC_PROGRAM_COUNT 8)
261    endif()
262
263    set(ISPC_GENX_FLAGS_DEBUG "-g" CACHE STRING "ISPC GENX Debug flags")
264    mark_as_advanced(ISPC_GENX_FLAGS_DEBUG)
265    set(ISPC_GENX_FLAGS_RELEASE "-O3" CACHE STRING "ISPC GENX Release flags")
266    mark_as_advanced(ISPC_GENX_FLAGS_RELEASE)
267    set(ISPC_GENX_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "ISPC GENX Release with Debug symbols flags")
268    mark_as_advanced(ISPC_GENX_FLAGS_RELWITHDEBINFO)
269
270    if (WIN32 OR "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
271      set(ISPC_GENX_OPT_FLAGS ${ISPC_GENX_FLAGS_RELEASE})
272    elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
273      set(ISPC_GENX_OPT_FLAGS ${ISPC_GENX_FLAGS_DEBUG})
274    else()
275      set(ISPC_GENX_OPT_FLAGS ${ISPC_GENX_FLAGS_RELWITHDEBINFO})
276    endif()
277    # turn space sparated list into ';' separated list
278    string(REPLACE " " ";" ISPC_GENX_OPT_FLAGS "${ISPC_GENX_OPT_FLAGS}")
279
280    # Additional flags passed by user
281    if (NOT ISPC_GENX_ADDITIONAL_ARGS)
282      set(ISPC_GENX_ADDITIONAL_ARGS "")
283    endif()
284
285    # Output ISPC module format passed by user
286    if (NOT ISPC_GENX_FORMAT)
287      set (ISPC_GENX_FORMAT "spv")
288    endif()
289
290    if (ISPC_GENX_FORMAT STREQUAL "spv")
291      set(ISPC_GPU_TARGET_NAME ${parent_target}_${fname}_spv)
292      set(ISPC_GPU_OUTPUT_OPT "--emit-spirv")
293      set(result "${outdir}/${output_prefix}${parent_target}.spv")
294    elseif (ISPC_GENX_FORMAT STREQUAL "zebin")
295      set(ISPC_GPU_TARGET_NAME ${parent_target}_${fname}_bin)
296      set(ISPC_GPU_OUTPUT_OPT "--emit-zebin")
297      set(result "${outdir}/${output_prefix}${parent_target}.bin")
298    endif()
299
300    add_custom_target(${ISPC_GPU_TARGET_NAME}
301      COMMAND ${ISPC_EXECUTABLE_GPU}
302        -I ${CMAKE_CURRENT_SOURCE_DIR}
303        ${ISPC_INCLUDE_DIR_PARMS}
304        ${ISPC_GENX_OPT_FLAGS}
305        -DISPC_GPU
306        ${ISPC_DEFINITIONS}
307        --addressing=64
308        --target=${ISPC_TARGET_GEN}
309        ${ISPC_GPU_OUTPUT_OPT}
310        --woff
311        ${ISPC_GENX_ADDITIONAL_ARGS}
312        -o ${result}
313        ${input}
314      COMMENT "Building ISPC GPU object ${result}"
315    )
316
317    add_dependencies(${parent_target} ${ISPC_GPU_TARGET_NAME})
318
319    target_compile_definitions(${parent_target}
320    PRIVATE
321      ISPC_GPU_PROGRAM_COUNT=${ISPC_PROGRAM_COUNT}
322    )
323
324    unset(ISPC_PROGRAM_COUNT)
325  endforeach()
326endmacro()
327
328###############################################################################
329## Generic kernel compilation #################################################
330###############################################################################
331
332function(add_ispc_kernel TARGET_NAME SOURCE PREFIX)
333if (WIN32)
334    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
335endif()
336  add_library(${TARGET_NAME} SHARED)
337  set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
338  set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${PREFIX}${TARGET_NAME}")
339  if (WIN32)
340    target_link_libraries(${TARGET_NAME} PRIVATE msvcrt.lib)
341    if (ISPC_BUILD)
342       target_link_libraries(${TARGET_NAME} PRIVATE ${ISPCRT_LIB})
343    else()
344       target_link_libraries(${TARGET_NAME} PRIVATE ispcrt::ispcrt)
345    endif()
346  endif()
347  ispc_target_add_sources(${TARGET_NAME} ${SOURCE})
348  if (BUILD_GPU)
349    ispc_compile_gpu(${TARGET_NAME} "${PREFIX}" ${SOURCE})
350  endif()
351endfunction()
352