问题
I have a native library for Android that has some files that include NEON assembly code. I've inherited this code from some other coder, and given my knowledge regarding NEON assembly coding (or any assembly, for that matter) is skimpy, to say the least. Anyhow, I've noticed the following problem: when I compile with 'ndk-build NDK_DEBUG=1', all is fine. When I compile for release, 'ndk-build NDK_DEBUG=0', the compiler optimizes away the assembly code. I've managed to work around the problem by hacking the ndk build scripts, and splitting my library into two, where one lib has all the assembly files in it - for this lib I set optimization to '-O0' in a very hacky way. So the question is: how can I specify an optimization level for a specific file? setting APP_OPTIM is done in Application.mk, that affects all the compiled files. So does the NDK_DEBUG flag.
EDIT: as per Alex's request, here's the Android.mk I ended up using, splitting the lib into two: one part with assembly code (and -O0), other part with regular C code (and -O2):
LOCAL_PATH := $(call my-dir)
# assembly_neon_code_here (neon) module - turn optimization off
include $(CLEAR_VARS)
LOCAL_MODULE := assembly_neon_code_here
LOCAL_SRC_FILES := assembly_neon_code_here.cpp
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_ARM_NEON := true
endif
LOCAL_CFLAGS := -O0
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
# main module
include $(CLEAR_VARS)
LOCAL_MODULE := complete_lib
LOCAL_SRC_FILES := regular_src1.cpp regular_src2.cpp regular_src3.cpp
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_ARM_NEON := true
endif
# allow logcat calls
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
LOCAL_SHARED_LIBRARIES := assembly_neon_code_here
include $(BUILD_SHARED_LIBRARY)
回答1:
GCC >= 4.4 seems to support #pragma GCC optimize
to change the optimization level mid-file, and also attribute optimize
to set it per function.
See http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Function-Specific-Option-Pragmas.html#Function-Specific-Option-Pragmas and http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Function-Attributes.html#Function-Attributes.
According to those links, putting #pragma GCC optimize ("O0")
at the top of the file causing the problem should do the trick.
回答2:
I don't know how to change the optimization level per-file, but doing so may harm your application's performance, so i wouldn't recommend it anway. I assume that the assembly code is in the form of inline assembly block, i.e. blocks of assembly coder interleaves with normal C or C++ code. It looks the following
asm {
.. assembly goes here, usually each line in double-quotes, often ending in \n\t
: ... input operands. Might not be present ...
: ... output operands. Might not be present ...
: ... clobber operands. Might not be present ...
}
The most likely reason why the compiler would remove an inline assembly block is if it contains no output operands, or if the output operands are all unused. You can avoid try by marking the inline assembly block as volatile
which tells the compiler not to mess with it. To do that, simply write volatile
after the asm
keyword.
Another thing that discourages the compiler from messing with inline assembly blocks is adding "memory" to their clobber list. This tells the compiler that the assembly is reading from or writing to arbitrary memory locations. And while you're at it, also add "cc" for good measure. This tells the compiler that the inline assembly messes with the condition-code register, i.e. that it executes test instructions which influence the behaviour of later conditional branch instructions.
In conclusion, try making all inline assembly blocks look like this
asm volatile {
.. whatever ...
: ... whatever ...
: ... whatever ...
: ... whatever ..., "cc", "memory"
}
Note that asm
may also be spelled __asm__
, and that volatile
may also be spelled __volatile__
.
来源:https://stackoverflow.com/questions/12663799/how-to-set-optimization-level-for-a-specific-file-in-android-ndk