# BiShengIR Project.

cmake_minimum_required(VERSION 3.28.0)

project(bishengir)



# bishengir-target-spec-tblgen related target has ninja version requirement

if(CMAKE_GENERATOR MATCHES "Ninja")

  execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} --version

    OUTPUT_VARIABLE NINJA_VERSION

    OUTPUT_STRIP_TRAILING_WHITESPACE)

  set(NINJA_VERSION ${NINJA_VERSION} CACHE STRING "Ninja version number" FORCE)

  if("${NINJA_VERSION}" VERSION_LESS "1.12.0")

    message(FATAL_ERROR "Ninja version too old, need at least 1.12.0")

  endif()

endif()



# TODO : release different version of ascendnpu ir and remove the macro

option(LLVM_MAJOR_VERSION_21_COMPATIBLE "NPUIR build with LLVM 21 or later" OFF)

if(LLVM_MAJOR_VERSION_21_COMPATIBLE)

  message(STATUS "Building with LLVM 21 or later")

  add_definitions(-D__LLVM_MAJOR_VERSION_21_COMPATIBLE__)

endif()



# Some compatibility changes for LLVM 21 are also needed on LLVM 22.

# Therefore __LLVM_MAJOR_VERSION_21_COMPATIBLE__ would be enabled too.

option(LLVM_MAJOR_VERSION_22_COMPATIBLE "NPUIR build with LLVM 22" OFF)

if(LLVM_MAJOR_VERSION_22_COMPATIBLE)

  message(STATUS "Building with LLVM 22 or later")

  add_definitions(-D__LLVM_MAJOR_VERSION_21_COMPATIBLE__)

  add_definitions(-D__LLVM_MAJOR_VERSION_22_COMPATIBLE__)

endif()



option(LLVM_MAJOR_VERSION_20_COMPATIBLE "NPUIR build with LLVM 20" OFF)

if(LLVM_MAJOR_VERSION_20_COMPATIBLE)

  message(STATUS "Building with LLVM 20 or later")

  add_definitions(-D__LLVM_MAJOR_VERSION_20_COMPATIBLE__)

endif()

# -------------------------------------------------------------------------------

# Handle Option

# -------------------------------------------------------------------------------



# The BISHENGIR_PUBLISH option is used to control behaviors that is unpublished.

option(BISHENGIR_PUBLISH "BiShengIR is publish" OFF)



option(BISHENGIR_BUILD_EXAMPLES

  "Build the BiShengIR example programs. If OFF, just generate build targets." OFF)



# Build the Torch-MLIR conversion when "torch-mlir" project is enabled.

if("torch-mlir" IN_LIST LLVM_EXTERNAL_PROJECTS)

  set(BISHENGIR_ENABLE_TORCH_CONVERSIONS 1)

else()

  set(BISHENGIR_ENABLE_TORCH_CONVERSIONS 0)

endif()



# The BISHENGIR_BUILD_TEMPLATE option is used to build BiShengIR template.

option(BISHENGIR_BUILD_TEMPLATE

  "Build the BiShengIR template." OFF)



# The BISHENGIR_BUILD_STANDALONE_IR_ONLY option is used to only build IR definitions.

option(BISHENGIR_BUILD_STANDALONE_IR_ONLY

  "Experimental feature. If set, only build IR definitions." OFF)



# The BISHENGIR_ENABLE_A5_UNPUBLISHED_FEATURES option is used to enable A5 features that are currently unpublished.

option(BISHENGIR_ENABLE_A5_UNPUBLISHED_FEATURES

  "Experimental feature. If set, enable A5 unpublished features." OFF)



# Only enable execution engine if the native target is available.

if (${LLVM_NATIVE_ARCH} IN_LIST LLVM_TARGETS_TO_BUILD)

  set(MLIR_ENABLE_EXECUTION_ENGINE 1)

else()

  set(MLIR_ENABLE_EXECUTION_ENGINE 0)

endif()



if(BISHENGIR_ENABLE_TORCH_CONVERSIONS AND BUILD_SHARED_LIBS)

  message(FATAL_ERROR "torch-mlir can't build with sharded libs.")

endif()



set(LLVM_LIT_ARGS

    "-sv"

    CACHE STRING "lit default options")



find_program(

  BISHENG_COMPILER_EXECUTABLE

  NAMES bisheng

  PATHS $ENV{PATH})



# -------------------------------------------------------------------------------

# Setup variables and includes

# -------------------------------------------------------------------------------



set(MLIR_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../mlir)

set(MLIR_MAIN_INCLUDE_DIR ${MLIR_MAIN_SRC_DIR}/include)

set(MLIR_CMAKE_DIR ${MLIR_MAIN_SRC_DIR}/cmake/modules)

set(MLIR_INCLUDE_DIR ${LLVM_BINARY_DIR}/tools/mlir/include)

set(MLIR_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})



set(BISHENGIR_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bishengir)

set(BISHENGIR_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})

set(BISHENGIR_MAIN_INCLUDE_DIR ${BISHENGIR_SRC_DIR}/include)

set(BISHENGIR_INCLUDE_DIR ${BISHENGIR_BINARY_DIR}/bishengir/include)



# Make sure that our source directory is on the current cmake module path so

# that we can include cmake files from this directory.

list(INSERT CMAKE_MODULE_PATH 0

  "${BISHENGIR_SRC_DIR}/cmake/modules"

  "${LLVM_COMMON_CMAKE_UTILS}/Modules"

)



list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}")

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")



include(AddLLVM)

include(TableGen)

include(AddMLIR)

include(AddMLIRPython)

include(AddBiShengIR)

include(BiShengIRVersion)



configure_file(

  ${BISHENGIR_MAIN_INCLUDE_DIR}/bishengir/Config/bishengir-config.h.cmake

  ${BISHENGIR_INCLUDE_DIR}/bishengir/Config/bishengir-config.h)



include_directories(${LLVM_INCLUDE_DIRS})

include_directories(${MLIR_MAIN_INCLUDE_DIR})

include_directories(${MLIR_INCLUDE_DIR})

include_directories(${BISHENGIR_MAIN_INCLUDE_DIR})

include_directories(${BISHENGIR_INCLUDE_DIR})



# Adding tblgen tools here as calling add_tablegen sets some variables in

# PARENT_SCOPE which gets lost if that folder is included from another directory

# like tools

add_subdirectory(bishengir/tools/bishengir-target-spec-tblgen)

set(BISHENGIR_TARGET_SPEC_TABLEGEN_EXE

    "${BISHENGIR_TARGET_SPEC_TABLEGEN_EXE}"

    CACHE INTERNAL "")

set(BISHENGIR_TARGET_SPEC_TABLEGEN_TARGET

    "${BISHENGIR_TARGET_SPEC_TABLEGEN_TARGET}"

    CACHE INTERNAL "")



add_subdirectory(bishengir/tools/bishengir-options-tblgen)

set(BISHENGIR_OPTIONS_TABLEGEN_EXE

    "${BISHENGIR_OPTIONS_TABLEGEN_EXE}"

    CACHE INTERNAL "")

set(BISHENGIR_OPTIONS_TABLEGEN_TARGET

    "${BISHENGIR_OPTIONS_TABLEGEN_TARGET}"

    CACHE INTERNAL "")



if(BISHENGIR_ENABLE_TORCH_CONVERSIONS)

  set(TORCH_MAIN_SRC_DIR ${LLVM_EXTERNAL_TORCH_MLIR_SOURCE_DIR})

  set(TORCH_MLIR_INCLUDE_DIRS ${TORCH_MAIN_SRC_DIR}/include)

  set(TORCH_TABLEGEN_OUTPUT_DIR ${LLVM_BINARY_DIR}/tools/torch-mlir/include)

  include_directories(${TORCH_TABLEGEN_OUTPUT_DIR})

  include_directories(${TORCH_MLIR_INCLUDE_DIRS})

endif()



if(MLIR_ENABLE_BINDINGS_PYTHON)

  include(MLIRDetectPythonEnv)

  mlir_configure_python_dev_packages()

endif()



if(BISHENGIR_BUILD_EXAMPLES)

  set(ASCEND_HOME_PATH $ENV{ASCEND_HOME_PATH}

        CACHE STRING "Ascend CANN install path")

  if(${ASCEND_HOME_PATH} STREQUAL "")

    message(FATAL_ERROR "Ascend CANN package is required for building example!")

  endif()

  add_subdirectory(bishengir/test/Integration)

endif()



# Declare target before adding `include/bishengir`

add_custom_target(bishengir-doc)

set_target_properties(bishengir-doc PROPERTIES FOLDER "BiShengIR/Docs")



# Custom target to install all bishengir products for release

add_custom_target(bishengir-publish-products)

set_target_properties(bishengir-publish-products PROPERTIES FOLDER "BiShengIR/Tools")

add_llvm_install_targets(install-bishengir-publish-products

                         COMPONENT bishengir-publish-products)



# Check format for BISHENGIR_VERSION

foreach(part MAJOR MINOR PATCHLEVEL)

  if(NOT BISHENGIR_VERSION_${part} MATCHES "^[0-9]+$")

    message(FATAL_ERROR 

      "BISHENGIR_VERSION_${part} is invalid: '${BISHENGIR_VERSION_${part}}'. "

      "This part must contain only digits.")

  endif()

endforeach()

if(NOT "${BISHENGIR_VERSION_SUFFIX}" MATCHES "^[a-zA-Z0-9-]*$")

  message(FATAL_ERROR 

    "BISHENGIR_VERSION_SUFFIX is invalid: '${BISHENGIR_VERSION_SUFFIX}'. "

    "Suffix must only contain alphanumeric characters or hyphens.")

endif()

set(BISHENGIR_VERSION "${BISHENGIR_VERSION_MAJOR}.${BISHENGIR_VERSION_MINOR}.${BISHENGIR_VERSION_PATCHLEVEL}${BISHENGIR_VERSION_SUFFIX}")

string(TIMESTAMP BISHENGIR_BUILD_DATE "%Y-%m-%d")

message(STATUS "BISHENGIR version: ${BISHENGIR_VERSION}")

message(STATUS "BISHENGIR build date: ${BISHENGIR_BUILD_DATE}")



# Configure the Version.inc file.

configure_file(

  ${CMAKE_CURRENT_SOURCE_DIR}/bishengir/include/bishengir/Version/Version.inc.in

  ${CMAKE_CURRENT_BINARY_DIR}/bishengir/include/bishengir/Version/Version.inc)



add_subdirectory(bishengir/tools/bishengir-hfusion-ods-gen)

if (BISHENGIR_BUILD_STANDALONE_IR_ONLY)

  add_definitions(-DBISHENGIR_BUILD_STANDALONE_IR_ONLY)

  add_subdirectory(bishengir/include/bishengir/Interfaces)

  set(STANDALONE_IR_BUILD_DIALECT

  Annotation

  HACC

  HFusion

  HIVM

  MemRef

  MemRefExt

  Scope

  Symbol

  Tensor

  )

  foreach(d IN LISTS STANDALONE_IR_BUILD_DIALECT)

    add_subdirectory(bishengir/include/bishengir/Dialect/${d})

    add_subdirectory(bishengir/lib/Dialect/${d}/IR)

  endforeach()

  # TODO: Math and Utils should be added in STANDALONE_IR_BUILD_DIALECT

  add_subdirectory(bishengir/include/bishengir/Dialect/MathExt)

  add_subdirectory(bishengir/lib/Dialect/HIVM/Utils)

  add_subdirectory(bishengir/lib/Dialect/HACC/Transforms)

  add_subdirectory(bishengir/lib/Dialect/HACC/Utils)

  add_subdirectory(bishengir/lib/Dialect/Math)

  add_subdirectory(bishengir/lib/Dialect/Utils)

else()

  add_subdirectory(bishengir/include/bishengir)

  add_subdirectory(bishengir/lib)

endif()

add_subdirectory(bishengir/lib/CAPI)



if(MLIR_INCLUDE_TESTS)
  add_definitions(-DMLIR_INCLUDE_TESTS)
  add_subdirectory(bishengir/test)
  add_subdirectory(bishengir/unittests)
endif()


# TODO: Standalone build should support python binding

if(NOT BISHENGIR_BUILD_STANDALONE_IR_ONLY AND MLIR_ENABLE_BINDINGS_PYTHON)

  # If parent projects want to configure where to place the python packages,

  # respect that.

  if(NOT BISHENGIR_PYTHON_PACKAGES_DIR)

    set(BISHENGIR_PYTHON_PACKAGES_DIR

        "${CMAKE_CURRENT_BINARY_DIR}/bishengir/python_packages")

  endif()

  add_subdirectory(bishengir/python)

endif()



if(NOT BISHENGIR_BUILD_STANDALONE_IR_ONLY)

  add_subdirectory(bishengir/tools)

endif()



if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)

  install(

    DIRECTORY bishengir/include/bishengir

    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"

    COMPONENT bishengir-headers

    FILES_MATCHING

    PATTERN "*.def"

    PATTERN "*.h"

    PATTERN "*.inc"

    PATTERN "*.td"

    PATTERN "LICENSE.TXT")



  install(

    DIRECTORY ${BISHENGIR_BINARY_DIR}/bishengir/include/bishengir

    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"

    COMPONENT bishengir-headers

    FILES_MATCHING

    PATTERN "*.def"

    PATTERN "*.h"

    PATTERN "*.gen"

    PATTERN "*.inc"

    PATTERN "*.td"

    PATTERN "CMakeFiles" EXCLUDE

    PATTERN "config.h" EXCLUDE)



  if(NOT LLVM_ENABLE_IDE)

    add_llvm_install_targets(install-bishengir-headers DEPENDS

                             bishengir-headers COMPONENT bishengir-headers)

  endif()

endif()



set_property(GLOBAL PROPERTY BISHENGIR_LIBS "@BISHENGIR_LIBS@")

set_property(GLOBAL PROPERTY BISHENGIR_DIALECT_LIBS "@BISHENGIR_DIALECT_LIBS@")

set_property(GLOBAL PROPERTY BISHENGIR_CONVERSION_LIBS "@BISHENGIR_CONVERSION_LIBS@")

set_property(GLOBAL PROPERTY BISHENGIR_TRANSLATION_LIBS "@BISHENGIR_TRANSLATION_LIBS@")

set_property(GLOBAL PROPERTY BISHENGIR_EXTENSION_LIBS "@BISHENGIR_EXTENSION_LIBS@")