diff --git a/CMakeLists.txt b/CMakeLists.txt index 40e1b723..aa7c229b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.10) project(NE10 C CXX ASM) @@ -113,9 +113,11 @@ if(ANDROID_PLATFORM) endif() #TODO: Fine tune pic and pie flag for executable, share library and static library. - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=${NDK_SYSROOT_PATH} -pie") - string(APPEND CMAKE_C_FLAGS " -isysroot ${NDK_ISYSROOT_PATH}") - add_definitions(-D__ANDROID_API__=${ANDROID_API_LEVEL}) + # If using NDK version older than 19 + if(NOT DEFINED ANDROID_NDK_MAJOR OR ANDROID_NDK_MAJOR VERSION_LESS "19") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=${NDK_SYSROOT_PATH} -pie") + string(APPEND CMAKE_C_FLAGS " -isysroot ${NDK_ISYSROOT_PATH}") + endif() # Adding cflags for armv7. Aarch64 does not need such flags. if(${NE10_TARGET_ARCH} STREQUAL "armv7") diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 4f158e9d..028f9d1c 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -77,6 +77,35 @@ if(IOS_PLATFORM) endfunction() endif(IOS_PLATFORM) +if(ANDROID_PLATFORM) + # Similar to ios, android ARM assembler(Clang) doesn't support GNU as(GAS)'s assembly + # However, ios use Mach-o format, while android use ELF format. + # So we need to convert the assembly file to natch ELF format with differnt conversion script based on gas2ios_convert.py + function(convert_gas gas_files android_files) + #message(STATUS "in convert_gas function:${${gas_files}}") + #TODO: Change naming to android instead of ios + foreach(gas_file ${${gas_files}}) + string(REGEX REPLACE + ".*\(NE10_.*\).neon.s" + "${NE10_BINARY_DIR}/modules/CMakeFiles/NE10.dir/\\1_android.neon.s" + android_file + ${gas_file}) + list(APPEND android_files_tmp ${android_file}) + + #call a script to convert each assembly file in GAS to Clang + add_custom_command( + OUTPUT ${android_file} + COMMAND ${NE10_SOURCE_DIR}/tools/gas2android_convert.py + ${gas_file} ${android_file} + DEPENDS ${gas_file} + ) + endforeach() + + #return value by setting the variable to PARENT_SCOPE + set(${android_files} ${android_files_tmp} PARENT_SCOPE) + endfunction() +endif(ANDROID_PLATFORM) + if(NE10_ENABLE_MATH) #enable NE10_init_math add_definitions(-DNE10_ENABLE_MATH) @@ -198,22 +227,30 @@ if(NE10_ENABLE_DSP) if("${NE10_TARGET_ARCH}" STREQUAL "armv7") if(IOS_PLATFORM) else() + set(NE10_DSP_GAS_TEMP + ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fir.neon.s + ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_iir.neon.s + ) + convert_gas(NE10_DSP_GAS_TEMP NE10_DSP_ANDROID_NEON_SRCS) # Add dsp NEON files. set(NE10_DSP_NEON_SRCS ${NE10_DSP_NEON_SRCS} - ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fir.neon.s - ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_iir.neon.s + ${NE10_DSP_ANDROID_NEON_SRCS} ) endif() endif() if(NE10_ASM_OPTIMIZATION) - set(NE10_DSP_NEON_SRCS - ${NE10_DSP_NEON_SRCS} + set(NE10_DSP_FFT_GAS_TEMP ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fft_float32.neon.s ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fft_int32.neon.s ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fft_int16.neon.s ) + convert_gas(NE10_DSP_FFT_GAS_TEMP NE10_DSP_ANDROID_NEON_SRCS) + set(NE10_DSP_NEON_SRCS + ${NE10_DSP_NEON_SRCS} + ${NE10_DSP_ANDROID_NEON_SRCS} + ) set(NE10_DSP_INTRINSIC_SRCS ${NE10_DSP_INTRINSIC_SRCS} ${PROJECT_SOURCE_DIR}/modules/dsp/NE10_fft_float32.neon.c @@ -277,9 +314,13 @@ if(NE10_ENABLE_IMGPROC) if("${NE10_TARGET_ARCH}" STREQUAL "armv7") # Add image processing NEON files. - set(NE10_IMGPROC_NEON_SRCS + set(NE10_IMGPROC_GAS_TEMP ${PROJECT_SOURCE_DIR}/modules/imgproc/NE10_rotate.neon.s ) + convert_gas(NE10_IMGPROC_GAS_TEMP NE10_ANDROID_IMG_TEMP) + set(NE10_IMGPROC_NEON_SRCS + ${NE10_ANDROID_IMG_TEMP} + ) endif() # Add image intrinsic NEON files. set(NE10_IMGPROC_INTRINSIC_SRCS diff --git a/tools/gas2android_convert.py b/tools/gas2android_convert.py new file mode 100755 index 00000000..c19c44e9 --- /dev/null +++ b/tools/gas2android_convert.py @@ -0,0 +1,318 @@ +#!/usr/bin/python3 +''' + Copyright 2013-16 ARM Limited and Contributors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of ARM Limited nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL ARM LIMITED AND CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''' + +'''convert GAS arm assembly to Clang's integrated-as''' +import re,sys,os + +''' parse .qn .dn .req directive for arm assembly + input is string list +''' +def parse_alias(inlines): + #the value name doesn't include .F32 suffix, but include [0], such as d0[0] + alias_exp = re.compile(r" *" + r"(?P[_a-zA-Z0-9]+)" + " +\.(req|qn|dn) +" + r"(?P[a-zA-Z0-9\[\]]+)" + ) + global_exp = re.compile(r"\.global") + #store aliases in different function in different dictionary + #use .global to label different function + alias_dics = [] + alias_dics.append({}) + func_count = 0 + for line in inlines: + if global_exp.search(line): + alias_dics.append({}) + func_count += 1 + result = alias_exp.search(line) + if result != None: + alias = result.group('alias') + value = result.group('value') + alias_dics[func_count][alias] = value + #print alias_dics + + #replace alias + func_count = 0 + line_result1 = [] + for line in inlines: + if global_exp.search(line): + func_count += 1 + for alias in alias_dics[func_count]: + alias_str = "\\b"+alias+"\\b" + alias_exp = re.compile(alias_str) + line = alias_exp.sub(alias_dics[func_count][alias], line) + line_result1.append(line) + + #remove .qn .dn .req line + line_result2 = [] + alias_exp = re.compile(r"\.(qn|dn|req|unreq)") + for line in line_result1: + if not alias_exp.search(line): + line_result2.append(line) + + return line_result2 + +''' parse .qn .dn .req directive for arm assembly + input is string list. + this is for fft module's new format: in the new format, + all aliases are defined at the begin of files and all functions + share one set of defines. +''' +def parse_alias_fft(inlines): + #the value name doesn't include .F32 suffix, but include [0], such as d0[0] + alias_exp = re.compile(r" *" + r"(?P[_a-zA-Z0-9]+)" + " +\.(req|qn|dn) +" + r"(?P[a-zA-Z0-9\[\]]+)" + ) + aliases = {} + for line in inlines: + result = alias_exp.search(line) + if result != None: + alias = result.group('alias') + value = result.group('value') + aliases[alias] = value + #print aliases + + #replace alias + line_result1 = [] + for line in inlines: + for alias in aliases: + alias_str = "\\b"+alias+"\\b" + alias_exp = re.compile(alias_str) + line = alias_exp.sub(aliases[alias], line) + line_result1.append(line) + + #remove .qn .dn .req line + line_result2 = [] + alias_exp = re.compile(r"\.(qn|dn|req|unreq)") + for line in line_result1: + if not alias_exp.search(line): + line_result2.append(line) + + return line_result2 + +'''add .F32 to some instructions for Clang's as doesn't support register with + datatype, such as VADD Q0.F32, Q1.F32, Q2.F32''' +def add_f32(inlines): + instructions = ['VADD', 'VSUB', 'VLD1', 'VLD2', 'VMUL', 'VMLA', 'VMLS', + 'VZIP', 'VST1', 'VST2', 'VPADD', 'VEXT', 'VREV64', + 'VDUP', 'VMOV'] + line_result = [] + for line in inlines: + for instruction in instructions: + instruction_exp = re.compile(instruction) + instruction_f32_exp = re.compile(instruction + "\\.[Ff]32") + #only add .F32 to instruction without .F32(or .f32) + if instruction_exp.search(line) and \ + not instruction_f32_exp.search(line): + line = instruction_exp.sub(instruction + ".F32", line) + line_result.append(line) + return line_result + +'''remove .end instruction''' +def remove_end(inlines): + end_exp = re.compile(r"\.end\b") + line_result = [] + for line in inlines: + if not end_exp.search(line): + line_result.append(line) + return line_result + +'''expan ldr rx, =label for Clang, this method has *not* been used in current +assembly convertion, Clang doesn't support this pseudo-instruction''' +def expan_ldr1(inlines): + #search ldr rx, =label + labels = [] + ldr_exp = re.compile(r"\s*LDR.*=" + r"(?P