1#
2# Copyright (c) 2017, Alliance for Open Media. All rights reserved
3#
4# This source code is subject to the terms of the BSD 2 Clause License and the
5# Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License was
6# not distributed with this source code in the LICENSE file, you can obtain it
7# at www.aomedia.org/license/software. If the Alliance for Open Media Patent
8# License 1.0 was not distributed with this source code in the PATENTS file, you
9# can obtain it at www.aomedia.org/license/patent.
10#
11if(AOM_BUILD_CMAKE_AOM_OPTIMIZATION_CMAKE_)
12  return()
13endif() # AOM_BUILD_CMAKE_AOM_OPTIMIZATION_CMAKE_
14set(AOM_BUILD_CMAKE_AOM_OPTIMIZATION_CMAKE_ 1)
15
16include("${AOM_ROOT}/build/cmake/util.cmake")
17
18# Translate $flag to one which MSVC understands, and write the new flag to the
19# variable named by $translated_flag (or unset it, when MSVC needs no flag).
20function(get_msvc_intrinsic_flag flag translated_flag)
21  if("${flag}" STREQUAL "-mavx")
22    set(${translated_flag} "/arch:AVX" PARENT_SCOPE)
23  elseif("${flag}" STREQUAL "-mavx2")
24    set(${translated_flag} "/arch:AVX2" PARENT_SCOPE)
25  else()
26
27    # MSVC does not need flags for intrinsics flavors other than AVX/AVX2.
28    unset(${translated_flag} PARENT_SCOPE)
29  endif()
30endfunction()
31
32# Adds an object library target. Terminates generation if $flag is not supported
33# by the current compiler. $flag is the intrinsics flag required by the current
34# compiler, and is added to the compile flags for all sources in $sources.
35# $opt_name is used to name the target. $target_to_update is made dependent upon
36# the created target.
37#
38# Note: this function always updates the aom, and aom_static targets because
39# OBJECT libraries have rules that disallow the direct addition of .o files to
40# them as dependencies. Static and shared libraries do not have this limitation.
41function(add_intrinsics_object_library flag opt_name target_to_update sources)
42  if("${${sources}}" STREQUAL "")
43    return()
44  endif()
45  set(target_name ${target_to_update}_${opt_name}_intrinsics)
46  add_library(${target_name} OBJECT ${${sources}})
47
48  if(MSVC)
49    get_msvc_intrinsic_flag(${flag} "flag")
50  endif()
51
52  if("${flag}" STREQUAL "-mavx2")
53    unset(FLAG_SUPPORTED)
54    check_c_compiler_flag("-mno-avx256-split-unaligned-load" FLAG_SUPPORTED)
55    if(${FLAG_SUPPORTED})
56      set(flag "${flag} -mno-avx256-split-unaligned-load")
57    endif()
58
59    unset(FLAG_SUPPORTED)
60    check_c_compiler_flag("-mno-avx256-split-unaligned-store" FLAG_SUPPORTED)
61    if(${FLAG_SUPPORTED})
62      set(flag "${flag} -mno-avx256-split-unaligned-store")
63    endif()
64  endif()
65
66  if(flag)
67    separate_arguments(flag)
68    target_compile_options(${target_name} PUBLIC ${flag})
69  endif()
70
71  target_sources(aom PRIVATE $<TARGET_OBJECTS:${target_name}>)
72  if(BUILD_SHARED_LIBS)
73    target_sources(aom_static PRIVATE $<TARGET_OBJECTS:${target_name}>)
74  endif()
75
76  # Add the new lib target to the global list of aom library targets.
77  list(APPEND AOM_LIB_TARGETS ${target_name})
78  set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE)
79endfunction()
80
81# Adds sources in list named by $sources to $target and adds $flag to the
82# compile flags for each source file.
83function(add_intrinsics_source_to_target flag target sources)
84  target_sources(${target} PRIVATE ${${sources}})
85  if(MSVC)
86    get_msvc_intrinsic_flag(${flag} "flag")
87  endif()
88  if(flag)
89    foreach(source ${${sources}})
90      set_property(SOURCE ${source} APPEND PROPERTY COMPILE_FLAGS ${flag})
91    endforeach()
92  endif()
93endfunction()
94
95# Writes object format for the current target to the var named by $out_format,
96# or terminates the build when the object format for the current target is
97# unknown.
98function(get_asm_obj_format out_format)
99  if("${AOM_TARGET_CPU}" STREQUAL "x86_64")
100    if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin")
101      set(objformat "macho64")
102    elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS"
103           OR "${AOM_TARGET_SYSTEM}" STREQUAL "CYGWIN"
104           OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows")
105      set(objformat "win64")
106    else()
107      set(objformat "elf64")
108    endif()
109  elseif("${AOM_TARGET_CPU}" STREQUAL "x86")
110    if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin")
111      set(objformat "macho32")
112    elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS"
113           OR "${AOM_TARGET_SYSTEM}" STREQUAL "CYGWIN"
114           OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows")
115      set(objformat "win32")
116    else()
117      set(objformat "elf32")
118    endif()
119  else()
120    message(
121      FATAL_ERROR "Unknown obj format: ${AOM_TARGET_CPU}-${AOM_TARGET_SYSTEM}")
122  endif()
123
124  set(${out_format} ${objformat} PARENT_SCOPE)
125endfunction()
126
127# Adds library target named $lib_name for ASM files in variable named by
128# $asm_sources. Builds an output directory path from $lib_name. Links $lib_name
129# into the aom library target(s). Generates a dummy C file with a dummy function
130# to ensure that all cmake generators can determine the linker language, and
131# that build tools don't complain that an object exposes no symbols.
132function(add_asm_library lib_name asm_sources)
133  if("${${asm_sources}}" STREQUAL "")
134    return()
135  endif()
136  set(asm_lib_obj_dir "${AOM_CONFIG_DIR}/asm_objects/${lib_name}")
137  if(NOT EXISTS "${asm_lib_obj_dir}")
138    file(MAKE_DIRECTORY "${asm_lib_obj_dir}")
139  endif()
140
141  # TODO(tomfinegan): If cmake ever allows addition of .o files to OBJECT lib
142  # targets, make this OBJECT instead of STATIC to hide the target from
143  # consumers of the AOM cmake build.
144  add_library(${lib_name} STATIC ${${asm_sources}})
145
146  foreach(asm_source ${${asm_sources}})
147    get_filename_component(asm_source_name "${asm_source}" NAME)
148    set(asm_object "${asm_lib_obj_dir}/${asm_source_name}.o")
149    add_custom_command(OUTPUT "${asm_object}"
150                       COMMAND ${AS_EXECUTABLE} ARGS ${AOM_AS_FLAGS}
151                               -I${AOM_ROOT}/ -I${AOM_CONFIG_DIR}/ -o
152                               "${asm_object}" "${asm_source}"
153                       DEPENDS "${asm_source}"
154                       COMMENT "Building ASM object ${asm_object}"
155                       WORKING_DIRECTORY "${AOM_CONFIG_DIR}"
156                       VERBATIM)
157    target_sources(aom PRIVATE "${asm_object}")
158    if(BUILD_SHARED_LIBS)
159      target_sources(aom_static PRIVATE "${asm_object}")
160    endif()
161  endforeach()
162
163  # The above created a target containing only ASM sources. Cmake needs help
164  # here to determine the linker language. Add a dummy C file to force the
165  # linker language to C. We don't bother with setting the LINKER_LANGUAGE
166  # property on the library target because not all generators obey it (looking
167  # at you, xcode generator).
168  add_dummy_source_file_to_target("${lib_name}" "c")
169
170  # Add the new lib target to the global list of aom library targets.
171  list(APPEND AOM_LIB_TARGETS ${lib_name})
172  set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE)
173endfunction()
174
175# Terminates generation if nasm found in PATH does not meet requirements.
176# Currently checks only for presence of required object formats and support for
177# the -Ox argument (multipass optimization).
178function(test_nasm)
179  execute_process(COMMAND ${AS_EXECUTABLE} -hf OUTPUT_VARIABLE nasm_helptext)
180
181  if(NOT "${nasm_helptext}" MATCHES "-Ox")
182    message(
183      FATAL_ERROR "Unsupported nasm: multipass optimization not supported.")
184  endif()
185
186  if("${AOM_TARGET_CPU}" STREQUAL "x86")
187    if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin")
188      if(NOT "${nasm_helptext}" MATCHES "macho32")
189        message(
190          FATAL_ERROR "Unsupported nasm: macho32 object format not supported.")
191      endif()
192    elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS"
193           OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows")
194      if(NOT "${nasm_helptext}" MATCHES "win32")
195        message(
196          FATAL_ERROR "Unsupported nasm: win32 object format not supported.")
197      endif()
198    else()
199      if(NOT "${nasm_helptext}" MATCHES "elf32")
200        message(
201          FATAL_ERROR "Unsupported nasm: elf32 object format not supported.")
202      endif()
203    endif()
204  else()
205    if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin")
206      if(NOT "${nasm_helptext}" MATCHES "macho64")
207        message(
208          FATAL_ERROR "Unsupported nasm: macho64 object format not supported.")
209      endif()
210    elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS"
211           OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows")
212      if(NOT "${nasm_helptext}" MATCHES "win64")
213        message(
214          FATAL_ERROR "Unsupported nasm: win64 object format not supported.")
215      endif()
216    else()
217      if(NOT "${nasm_helptext}" MATCHES "elf64")
218        message(
219          FATAL_ERROR "Unsupported nasm: elf64 object format not supported.")
220      endif()
221    endif()
222  endif()
223endfunction()
224
225# Adds build command for generation of rtcd C source files using
226# build/cmake/rtcd.pl. $config is the input perl file, $output is the output C
227# include file, $source is the C source file, and $symbol is used for the symbol
228# argument passed to rtcd.pl.
229function(add_rtcd_build_step config output source symbol)
230  add_custom_command(
231    OUTPUT ${output}
232    COMMAND ${PERL_EXECUTABLE} ARGS "${AOM_ROOT}/build/cmake/rtcd.pl"
233            --arch=${AOM_TARGET_CPU}
234            --sym=${symbol} ${AOM_RTCD_FLAGS}
235            --config=${AOM_CONFIG_DIR}/config/aom_config.h ${config} > ${output}
236    DEPENDS ${config}
237    COMMENT "Generating ${output}"
238    WORKING_DIRECTORY ${AOM_CONFIG_DIR}
239    VERBATIM)
240  set_property(SOURCE ${source} PROPERTY OBJECT_DEPENDS ${output})
241  set_property(SOURCE ${output} PROPERTY GENERATED)
242endfunction()
243