From 846cc13ca82ca221f8c0b353fbb776db0e1791b5 Mon Sep 17 00:00:00 2001 From: Megvii Engine Team Date: Mon, 8 Nov 2021 16:04:15 +0800 Subject: [PATCH] fix(mge/functional): fix default dtype of F.full GitOrigin-RevId: 5cd34af9bfbf57e42e22f0f602c2c12dc53732fc --- cmake/FindBANG/FindBANG.cmake | 1012 ++++++++++++++++++++ cmake/FindBANG/make2cmake.cmake | 84 ++ cmake/FindBANG/parse_cnbin.cmake | 103 ++ cmake/FindBANG/run_cncc.cmake | 200 ++++ imperative/python/megengine/functional/tensor.py | 23 +- .../python/test/unit/functional/test_tensor.py | 8 + 6 files changed, 1423 insertions(+), 7 deletions(-) create mode 100755 cmake/FindBANG/FindBANG.cmake create mode 100755 cmake/FindBANG/make2cmake.cmake create mode 100755 cmake/FindBANG/parse_cnbin.cmake create mode 100755 cmake/FindBANG/run_cncc.cmake diff --git a/cmake/FindBANG/FindBANG.cmake b/cmake/FindBANG/FindBANG.cmake new file mode 100755 index 00000000..8b8f0bbd --- /dev/null +++ b/cmake/FindBANG/FindBANG.cmake @@ -0,0 +1,1012 @@ +#.rst: +# FindBANG +# -------- +# +# Tools for building BANG C files: libraries and build dependencies. +# +# This script locates the CAMBRICON BANG C tools. It should work on linux, +# windows, and mac and should be reasonably up to date with BANG C +# releases. +# +# This script makes use of the standard find_package arguments of +# , REQUIRED and QUIET. BANG_FOUND will report if an +# acceptable version of BANG was found. +# +# The following variables affect the behavior of the macros in the +# script (in alphebetical order). Note that any of these flags can be +# changed multiple times in the same directory before calling +# +# BANG_CNCC_FLAGS +# -- Additional CNCC command line arguments. NOTE: multiple arguments must be +# semi-colon delimited (e.g. --bang-mlu-arch=xxx;-Wall) +# +# BANG_TARGET_CPU_ARCH +# -- Specify the name of the class of CPU architecture for which the input +# files must be compiled (e.g. specify BANG_TARGET_CPU_ARCH=armv8a, +# will append --target=armv8a to BANG_CNCC_FLAGS) +# +# This code is licensed under the MIT License. See the FindBANG.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# MegEngine is Licensed under the Apache License, Version 2.0 (the "License") +# +# Copyright (c) 2014-2020 Megvii Inc. All rights reserved. +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# +# This file has been modified by Megvii ("Megvii Modifications"). +# All Megvii Modifications are Copyright (C) 2014-2019 Megvii Inc. All rights reserved +############################################################################### + +# FindBANG.cmake + +############################################################################### +# Check for required components +############################################################################### +set(BANG_FOUND TRUE) + +############################################################################### +# This macro helps us find the location of helper files we will need the full path to +############################################################################### +macro(BANG_FIND_HELPER_FILE _name _extension) + set(_full_name "${_name}.${_extension}") + # CMAKE_CURRENT_LIST_FILE contains the full path to the file currently being + # processed. Using this variable, we can pull out the current path, and + # provide a way to get access to the other files we need local to here. + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + set(BANG_${_name} "${CMAKE_CURRENT_LIST_DIR}/${_full_name}") + if(NOT EXISTS "${BANG_${_name}}") + set(error_message "${_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}") + if(BANG_FIND_REQUIRED) + message(FATAL_ERROR "${error_message}") + else() + if(NOT BANG_FIND_QUIETLY) + message(STATUS "${error_message}") + endif() + endif() + endif() + # Set this variable as internal, so the user isn't bugged with it. + set(BANG_${_name} ${BANG_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE) +endmacro() + +bang_find_helper_file(parse_cnbin cmake) +bang_find_helper_file(make2cmake cmake) +bang_find_helper_file(run_cncc cmake) + +############################################################################### +# Add include directories to pass to the cncc command. +############################################################################### +macro(BANG_INCLUDE_DIRECTORIES) + foreach(dir ${ARGN}) + list(APPEND BANG_CNCC_INCLUDE_ARGS_USER -I${dir}) + endforeach() +endmacro() + +############################################################################## +# Separate the OPTIONS out from the sources +############################################################################## +macro(BANG_GET_SOURCES_AND_OPTIONS _sources _cmake_options _options) + set( ${_sources} ) + set( ${_cmake_options} ) + set( ${_options} ) + set( _found_options FALSE ) + foreach(arg ${ARGN}) + if("x${arg}" STREQUAL "xOPTIONS") + set( _found_options TRUE ) + elseif( + "x${arg}" STREQUAL "xWIN32" OR + "x${arg}" STREQUAL "xMACOSX_BUNDLE" OR + "x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR + "x${arg}" STREQUAL "xSTATIC" OR + "x${arg}" STREQUAL "xSHARED" OR + "x${arg}" STREQUAL "xMODULE" + ) + list(APPEND ${_cmake_options} ${arg}) + else() + if ( _found_options ) + list(APPEND ${_options} ${arg}) + else() + # Assume this is a file + list(APPEND ${_sources} ${arg}) + endif() + endif() + endforeach() +endmacro() + +############################################################################## +# Parse the OPTIONS from ARGN and set the variables prefixed by _option_prefix +############################################################################## +macro(BANG_PARSE_CNCC_OPTIONS _option_prefix) + set( _found_config ) + foreach(arg ${ARGN}) + # Determine if we are dealing with a perconfiguration flag + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + if (arg STREQUAL "${config_upper}") + set( _found_config _${arg}) + # Set arg to nothing to keep it from being processed further + set( arg ) + endif() + endforeach() + + if ( arg ) + list(APPEND ${_option_prefix}${_found_config} "${arg}") + endif() + endforeach() +endmacro() + +##################################################################### +# BANG_INCLUDE_CNCC_DEPENDENCIES +# So we want to try and include the dependency file if it exists. If +# it doesn't exist then we need to create an empty one, so we can +# include it. +# If it does exist, then we need to check to see if all the files it +# depends on exist. If they don't then we should clear the dependency +# file and regenerate it later. This covers the case where a header +# file has disappeared or moved. +##################################################################### +macro(BANG_INCLUDE_CNCC_DEPENDENCIES dependency_file) + set(BANG_CNCC_DEPEND) + set(BANG_CNCC_DEPEND_REGENERATE FALSE) + + # Include the dependency file. Create it first if it doesn't exist . The + # INCLUDE puts a dependency that will force CMake to rerun and bring in the + # new info when it changes. DO NOT REMOVE THIS (as I did and spent a few + # hours figuring out why it didn't work. + if(NOT EXISTS ${dependency_file}) + file(WRITE ${dependency_file} "#FindBANG.cmake generated file. Do not edit.\n") + endif() + # Always include this file to force CMake to run again next + # invocation and rebuild the dependencies. + #message("including dependency_file = ${dependency_file}") + include(${dependency_file}) + + # Now we need to verify the existence of all the included files + # here. If they aren't there we need to just blank this variable and + # make the file regenerate again. + if(BANG_CNCC_DEPEND) + #message("BANG_CNCC_DEPEND found") + foreach(f ${BANG_CNCC_DEPEND}) + # message("searching for ${f}") + if(NOT EXISTS ${f}) + #message("file ${f} not found") + set(BANG_CNCC_DEPEND_REGENERATE TRUE) + endif() + endforeach() + else() + #message("BANG_CNCC_DEPEND false") + # No dependencies, so regenerate the file. + set(BANG_CNCC_DEPEND_REGENERATE TRUE) + endif() + + #message("BANG_CNCC_DEPEND_REGENERATE = ${BANG_CNCC_DEPEND_REGENERATE}") + # No incoming dependencies, so we need to generate them. Make the + # output depend on the dependency file itself, which should cause the + # rule to re-run. + if(BANG_CNCC_DEPEND_REGENERATE) + set(BANG_CNCC_DEPEND ${dependency_file}) + #message("Generating an empty dependency_file: ${dependency_file}") + file(WRITE ${dependency_file} "#FindBANG.cmake generated file. Do not edit.\n") + endif() + +endmacro() + +############################################################################### +# Helper to add the include directory for BANG only once +############################################################################### +function(BANG_ADD_BANG_INCLUDE_ONCE) + get_directory_property(_include_directories INCLUDE_DIRECTORIES) + set(_add TRUE) + if(_include_directories) + foreach(dir ${_include_directories}) + if("${dir}" STREQUAL "${BANG_INCLUDE_DIRS}") + set(_add FALSE) + endif() + endforeach() + endif() + if(_add) + include_directories(${BANG_INCLUDE_DIRS}) + endif() +endfunction() + +############################################################################## +# Build the shared library +############################################################################## +function(BANG_BUILD_SHARED_LIBRARY shared_flag) + set(cmake_args ${ARGN}) + # If SHARED, MODULE, or STATIC aren't already in the list of arguments, then + # add SHARED or STATIC based on the value of BUILD_SHARED_LIBS. + list(FIND cmake_args SHARED _bang_found_SHARED) + list(FIND cmake_args MODULE _bang_found_MODULE) + list(FIND cmake_args STATIC _bang_found_STATIC) + if( _bang_found_SHARED GREATER -1 OR + _bang_found_MODULE GREATER -1 OR + _bang_found_STATIC GREATER -1) + set(_bang_build_shared_libs) + else() + if (BUILD_SHARED_LIBS) + set(_bang_build_shared_libs SHARED) + else() + set(_bang_build_shared_libs STATIC) + endif() + endif() + set(${shared_flag} ${_bang_build_shared_libs} PARENT_SCOPE) +endfunction() + +############################################################################## +# Helper to avoid clashes of files with the same basename but different paths. +# This doesn't attempt to do exactly what CMake internals do, which is to only +# add this path when there is a conflict, since by the time a second collision +# in names is detected it's already too late to fix the first one. For +# consistency sake the relative path will be added to all files. +############################################################################## +function(BANG_COMPUTE_BUILD_PATH path build_path) + #message("BANG_COMPUTE_BUILD_PATH([${path}] ${build_path})") + # Only deal with CMake style paths from here on out + file(TO_CMAKE_PATH "${path}" bpath) + if (IS_ABSOLUTE "${bpath}") + # Absolute paths are generally unnessary, especially if something like + # file(GLOB_RECURSE) is used to pick up the files. + + string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos) + if (_binary_dir_pos EQUAL 0) + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}") + else() + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}") + endif() + endif() + + # This recipe is from cmLocalGenerator::CreateSafeUniqueObjectFileName in the + # CMake source. + + # Remove leading / + string(REGEX REPLACE "^[/]+" "" bpath "${bpath}") + # Avoid absolute paths by removing ':' + string(REPLACE ":" "_" bpath "${bpath}") + # Avoid relative paths that go up the tree + string(REPLACE "../" "__/" bpath "${bpath}") + # Avoid spaces + string(REPLACE " " "_" bpath "${bpath}") + + # Strip off the filename. I wait until here to do it, since removin the + # basename can make a path that looked like path/../basename turn into + # path/.. (notice the trailing slash). + get_filename_component(bpath "${bpath}" PATH) + + set(${build_path} "${bpath}" PARENT_SCOPE) + #message("${build_path} = ${bpath}") +endfunction() + +############################################################################## +# Compute the filename to be used by BANG_LINK_SEPARABLE_COMPILATION_OBJECTS +############################################################################## +function(BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME output_file_var bang_target object_files) + if (object_files) + set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION}) + set(output_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${bang_target}.dir/${CMAKE_CFG_INTDIR}/${bang_target}_intermediate_link${generated_extension}") + else() + set(output_file) + endif() + + set(${output_file_var} "${output_file}" PARENT_SCOPE) +endfunction() + +############################################################################## +# Setup the build rule for the separable compilation intermediate link file. +############################################################################## +function(BANG_LINK_SEPARABLE_COMPILATION_OBJECTS output_file bang_target options object_files) + if (object_files) + + set_source_files_properties("${output_file}" + PROPERTIES + EXTERNAL_OBJECT TRUE # This is an object file not to be compiled, but only + # be linked. + GENERATED TRUE # This file is generated during the build + ) + + # For now we are ignoring all the configuration specific flags. + set(cncc_flags) + BANG_PARSE_CNCC_OPTIONS(cncc_flags ${options}) + + # If -ccbin, --compiler-bindir has been specified, don't do anything. Otherwise add it here. + list( FIND cncc_flags "-ccbin" ccbin_found0 ) + list( FIND cncc_flags "--compiler-bindir" ccbin_found1 ) + if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND BANG_HOST_COMPILER ) + # Match VERBATIM check below. + if(BANG_HOST_COMPILER MATCHES "\\$\\(VCInstallDir\\)") + list(APPEND cncc_flags -ccbin "\"${BANG_HOST_COMPILER}\"") + else() + list(APPEND cncc_flags -ccbin "${BANG_HOST_COMPILER}") + endif() + endif() + + # Create a list of flags specified by BANG_CNCC_FLAGS_${CONFIG} and CMAKE_${BANG_C_OR_CXX}_FLAGS* + set(config_specific_flags) + set(flags) + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + # Add config specific flags + foreach(f ${BANG_CNCC_FLAGS_${config_upper}}) + list(APPEND config_specific_flags $<$:${f}>) + endforeach() + set(important_host_flags) + _bang_get_important_host_flags(important_host_flags "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}") + foreach(f ${important_host_flags}) + list(APPEND flags $<$:-Xcompiler> $<$:${f}>) + endforeach() + endforeach() + # Add CMAKE_${BANG_C_OR_CXX}_FLAGS + set(important_host_flags) + _bang_get_important_host_flags(important_host_flags "${CMAKE_${BANG_C_OR_CXX}_FLAGS}") + foreach(f ${important_host_flags}) + list(APPEND flags -Xcompiler ${f}) + endforeach() + + # Add our general BANG_CNCC_FLAGS with the configuration specifig flags + set(cncc_flags ${BANG_CNCC_FLAGS} ${config_specific_flags} ${cncc_flags}) + + file(RELATIVE_PATH output_file_relative_path "${CMAKE_BINARY_DIR}" "${output_file}") + + # Some generators don't handle the multiple levels of custom command + # dependencies correctly (obj1 depends on file1, obj2 depends on obj1), so + # we work around that issue by compiling the intermediate link object as a + # pre-link custom command in that situation. + set(do_obj_build_rule TRUE) + if (MSVC_VERSION GREATER 1599 AND MSVC_VERSION LESS 1800) + # VS 2010 and 2012 have this problem. + set(do_obj_build_rule FALSE) + endif() + + set(_verbatim VERBATIM) + if(cncc_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_verbatim "") + endif() + + if (do_obj_build_rule) + add_custom_command( + OUTPUT ${output_file} + DEPENDS ${object_files} + COMMAND ${BANG_CNCC_EXECUTABLE} ${cncc_flags} -dlink ${object_files} -o ${output_file} + ${flags} + COMMENT "Building CNCC intermediate link file ${output_file_relative_path}" + ${_verbatim} + ) + else() + get_filename_component(output_file_dir "${output_file}" DIRECTORY) + add_custom_command( + TARGET ${bang_target} + PRE_LINK + COMMAND ${CMAKE_COMMAND} -E echo "Building CNCC intermediate link file ${output_file_relative_path}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}" + COMMAND ${BANG_CNCC_EXECUTABLE} ${cncc_flags} ${flags} -dlink ${object_files} -o "${output_file}" + ${_verbatim} + ) + endif() + endif() +endfunction() + +############################################################################## +# This helper macro populates the following variables and setups up custom +# commands and targets to invoke the cncc compiler to generate C or MLISA source +# dependent upon the format parameter. +# INPUT: +# bang_target - Target name +# format - MLISA, CNBIN, CNFATBIN or OBJ +# FILE1 .. FILEN - The remaining arguments are the sources to be wrapped. +# OPTIONS - Extra options to CNCC +# OUTPUT: +# generated_files - List of generated files +############################################################################## +macro(BANG_WRAP_SRCS bang_target format generated_files) + # Set up all the command line flags here, so that they can be overridden on a per target basis. + + set(cncc_flags "") + + set(BANG_C_OR_CXX CXX) + + set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION}) + + if(BANG_TARGET_CPU_ARCH) + set(cncc_flags ${cncc_flags} "--target=${BANG_TARGET_CPU_ARCH}") + endif() + + set( BANG_build_configuration "${CMAKE_BUILD_TYPE}") + + # Get the include directories for this directory and use them for our cncc command. + # Remove duplicate entries which may be present since include_directories + # in CMake >= 2.8.8 does not remove them. + get_directory_property(BANG_CNCC_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES) + list(REMOVE_DUPLICATES BANG_CNCC_INCLUDE_DIRECTORIES) + if(BANG_CNCC_INCLUDE_DIRECTORIES) + foreach(dir ${BANG_CNCC_INCLUDE_DIRECTORIES}) + list(APPEND BANG_CNCC_INCLUDE_ARGS -I${dir}) + endforeach() + endif() + + # Reset these variables + set(BANG_WRAP_OPTION_CNCC_FLAGS) + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + set(BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}) + endforeach() + + BANG_GET_SOURCES_AND_OPTIONS(_bang_wrap_sources _bang_wrap_cmake_options _bang_wrap_options ${ARGN}) + BANG_PARSE_CNCC_OPTIONS(BANG_WRAP_OPTION_CNCC_FLAGS ${_bang_wrap_options}) + + # Figure out if we are building a shared library. BUILD_SHARED_LIBS is + # respected in BANG_ADD_LIBRARY. + set(_bang_build_shared_libs FALSE) + # SHARED, MODULE + list(FIND _bang_wrap_cmake_options SHARED _bang_found_SHARED) + list(FIND _bang_wrap_cmake_options MODULE _bang_found_MODULE) + if(_bang_found_SHARED GREATER -1 OR _bang_found_MODULE GREATER -1) + set(_bang_build_shared_libs TRUE) + endif() + # STATIC + list(FIND _bang_wrap_cmake_options STATIC _bang_found_STATIC) + if(_bang_found_STATIC GREATER -1) + set(_bang_build_shared_libs FALSE) + endif() + + # BANG_HOST_FLAGS + if(_bang_build_shared_libs) + # If we are setting up code for a shared library, then we need to add extra flags for + # compiling objects for shared libraries. + set(BANG_HOST_SHARED_FLAGS ${CMAKE_SHARED_LIBRARY_${BANG_C_OR_CXX}_FLAGS}) + else() + set(BANG_HOST_SHARED_FLAGS) + endif() + # Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We + # always need to set the SHARED_FLAGS, though. + set(_bang_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${BANG_C_OR_CXX}_FLAGS} ${BANG_HOST_SHARED_FLAGS})") + + set(_bang_cncc_flags_config "# Build specific configuration flags") + # Loop over all the configuration types to generate appropriate flags for run_cncc.cmake + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + # CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS + # we convert the strings to lists (like we want). + + set(_bang_C_FLAGS "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}") + set(_bang_host_flags "${_bang_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_bang_C_FLAGS})") + + # Note that if we ever want BANG_CNCC_FLAGS_ to be string (instead of a list + # like it is currently), we can remove the quotes around the + # ${BANG_CNCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_ variable. + set(_bang_cncc_flags_config "${_bang_cncc_flags_config}\nset(BANG_CNCC_FLAGS_${config_upper} ${BANG_CNCC_FLAGS_${config_upper}} ;; ${BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}})") + endforeach() + + # Process the C++11 flag. If the host sets the flag, we need to add it to cncc and + # remove it from the host. This is because -Xcompile -std=c++ will choke cncc (it uses + # the C preprocessor). In order to get this to work correctly, we need to use cncc's + # specific c++11 flag. + if( "${_bang_host_flags}" MATCHES "-std=c\\+\\+11") + # Add the c++11 flag to cncc if it isn't already present. Note that we only look at + # the main flag instead of the configuration specific flags. + if( NOT "${BANG_CNCC_FLAGS}" MATCHES "-std;c\\+\\+11" ) + list(APPEND cncc_flags -std=c++11) + endif() + string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _bang_host_flags "${_bang_host_flags}") + endif() + + # Get the list of definitions from the directory property + get_directory_property(BANG_CNCC_DEFINITIONS COMPILE_DEFINITIONS) + if(BANG_CNCC_DEFINITIONS) + foreach(_definition ${BANG_CNCC_DEFINITIONS}) + list(APPEND cncc_flags "-D${_definition}") + endforeach() + endif() + + if(_bang_build_shared_libs) + list(APPEND cncc_flags "-D${bang_target}_EXPORTS") + endif() + + # Reset the output variable + set(_bang_wrap_generated_files "") + + # Iterate over the macro arguments and create custom + # commands for all the .cu files. + foreach(file ${ARGN}) + # Ignore any file marked as a HEADER_FILE_ONLY + get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) + # Allow per source file overrides of the format. Also allows compiling non-.cu files. + get_source_file_property(_bang_source_format ${file} BANG_SOURCE_PROPERTY_FORMAT) + if((${file} MATCHES "\\.mlu$" OR _bang_source_format) AND NOT _is_header) + + if(NOT _bang_source_format) + set(_bang_source_format ${format}) + endif() + + if( ${_bang_source_format} MATCHES "OBJ") + set( bang_compile_to_external_module OFF ) + else() + set( bang_compile_to_external_module ON ) + if( ${_bang_source_format} MATCHES "MLISA" ) + set( bang_compile_to_external_module_type "mlisa" ) + elseif( ${_bang_source_format} MATCHES "CNBIN") + set( bang_compile_to_external_module_type "cnbin" ) + elseif( ${_bang_source_format} MATCHES "CNFATBIN") + set( bang_compile_to_external_module_type "cnfatbin" ) + else() + message( FATAL_ERROR "Invalid format flag passed to BANG_WRAP_SRCS or set with BANG_SOURCE_PROPERTY_FORMAT file property for file '${file}': '${_bang_source_format}'. Use OBJ, MLISA, CNBIN or CNFATBIN.") + endif() + endif() + + if(bang_compile_to_external_module) + # Don't use any of the host compilation flags for MLISA targets. + set(BANG_HOST_FLAGS) + set(BANG_CNCC_FLAGS_CONFIG) + else() + set(BANG_HOST_FLAGS ${_bang_host_flags}) + set(BANG_CNCC_FLAGS_CONFIG ${_bang_cncc_flags_config}) + endif() + + # Determine output directory + bang_compute_build_path("${file}" bang_build_path) + set(bang_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${bang_target}.dir/${bang_build_path}") + if(BANG_GENERATED_OUTPUT_DIR) + set(bang_compile_output_dir "${BANG_GENERATED_OUTPUT_DIR}") + else() + if ( bang_compile_to_external_module ) + set(bang_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}") + else() + set(bang_compile_output_dir "${bang_compile_intermediate_directory}") + endif() + endif() + + # Add a custom target to generate a c or mlisa file. ###################### + + get_filename_component( basename ${file} NAME ) + if( bang_compile_to_external_module ) + set(generated_file_path "${bang_compile_output_dir}") + set(generated_file_basename "${bang_target}_generated_${basename}.${bang_compile_to_external_module_type}") + set(format_flag "-${bang_compile_to_external_module_type}") + file(MAKE_DIRECTORY "${bang_compile_output_dir}") + else() + set(generated_file_path "${bang_compile_output_dir}/${CMAKE_CFG_INTDIR}") + set(generated_file_basename "${bang_target}_generated_${basename}${generated_extension}") + set(format_flag "-c") + endif() + + # Set all of our file names. Make sure that whatever filenames that have + # generated_file_path in them get passed in through as a command line + # argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time + # instead of configure time. + set(generated_file "${generated_file_path}/${generated_file_basename}") + set(cmake_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.depend") + set(CNCC_generated_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.CNCC-depend") + set(generated_cnbin_file "${generated_file_path}/${generated_file_basename}.cnbin.txt") + set(custom_target_script "${bang_compile_intermediate_directory}/${generated_file_basename}.cmake") + + # Setup properties for obj files: + if( NOT bang_compile_to_external_module ) + set_source_files_properties("${generated_file}" + PROPERTIES + EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked. + ) + endif() + + # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path. + get_filename_component(file_path "${file}" PATH) + if(IS_ABSOLUTE "${file_path}") + set(source_file "${file}") + else() + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + # Bring in the dependencies. Creates a variable BANG_CNCC_DEPEND ####### + bang_include_cncc_dependencies(${cmake_dependency_file}) + + # Build the CNCC made dependency file ################################### + set(build_cnbin OFF) + if ( BANG_BUILD_CNBIN ) + if ( NOT bang_compile_to_external_module ) + set ( build_cnbin ON ) + endif() + endif() + + # Configure the build script + configure_file("${BANG_run_cncc}" "${custom_target_script}" @ONLY) + + # So if a user specifies the same bang file as input more than once, you + # can have bad things happen with dependencies. Here we check an option + # to see if this is the behavior they want. + set(main_dep DEPENDS ${source_file}) + + if(BANG_VERBOSE_BUILD) + set(verbose_output ON) + elseif(CMAKE_GENERATOR MATCHES "Makefiles") + set(verbose_output "$(VERBOSE)") + else() + set(verbose_output OFF) + endif() + + # Create up the comment string + file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}") + if(bang_compile_to_external_module) + set(bang_build_comment_string "Building CNCC ${bang_compile_to_external_module_type} file ${generated_file_relative_path}") + else() + set(bang_build_comment_string "Building CNCC object ${generated_file_relative_path}") + endif() + + set(_verbatim VERBATIM) + if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_verbatim "") + endif() + + # Build the generated file and dependency file ########################## + add_custom_command( + OUTPUT ${generated_file} + # These output files depend on the source_file and the contents of cmake_dependency_file + ${main_dep} + DEPENDS ${BANG_CNCC_DEPEND} + DEPENDS ${custom_target_script} + # Make sure the output directory exists before trying to write to it. + COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} ARGS + -D verbose:BOOL=${verbose_output} + ${ccbin_flags} + -D build_configuration:STRING=${BANG_build_configuration} + -D "generated_file:STRING=${generated_file}" + -D "generated_cnbin_file:STRING=${generated_cnbin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${bang_compile_intermediate_directory}" + COMMENT "${bang_build_comment_string}" + ${_verbatim} + ) + + # Make sure the build system knows the file is generated. + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + + list(APPEND _bang_wrap_generated_files ${generated_file}) + + # Add the other files that we want cmake to clean on a cleanup ########## + list(APPEND BANG_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}") + list(REMOVE_DUPLICATES BANG_ADDITIONAL_CLEAN_FILES) + set(BANG_ADDITIONAL_CLEAN_FILES ${BANG_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the bang dependency scanning.") + + endif() + endforeach() + + # Set the return parameter + set(${generated_files} ${_bang_wrap_generated_files}) +endmacro() + +############################################################################### +############################################################################### +# Locate NEUWARE, Set Build Type, etc. +############################################################################### +############################################################################### + +# BANG_CNCC_EXECUTABLE +find_program(BANG_CNCC_EXECUTABLE + NAMES cncc + PATHS "${NEUWARE_ROOT_DIR}" + ENV NEUWARE_PATH + ENV NEUWARE_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +find_program(BANG_CNCC_EXECUTABLE cncc) +mark_as_advanced(BANG_CNCC_EXECUTABLE) + +############################################################################### +############################################################################### +# ADD LIBRARY +############################################################################### +############################################################################### +macro(BANG_ADD_LIBRARY bang_target) + + BANG_ADD_BANG_INCLUDE_ONCE() + + # Separate the sources from the options + BANG_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + BANG_BUILD_SHARED_LIBRARY(_bang_shared_flag ${ARGN}) + # Create custom commands and targets for each file. + BANG_WRAP_SRCS( ${bang_target} OBJ _generated_files ${_sources} + ${_cmake_options} ${_bang_shared_flag} + OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${bang_target} "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_library(${bang_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${bang_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + BANG_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${bang_target} "${_options}" "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${bang_target} + ${BANG_LIBRARIES} + ) + + # We need to set the linker language based on what the expected generated file + # would be. BANG_C_OR_CXX is computed based on BANG_HOST_COMPILATION_CPP. + set_target_properties(${bang_target} + PROPERTIES + LINKER_LANGUAGE ${BANG_C_OR_CXX} + ) + +endmacro() + + +############################################################################### +############################################################################### +# ADD EXECUTABLE +############################################################################### +############################################################################### +macro(BANG_ADD_EXECUTABLE bang_target) + + BANG_ADD_BANG_INCLUDE_ONCE() + + # Separate the sources from the options + BANG_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + # Create custom commands and targets for each file. + BANG_WRAP_SRCS( ${bang_target} OBJ _generated_files ${_sources} OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${bang_target} "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_executable(${bang_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${bang_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + BANG_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${bang_target} "${_options}" "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${bang_target} + ${BANG_LIBRARIES} + ) + + # We need to set the linker language based on what the expected generated file + # would be. BANG_C_OR_CXX is computed based on BANG_HOST_COMPILATION_CPP. + set_target_properties(${bang_target} + PROPERTIES + LINKER_LANGUAGE ${BANG_C_OR_CXX} + ) + +endmacro() + +##################################################################################### +# This macro invokes the cncc compiler to compile mlu source files, and to generate +# object files. +# INPUT: +# _source_files - List of mlu source files to be compiled +# _include_directories_generator_user - List of user provided include files +# OUTPUT: +# _generated_files - List of generated files +##################################################################################### +macro(BANG_COMPILE _generated_files _source_files _include_directories_generator_user) + # Set up all the command line flags here, so that they can be overridden on a per target basis. + set(cncc_flags "") + + set(BANG_C_OR_CXX CXX) + + set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION}) + + if(BANG_TARGET_CPU_ARCH) + set(cncc_flags ${cncc_flags} "--target=${BANG_TARGET_CPU_ARCH}") + endif() + + set( BANG_build_configuration "${CMAKE_BUILD_TYPE}") + + set(include_directories_generator ${_include_directories_generator_user}) + foreach(dir ${include_directories_generator}) + if(dir) + list(APPEND BANG_CNCC_INCLUDE_ARGS -I${dir}) + endif() + endforeach() + + # Reset these variables + set(BANG_WRAP_OPTION_CNCC_FLAGS) + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + set(BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}) + endforeach() + + BANG_GET_SOURCES_AND_OPTIONS(_bang_wrap_sources _bang_wrap_cmake_options _bang_wrap_options ${_source_files}) + BANG_PARSE_CNCC_OPTIONS(BANG_WRAP_OPTION_CNCC_FLAGS ${_bang_wrap_options}) + + set(BANG_HOST_SHARED_FLAGS) + # Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We + # always need to set the SHARED_FLAGS, though. + set(_bang_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${BANG_C_OR_CXX}_FLAGS} ${BANG_HOST_SHARED_FLAGS})") + + set(_bang_cncc_flags_config "# Build specific configuration flags") + # Loop over all the configuration types to generate appropriate flags for run_cncc.cmake + foreach(config ${BANG_configuration_types}) + string(TOUPPER ${config} config_upper) + # CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS + # we convert the strings to lists (like we want). + + set(_bang_C_FLAGS "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}") + set(_bang_host_flags "${_bang_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_bang_C_FLAGS})") + + # Note that if we ever want BANG_CNCC_FLAGS_ to be string (instead of a list + # like it is currently), we can remove the quotes around the + # ${BANG_CNCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_ variable. + set(_bang_cncc_flags_config "${_bang_cncc_flags_config}\nset(BANG_CNCC_FLAGS_${config_upper} ${BANG_CNCC_FLAGS_${config_upper}} ;; ${BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}})") + endforeach() + + # Process the C++11 flag. If the host sets the flag, we need to add it to cncc and + # remove it from the host. This is because -Xcompile -std=c++ will choke cncc (it uses + # the C preprocessor). In order to get this to work correctly, we need to use cncc's + # specific c++11 flag. + if( "${_bang_host_flags}" MATCHES "-std=c\\+\\+11") + # Add the c++11 flag to cncc if it isn't already present. Note that we only look at + # the main flag instead of the configuration specific flags. + if( NOT "${BANG_CNCC_FLAGS}" MATCHES "-std;c\\+\\+11" ) + list(APPEND cncc_flags -std=c++11) + endif() + string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _bang_host_flags "${_bang_host_flags}") + endif() + + # Get the list of definitions from the directory property + get_directory_property(BANG_CNCC_DEFINITIONS COMPILE_DEFINITIONS) + if(BANG_CNCC_DEFINITIONS) + foreach(_definition ${BANG_CNCC_DEFINITIONS}) + list(APPEND cncc_flags "-D${_definition}") + endforeach() + endif() + + # Reset the output variable + set(_bang_wrap_generated_files "") + + # Iterate over the macro arguments and create custom + # commands for all the .cu files. + foreach(file ${_source_files}) + # Ignore any file marked as a HEADER_FILE_ONLY + get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) + # Allow per source file overrides of the format. Also allows compiling non-.cu files. + get_source_file_property(_bang_source_format ${file} BANG_SOURCE_PROPERTY_FORMAT) + if((${file} MATCHES "\\.mlu$" OR _bang_source_format) AND NOT _is_header) + + set(_bang_source_format "OBJ") + + set(BANG_HOST_FLAGS ${_bang_host_flags}) + set(BANG_CNCC_FLAGS_CONFIG ${_bang_cncc_flags_config}) + + # Determine output directory + bang_compute_build_path("${file}" bang_build_path) + set(bang_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/bang_compile.dir/${bang_build_path}") + if(BANG_GENERATED_OUTPUT_DIR) + set(bang_compile_output_dir "${BANG_GENERATED_OUTPUT_DIR}") + else() + set(bang_compile_output_dir "${bang_compile_intermediate_directory}") + endif() + + # Add a custom target to generate a c or mlisa file. ###################### + + get_filename_component( basename ${file} NAME ) + set(generated_file_path "${bang_compile_output_dir}/${CMAKE_CFG_INTDIR}") + set(generated_file_basename "bang_compile_generated_${basename}${generated_extension}") + set(format_flag "-c") + + # Set all of our file names. Make sure that whatever filenames that have + # generated_file_path in them get passed in through as a command line + # argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time + # instead of configure time. + set(generated_file "${generated_file_path}/${generated_file_basename}") + set(cmake_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.depend") + set(CNCC_generated_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.CNCC-depend") + set(generated_cnbin_file "${generated_file_path}/${generated_file_basename}.cnbin.txt") + set(custom_target_script "${bang_compile_intermediate_directory}/${generated_file_basename}.cmake") + + set_source_files_properties("${generated_file}" + PROPERTIES + EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked. + ) + + # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path. + get_filename_component(file_path "${file}" PATH) + if(IS_ABSOLUTE "${file_path}") + set(source_file "${file}") + else() + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + # Bring in the dependencies. Creates a variable BANG_CNCC_DEPEND ####### + bang_include_cncc_dependencies(${cmake_dependency_file}) + + # Build the CNCC made dependency file ################################### + set(build_cnbin OFF) + + # Configure the build script + configure_file("${BANG_run_cncc}" "${custom_target_script}" @ONLY) + + # So if a user specifies the same bang file as input more than once, you + # can have bad things happen with dependencies. Here we check an option + # to see if this is the behavior they want. + set(main_dep DEPENDS ${source_file}) + + if(BANG_VERBOSE_BUILD) + set(verbose_output ON) + elseif(CMAKE_GENERATOR MATCHES "Makefiles") + set(verbose_output "$(VERBOSE)") + else() + set(verbose_output OFF) + endif() + + # Create up the comment string + file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}") + set(bang_build_comment_string "Building CNCC object ${generated_file_relative_path}") + + set(_verbatim VERBATIM) + if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_verbatim "") + endif() + + # Build the generated file and dependency file ########################## + add_custom_command( + OUTPUT ${generated_file} + # These output files depend on the source_file and the contents of cmake_dependency_file + ${main_dep} + DEPENDS ${BANG_CNCC_DEPEND} + DEPENDS ${custom_target_script} + # Make sure the output directory exists before trying to write to it. + COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} ARGS + -D verbose:BOOL=${verbose_output} + ${ccbin_flags} + -D build_configuration:STRING=${BANG_build_configuration} + -D "generated_file:STRING=${generated_file}" + -D "generated_cnbin_file:STRING=${generated_cnbin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${bang_compile_intermediate_directory}" + COMMENT "${bang_build_comment_string}" + ${_verbatim} + ) + + # Make sure the build system knows the file is generated. + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + + list(APPEND _bang_wrap_generated_files ${generated_file}) + + # Add the other files that we want cmake to clean on a cleanup ########## + list(APPEND BANG_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}") + list(REMOVE_DUPLICATES BANG_ADDITIONAL_CLEAN_FILES) + set(BANG_ADDITIONAL_CLEAN_FILES ${BANG_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the bang dependency scanning.") + + endif() + endforeach() + + # Set the return parameter + set(${_generated_files} ${_bang_wrap_generated_files}) +endmacro() diff --git a/cmake/FindBANG/make2cmake.cmake b/cmake/FindBANG/make2cmake.cmake new file mode 100755 index 00000000..b3875c58 --- /dev/null +++ b/cmake/FindBANG/make2cmake.cmake @@ -0,0 +1,84 @@ +# This code is licensed under the MIT License. See the FindBANG.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +####################################################################### +# This converts a file written in makefile syntax into one that can be included +# by CMake. + +file(READ ${input_file} depend_text) + +if (NOT "${depend_text}" STREQUAL "") + + # message("FOUND DEPENDS") + + string(REPLACE "\\ " " " depend_text ${depend_text}) + + # This works for the cncc -M generated dependency files. + string(REGEX REPLACE "^.* : " "" depend_text ${depend_text}) + string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text}) + + set(dependency_list "") + + foreach(file ${depend_text}) + + string(REGEX REPLACE "^ +" "" file ${file}) + + # OK, now if we had a UNC path, cncc has a tendency to only output the first '/' + # instead of '//'. Here we will test to see if the file exists, if it doesn't then + # try to prepend another '/' to the path and test again. If it still fails remove the + # path. + + if(NOT EXISTS "${file}") + if (EXISTS "/${file}") + set(file "/${file}") + else() + message(WARNING " Removing non-existent dependency file: ${file}") + set(file "") + endif() + endif() + + if(NOT IS_DIRECTORY "${file}") + # If softlinks start to matter, we should change this to REALPATH. For now we need + # to flatten paths, because cncc can generate stuff like /bin/../include instead of + # just /include. + get_filename_component(file_absolute "${file}" ABSOLUTE) + list(APPEND dependency_list "${file_absolute}") + endif() + + endforeach() + +else() + # message("FOUND NO DEPENDS") +endif() + +# Remove the duplicate entries and sort them. +list(REMOVE_DUPLICATES dependency_list) +list(SORT dependency_list) + +foreach(file ${dependency_list}) + set(bang_cncc_depend "${bang_cncc_depend} \"${file}\"\n") +endforeach() + +file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(BANG_CNCC_DEPEND\n ${bang_cncc_depend})\n\n") diff --git a/cmake/FindBANG/parse_cnbin.cmake b/cmake/FindBANG/parse_cnbin.cmake new file mode 100755 index 00000000..8143802f --- /dev/null +++ b/cmake/FindBANG/parse_cnbin.cmake @@ -0,0 +1,103 @@ +# This code is licensed under the MIT License. See the FindBANG.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +####################################################################### +# Parses a .cnbin file produced by cncc and reports statistics about the file. + + +file(READ ${input_file} file_text) + +if (NOT "${file_text}" STREQUAL "") + + string(REPLACE ";" "\\;" file_text ${file_text}) + string(REPLACE "\ncode" ";code" file_text ${file_text}) + + list(LENGTH file_text len) + + foreach(line ${file_text}) + + # Only look at "code { }" blocks. + if(line MATCHES "^code") + + # Break into individual lines. + string(REGEX REPLACE "\n" ";" line ${line}) + + foreach(entry ${line}) + + # Extract kernel names. + if (${entry} MATCHES "[^g]name = ([^ ]+)") + set(entry "${CMAKE_MATCH_1}") + + # Check to see if the kernel name starts with "_" + set(skip FALSE) + # if (${entry} MATCHES "^_") + # Skip the rest of this block. + # message("Skipping ${entry}") + # set(skip TRUE) + # else () + message("Kernel: ${entry}") + # endif () + + endif() + + # Skip the rest of the block if necessary + if(NOT skip) + + # Registers + if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Registers: ${entry}") + endif() + + # Local memory + if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Local: ${entry}") + endif() + + # Shared memory + if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)") + set(entry "${CMAKE_MATCH_3}") + message("Shared: ${entry}") + endif() + + if (${entry} MATCHES "^}") + message("") + endif() + + endif() + + + endforeach() + + endif() + + endforeach() + +else() + # message("FOUND NO DEPENDS") +endif() + + diff --git a/cmake/FindBANG/run_cncc.cmake b/cmake/FindBANG/run_cncc.cmake new file mode 100755 index 00000000..62c95284 --- /dev/null +++ b/cmake/FindBANG/run_cncc.cmake @@ -0,0 +1,200 @@ +# This code is licensed under the MIT License. See the FindBANG.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +########################################################################## +# This file runs the cncc commands to produce the desired output file along with +# the dependency file needed by CMake to compute dependencies. In addition the +# file checks the output of each command and if the command fails it deletes the +# output files. + +# Input variables +# +# verbose:BOOL=<> OFF: Be as quiet as possible (default) +# ON : Describe each step +# +# build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or +# RelWithDebInfo, but it should match one of the +# entries in BANG_HOST_FLAGS. This is the build +# configuration used when compiling the code. If +# blank or unspecified Debug is assumed as this is +# what CMake does. +# +# generated_file:STRING=<> File to generate. This argument must be passed in. +# +# generated_cnbin_file:STRING=<> File to generate. This argument must be passed +# in if build_cnbin is true. + +if(NOT generated_file) + message(FATAL_ERROR "You must specify generated_file on the command line") +endif() + +# Set these up as variables to make reading the generated file easier +set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path +set(source_file "@source_file@") # path +set(CNCC_generated_dependency_file "@CNCC_generated_dependency_file@") # path +set(cmake_dependency_file "@cmake_dependency_file@") # path +set(BANG_make2cmake "@BANG_make2cmake@") # path +set(BANG_parse_cnbin "@BANG_parse_cnbin@") # path +set(build_cnbin @build_cnbin@) # bool +set(BANG_HOST_COMPILER "@BANG_HOST_COMPILER@") # path +# We won't actually use these variables for now, but we need to set this, in +# order to force this file to be run again if it changes. +set(generated_file_path "@generated_file_path@") # path +set(generated_file_internal "@generated_file@") # path +set(generated_cnbin_file_internal "@generated_cnbin_file@") # path + +set(BANG_CNCC_EXECUTABLE "@BANG_CNCC_EXECUTABLE@") # path +set(BANG_CNCC_FLAGS @BANG_CNCC_FLAGS@ ;; @BANG_WRAP_OPTION_CNCC_FLAGS@) # list +@BANG_CNCC_FLAGS_CONFIG@ +set(cncc_flags @cncc_flags@) # list +set(BANG_CNCC_INCLUDE_ARGS "@BANG_CNCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly). +set(format_flag "@format_flag@") # string +set(bang_language_flag @bang_language_flag@) # list + +if(build_cnbin AND NOT generated_cnbin_file) + message(FATAL_ERROR "You must specify generated_cnbin_file on the command line") +endif() + +# This is the list of host compilation flags. It C or CXX should already have +# been chosen by FindBANG.cmake. +@BANG_HOST_FLAGS@ + +# Take the compiler flags and package them up to be sent to the compiler via -Xcompiler +set(cncc_host_compiler_flags "") +# If we weren't given a build_configuration, use Debug. +if(NOT build_configuration) + set(build_configuration Debug) +endif() +string(TOUPPER "${build_configuration}" build_configuration) +#message("BANG_CNCC_HOST_COMPILER_FLAGS = ${BANG_CNCC_HOST_COMPILER_FLAGS}") +foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}}) + # Extra quotes are added around each flag to help cncc parse out flags with spaces. + set(cncc_host_compiler_flags ${cncc_host_compiler_flags} ${flag}) +endforeach() +# message("cncc_host_compiler_flags = ${cncc_host_compiler_flags}") +# Add the build specific configuration flags +list(APPEND BANG_CNCC_FLAGS ${BANG_CNCC_FLAGS_${build_configuration}}) + +# Remove the duplicated flags and including +list(REMOVE_DUPLICATES BANG_CNCC_FLAGS) +list(REMOVE_DUPLICATES BANG_CNCC_INCLUDE_ARGS) + +# bang_execute_process - Executes a command with optional command echo and status message. +# +# status - Status message to print if verbose is true +# command - COMMAND argument from the usual execute_process argument structure +# ARGN - Remaining arguments are the command with arguments +# +# BANG_result - return value from running the command +# +# Make this a macro instead of a function, so that things like RESULT_VARIABLE +# and other return variables are present after executing the process. +macro(bang_execute_process status command) + set(_command ${command}) + if(NOT "x${_command}" STREQUAL "xCOMMAND") + message(FATAL_ERROR "Malformed call to bang_execute_process. Missing COMMAND as second argument. (command = ${command})") + endif() + if(verbose) + execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status}) + # Now we need to build up our command string. We are accounting for quotes + # and spaces, anything else is left up to the user to fix if they want to + # copy and paste a runnable command line. + set(bang_execute_process_string) + foreach(arg ${ARGN}) + # If there are quotes, excape them, so they come through. + string(REPLACE "\"" "\\\"" arg ${arg}) + # Args with spaces need quotes around them to get them to be parsed as a single argument. + if(arg MATCHES " ") + list(APPEND bang_execute_process_string "\"${arg}\"") + else() + list(APPEND bang_execute_process_string ${arg}) + endif() + endforeach() + # Echo the command + execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${bang_execute_process_string}) + endif() + # Run the command + execute_process(COMMAND ${ARGN} RESULT_VARIABLE BANG_result ) +endmacro() + +# Delete the target file +bang_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + +# cncc ignore host flags +set(cncc_host_compiler_flags "") + +# Generate the code +bang_execute_process( + "Generating ${generated_file}" + COMMAND "${BANG_CNCC_EXECUTABLE}" + "${source_file}" + ${bang_language_flag} + ${format_flag} -o "${generated_file}" + ${cncc_flags} + ${cncc_host_compiler_flags} + ${BANG_CNCC_FLAGS} + -DCNCC + ${BANG_CNCC_INCLUDE_ARGS} + ) + +if(BANG_result) + # Since cncc can sometimes leave half done files make sure that we delete the output file. + bang_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + message(FATAL_ERROR "Error generating file ${generated_file}") +else() + message(VERBOSE "Generated ${generated_file} successfully.") +endif() + +# Cnbin resource report commands. +if( build_cnbin ) + # Run with -cnbin to produce resource usage report. + bang_execute_process( + "Generating ${generated_cnbin_file}" + COMMAND "${BANG_CNCC_EXECUTABLE}" + "${source_file}" + ${BANG_CNCC_FLAGS} + ${cncc_flags} + ${cncc_host_compiler_flags} + -DCNCC + -cnbin + -o "${generated_cnbin_file}" + ${BANG_CNCC_INCLUDE_ARGS} + ) + + # Execute the parser script. + bang_execute_process( + "Executing the parser script" + COMMAND "${CMAKE_COMMAND}" + -D "input_file:STRING=${generated_cnbin_file}" + -P "${BANG_parse_cnbin}" + ) + +endif() diff --git a/imperative/python/megengine/functional/tensor.py b/imperative/python/megengine/functional/tensor.py index a0a08db3..040a4981 100755 --- a/imperative/python/megengine/functional/tensor.py +++ b/imperative/python/megengine/functional/tensor.py @@ -98,18 +98,27 @@ def eye(N, M=None, *, dtype="float32", device: Optional[CompNode] = None) -> Ten return result -def full(shape, value, dtype="float32", device=None) -> Tensor: +def full( + shape: Union[int, tuple, list], + value: Union[bool, int, float, Tensor], + dtype=None, + device=None, +) -> Tensor: r"""Creates a tensor of shape ``shape`` filled with ``value``. Args: - shape: a list, tuple or integer defining the shape of the output tensor. - value: the value to fill the output tensor with. - dtype: the desired data type of the output tensor. Default: ``float32``. - device: the desired device of the output tensor. Default: if ``None``, - use the default device (see :func:`~.megengine.get_default_device`). + shape: output tensor shape. + value: fill value. + dtype: output tensor data type. If ``dtype`` is ``None``, the output tensor + data type must be inferred from ``value``. If the value is an ``int``, + the output tensor data type must be the default integer data type. If the + value is a ``float``, the output tensor data type must be the default + floating-point data type. If the value is a ``bool``, the output tensor + must have boolean data type. Default: ``None``. + device: device on which to place the created tensor. Default: ``None``. Returns: - output tensor. + a tensor where every element is equal to ``value``. Examples: diff --git a/imperative/python/test/unit/functional/test_tensor.py b/imperative/python/test/unit/functional/test_tensor.py index aa609dcd..3f014325 100644 --- a/imperative/python/test/unit/functional/test_tensor.py +++ b/imperative/python/test/unit/functional/test_tensor.py @@ -41,6 +41,14 @@ def test_eye(): ) +def test_full(): + shape = (2, 3) + values = [True, 4, 5.0] + for value in values: + np.testing.assert_allclose(F.full(shape, value).numpy(), np.full(shape, value)) + assert F.full(shape, value).dtype == tensor(value).dtype + + @pytest.mark.parametrize("is_varnode", [True, False]) def test_concat(is_varnode): if is_varnode: