Gaël Jobin via llvm-dev
2016-Nov-09 09:53 UTC
[llvm-dev] Bad ARM instruction "sub.w sp, r7, #8" allowed by Clang
Hi all, I have a project with Android Studio using a Clang 3.9 for compilation (built from the source). For those who are not familiar with the NDK build system, when building JNI library through the ndk-build command, clang is used to generate assembly file (.s) and then "as" is called to generate object file (.o). With ndk r10e, all was working fine. Since ndk r13b, I got an error during the compilation. When building my project with -O0, it is still working. But building it with -O1 with ndk r13b, I got many messages like: Error: r13 not allowed here -- 'sub.w sp,r7,#8' I found out that under ndk r10e, the compilation was made in arm mode. Under ndk r13b, the compilation is made in thumb mode. So passing -mthumb with ndk r10e produce the same error. The generated instruction "sub.w sp,r7,#8" is illegal (A8.8.223 T2). When Rd equal to SP, it must use the "SUB (SP minus register)" synthax (A8.8.225 T2) which explicitly allows only SP as Rn (source). Using -mllvm -print-after-all, the bad t2SUBri instruction seems to appear right after the RegisterCoalescer pass. Looking at gas source code, the check is made correctly in "gas/config/tc-arm.c" inside functions do_t_add_sub_w()/do_t_add_sub(). This is the reason of the error above. Now, in the Clang side, inside "lib/Target/ARM/ARMInstrThumb2.td", we have the following: defm t2ADD : T2I_bin_ii12rs<0b000, "add", add, 1>; defm t2SUB : T2I_bin_ii12rs<0b101, "sub", sub>; T2I_bin_ii12rs is a multiclass which define t2SUBri, t2SUBri12, t2SUBrr and t2SUBrs. The problem is that the register class used for the destination register is always set to GPRnopc which include SP. As I don't now enough about TableGen to put a constraint like "if destination register is SP, only SP is allowed as a source register", I simply replaced destination register GPRnopc to tGPR for ri,ri12,rr and rs. Then I updated all alias (t2InstAlias) that use t2ADD{ri,ri12,rr,rs} and t2SUB{ri,ri12,rr,rs} by replacing GPRnopc by tGPR. This fix has allowed me to compile my project again without error !!! Given that it is the first time I mess with the ARM backend, what do you think of this fix? Did I miss something? As the fix is not complete (it does not support the "SUB (SP minus register)"), any idea how to implement this special instruction ? Thank you Regards, Gael
Tim Northover via llvm-dev
2016-Nov-09 14:55 UTC
[llvm-dev] Bad ARM instruction "sub.w sp, r7, #8" allowed by Clang
Hi Gael, On 9 November 2016 at 01:53, Gaël Jobin via llvm-dev <llvm-dev at lists.llvm.org> wrote:> Given that it is the first time I mess with the ARM backend, what do > you think of this fix?The analysis seems spot on, thanks for taking the time to look into this and work on a solution. We do have a better register class: "rGPR" only excludes SP and PC (tGPR is just the Thumb1 registers r0-r7).> Did I miss something? As the fix is not complete > (it does not support the "SUB (SP minus register)"), any idea how to > implement this special instruction ?They'll probably have to be separate instructions, "t2SUBspi" or something where Rn can only be SP. Analogous to tSUBspi that already exists. TableGen can't easily encode Rd != SP unless Rn == SP. Let me know if anything's still unclear. Tim.