# Copyright 2021 The IREE Authors # # Licensed under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # iree_static_linker_test() # # Creates a test test for the statically linked libraries generated by the # llvm-cpu compiler target backend and executed using the local-sync runtime # HAL driver. # # Parameters: # NAME: Name of the target # SRC: mlir source file to be compiled to an IREE module. # INPUT_TYPE: Module input type, assuming native c/c++ data types # HAL_TYPE: HAL data type, see runtime/src/iree/hal/buffer_view.h for possible # options. # STATIC_LIB_PREFIX: llvm static library prefix. # ENTRY_FUNCTION: Entry function call. # EMITC: Uses EmitC to output C code instead of VM bytecode. # COMPILER_FLAGS: additional flags to pass to the compiler. Bytecode output # format and backend flags are passed automatically. # FUNCTION_INPUTS: Module input in the format of mxnxcx. # LABELS: Additional labels to apply to the test. The package path and # "driver=local-sync" are added automatically. # TARGET_CPU_FEATURES: If specified, a string passed as argument to # --iree-llvmcpu-target-cpu-features. # # Example: # iree_static_linker_test( # NAME # edge_detection_test # SRC # "edge_detection.mlir" # STATIC_LIB_PREFIX # edge_detection_linked_llvm_cpu # ENTRY_FUNCTION # "edge_detect_sobel_operator" # FUNCTION_INPUTS # "1x128x128xf32" # COMPILER_FLAGS # "--iree-input-type=stablehlo" # ) function(iree_static_linker_test) if(NOT IREE_BUILD_TESTS) return() endif() # See comment in iree_check_test about this condition. if(NOT IREE_BUILD_COMPILER AND NOT IREE_HOST_BIN_DIR) return() endif() if(NOT (IREE_TARGET_BACKEND_LLVM_CPU OR IREE_HOST_BIN_DIR) OR NOT IREE_HAL_DRIVER_LOCAL_SYNC) return() endif() cmake_parse_arguments( _RULE "EMITC" "NAME;SRC;DRIVER;STATIC_LIB_PREFIX;ENTRY_FUNCTION;INPUT_TYPE;HAL_TYPE" "COMPILER_FLAGS;LABELS;TARGET_CPU_FEATURES;FUNCTION_INPUTS" ${ARGN} ) if(_RULE_EMITC AND NOT (IREE_OUTPUT_FORMAT_C OR IREE_HOST_BIN_DIR)) return() endif() iree_package_name(_PACKAGE_NAME) iree_package_ns(_PACKAGE_NS) set(_NAME "${_PACKAGE_NAME}_${_RULE_NAME}") # Set up static library name. set(_O_FILE_NAME "${_RULE_NAME}.o") set(_H_FILE_NAME "${_RULE_NAME}.h") # Set common iree-compile flags set(_COMPILER_ARGS ${_RULE_COMPILER_FLAGS}) list(APPEND _COMPILER_ARGS "--iree-hal-target-backends=llvm-cpu") if(_RULE_TARGET_CPU_FEATURES) list(APPEND _COMPILER_ARGS "--iree-llvmcpu-target-cpu-features=${_RULE_TARGET_CPU_FEATURES}") endif() if(_RULE_EMITC) set(_C_FILE_NAME "${_RULE_NAME}_emitc.h") iree_c_module( NAME ${_RULE_NAME}_emitc SRC "${_RULE_SRC}" FLAGS ${_COMPILER_ARGS} H_FILE_OUTPUT "${_C_FILE_NAME}" STATIC_LIB_PATH "${_O_FILE_NAME}" NO_RUNTIME ) else() # bytecode module path # Generate the embed data with the bytecode module. set(_MODULE_NAME "${_RULE_NAME}_module") set(_EMBED_H_FILE_NAME ${_MODULE_NAME}_c.h) iree_bytecode_module( NAME ${_MODULE_NAME} SRC "${_RULE_SRC}" FLAGS ${_COMPILER_ARGS} STATIC_LIB_PATH "${_O_FILE_NAME}" C_IDENTIFIER "${_NAME}" PUBLIC ) endif(_RULE_EMITC) set(_LIB_NAME "${_NAME}_lib") add_library(${_LIB_NAME} STATIC ${_O_FILE_NAME} ) SET_TARGET_PROPERTIES( ${_LIB_NAME} PROPERTIES LINKER_LANGUAGE C ) # If any of these arguments are not specified, only compilation will be # tested. if(NOT _RULE_FUNCTION_INPUTS OR NOT _RULE_ENTRY_FUNCTION OR NOT _RULE_STATIC_LIB_PREFIX) return() endif() # Set alias for this static library to be used later in the function. add_library(${_PACKAGE_NS}::${_RULE_NAME}_lib ALIAS ${_LIB_NAME}) # Process module input configs to be used in the c template. # Example: # FUNCTION_INPUTS "1x28x28x1xf32" # _INPUT_NUM 1 # _INPUT_DIM_STR 4 # _INPUT_SIZE_STR 768 # _INPUT_SHAPE_STR of {1, 28, 28, 1}, # FUNCTION_INPUTS "4xf32,f32" # _INPUT_NUM 2 # _INPUT_DIM_STR 1, 1 # _INPUT_SIZE_STR 4, 1 # _INPUT_SHAPE_STR of {4}, {1}, string(REPLACE "," ";" _INPUTS_LIST "${_RULE_FUNCTION_INPUTS}") list(LENGTH _INPUTS_LIST _INPUT_NUM) set(_INPUT_DIM_LIST) set(_INPUT_SIZE_LIST) set(_INPUT_SHAPE_STR) set(_INPUT_DIM_MAX 0) foreach(_INPUT_ENTRY ${_INPUTS_LIST}) # Separate the function input into shape (m,n,c) and format string(REPLACE "x" ";" _INPUT_ENTRY_LIST "${_INPUT_ENTRY}") list(POP_BACK _INPUT_ENTRY_LIST _INPUT_FORMAT) # Process shape to compute the size (number of elements) and dimention. # The results are stored into lists to support multiple inputs if(NOT _INPUT_ENTRY_LIST) # single entry input set(_INPUT_ENTRY_LIST "1") endif() string(REPLACE ";" ", " _INPUT_ENTRY_STR "${_INPUT_ENTRY_LIST}") set(_INPUT_SHAPE_STR "${_INPUT_SHAPE_STR}\{${_INPUT_ENTRY_STR}\}, ") list(LENGTH _INPUT_ENTRY_LIST _INPUT_DIM) list(APPEND _INPUT_DIM_LIST ${_INPUT_DIM}) if(_INPUT_DIM GREATER _INPUT_DIM_MAX) set(_INPUT_DIM_MAX ${_INPUT_DIM}) endif() set(_INPUT_SIZE 1) foreach(_INPUT_DIM_VAL ${_INPUT_ENTRY_LIST}) math(EXPR _INPUT_SIZE "${_INPUT_SIZE} * ${_INPUT_DIM_VAL}") endforeach() list(APPEND _INPUT_SIZE_LIST ${_INPUT_SIZE}) endforeach(_INPUT_ENTRY) string(REPLACE ";" ", " _INPUT_DIM_STR "${_INPUT_DIM_LIST}") string(REPLACE ";" ", " _INPUT_SIZE_STR "${_INPUT_SIZE_LIST}") # Process input and HAL data format based on the last input entry. set(IREE_INPUT_TYPE) set(IREE_HAL_TYPE) if("${_INPUT_FORMAT}" STREQUAL "f32") set(IREE_INPUT_TYPE "float") set(IREE_HAL_TYPE "IREE_HAL_ELEMENT_TYPE_FLOAT_32") elseif("${_INPUT_FORMAT}" STREQUAL "i32") set(IREE_INPUT_TYPE "int32_t") set(IREE_HAL_TYPE "IREE_HAL_ELEMENT_TYPE_SINT_32") elseif("${_INPUT_FORMAT}" STREQUAL "i16") set(IREE_INPUT_TYPE "int16_t") set(IREE_HAL_TYPE "IREE_HAL_ELEMENT_TYPE_SINT_16") elseif("${_INPUT_FORMAT}" STREQUAL "i8") set(IREE_INPUT_TYPE "int8_t") set(IREE_HAL_TYPE "IREE_HAL_ELEMENT_TYPE_SINT_8") elseif("${_INPUT_FORMAT}" STREQUAL "ui8") set(IREE_INPUT_TYPE "uint8_t") set(IREE_HAL_TYPE "IREE_HAL_ELEMENT_TYPE_UINT_8") else() message(SEND_ERROR "Unsupported format ${_INPUT_FORMAT}") endif() # Generate the source file. # TODO(scotttodd): Move to build time instead of configure time? set(IREE_STATIC_LIB_HDR "\"${_H_FILE_NAME}\"") set(IREE_STATIC_LIB_QUERY_FN "${_RULE_STATIC_LIB_PREFIX}_library_query") set(IREE_MODULE_HDR "${_EMBED_H_FILE_NAME}") set(IREE_MODULE_CREATE_FN "${_NAME}_create\(\)") set(IREE_EMITC_HDR "${_C_FILE_NAME}") set(IREE_MODULE_MAIN_FN "\"module.${_RULE_ENTRY_FUNCTION}\"") set(IREE_INPUT_NUM "${_INPUT_NUM}") set(IREE_INPUT_DIM_MAX "${_INPUT_DIM_MAX}") set(IREE_INPUT_DIM_ARR "\{${_INPUT_DIM_STR}\}") set(IREE_INPUT_SIZE_ARR "\{${_INPUT_SIZE_STR}\}") set(IREE_INPUT_SHAPE_ARR "\{${_INPUT_SHAPE_STR}\}") set(IREE_EXE_NAME "\"${_RULE_NAME}\"") configure_file( "${IREE_ROOT_DIR}/build_tools/cmake/static_linker_test.c.in" "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_NAME}.c" ) iree_cc_binary( NAME ${_RULE_NAME}_run SRCS "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_NAME}.c" DEPS ::${_RULE_NAME}_lib iree::runtime iree::hal::drivers::local_sync::sync_driver iree::hal::local::loaders::static_library_loader ) if(_RULE_EMITC) target_link_libraries(${_NAME}_run PRIVATE iree_vm_shims_emitc ${_NAME}_emitc ) target_compile_definitions(${_NAME}_run PRIVATE EMITC_IMPLEMENTATION=\"${_C_FILE_NAME}\" ) else() target_link_libraries(${_NAME}_run PRIVATE ${_NAME}_module_c) endif() add_dependencies(iree-test-deps "${_NAME}_run") iree_native_test( NAME ${_RULE_NAME} SRC ::${_RULE_NAME}_run DRIVER local-sync LABELS ${_RULE_LABELS} ${_RULE_TARGET_CPU_FEATURES} ) endfunction()