From d9605fec4b320e4aa38d399ffc6ef3b57fe876af Mon Sep 17 00:00:00 2001 From: Sam Parker Date: Tue, 31 Jan 2017 14:35:01 +0000 Subject: [PATCH] [ARM] Avoid using ARM instructions in Thumb mode The Requires class overrides the target requirements of an instruction, rather than adding to them, so all ARM instructions need to include the IsARM predicate when they have overwitten requirements. This caused the swp and swpb instructions to be allowed in thumb mode assembly, and the ARM encoding of CDP to be selected in codegen (which is different for conditional instructions). Differential Revision: https://reviews.llvm.org/D29283 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293634 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELFObjectFile.h | 4 +- include/llvm/Object/ObjectFile.h | 2 - lib/Target/ARM/ARMInstrInfo.td | 25 ++--- test/CodeGen/ARM/2009-05-18-InlineAsmMem.ll | 1 - test/CodeGen/ARM/intrinsics-coprocessor.ll | 1 - test/CodeGen/Thumb2/intrinsics-coprocessor.ll | 93 +++++++++++++++++++ test/MC/ARM/thumb2-diagnostics.s | 6 ++ 7 files changed, 114 insertions(+), 18 deletions(-) create mode 100644 test/CodeGen/Thumb2/intrinsics-coprocessor.ll diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index f9fdcac8c55..64b1921143c 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -74,9 +74,9 @@ public: SubtargetFeatures getFeatures() const override; - SubtargetFeatures getMIPSFeatures() const override; + SubtargetFeatures getMIPSFeatures() const; - SubtargetFeatures getARMFeatures() const override; + SubtargetFeatures getARMFeatures() const; void setARMSubArch(Triple &TheTriple) const override; }; diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index b4251193cd1..b689dc2ac03 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -267,8 +267,6 @@ public: virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; virtual SubtargetFeatures getFeatures() const = 0; - virtual SubtargetFeatures getMIPSFeatures() const { return SubtargetFeatures(); } - virtual SubtargetFeatures getARMFeatures() const { return SubtargetFeatures(); } virtual void setARMSubArch(Triple &TheTriple) const { } /// Returns platform-specific object flags, if any. diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index c47393990e9..d67af094f4d 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -4831,14 +4831,15 @@ let AddedComplexity = 8 in { def : ARMPat<(atomic_store_release_32 addr_offset_none:$addr, GPR:$val), (STL GPR:$val, addr_offset_none:$addr)>; } -// SWP/SWPB are deprecated in V6/V7. +// SWP/SWPB are deprecated in V6/V7 and optional in v7VE. +// FIXME Use InstAlias to generate LDREX/STREX pairs instead. let mayLoad = 1, mayStore = 1 in { def SWP : AIswp<0, (outs GPRnopc:$Rt), (ins GPRnopc:$Rt2, addr_offset_none:$addr), "swp", []>, - Requires<[PreV8]>; + Requires<[IsARM,PreV8]>; def SWPB: AIswp<1, (outs GPRnopc:$Rt), (ins GPRnopc:$Rt2, addr_offset_none:$addr), "swpb", []>, - Requires<[PreV8]>; + Requires<[IsARM,PreV8]>; } //===----------------------------------------------------------------------===// @@ -4850,7 +4851,7 @@ def CDP : ABI<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1, NoItinerary, "cdp", "\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]>, - Requires<[PreV8]> { + Requires<[IsARM,PreV8]> { bits<4> opc1; bits<4> CRn; bits<4> CRd; @@ -4872,7 +4873,7 @@ def CDP2 : ABXI<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1, NoItinerary, "cdp2\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp2 imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]>, - Requires<[PreV8]> { + Requires<[IsARM,PreV8]> { let Inst{31-28} = 0b1111; bits<4> opc1; bits<4> CRn; @@ -5048,13 +5049,13 @@ multiclass LdSt2Cop pattern> { defm LDC : LdStCop <1, 0, "ldc", [(int_arm_ldc imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm LDCL : LdStCop <1, 1, "ldcl", [(int_arm_ldcl imm:$cop, imm:$CRd, addrmode5:$addr)]>; -defm LDC2 : LdSt2Cop<1, 0, "ldc2", [(int_arm_ldc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8]>; -defm LDC2L : LdSt2Cop<1, 1, "ldc2l", [(int_arm_ldc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8]>; +defm LDC2 : LdSt2Cop<1, 0, "ldc2", [(int_arm_ldc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; +defm LDC2L : LdSt2Cop<1, 1, "ldc2l", [(int_arm_ldc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; defm STC : LdStCop <0, 0, "stc", [(int_arm_stc imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm STCL : LdStCop <0, 1, "stcl", [(int_arm_stcl imm:$cop, imm:$CRd, addrmode5:$addr)]>; -defm STC2 : LdSt2Cop<0, 0, "stc2", [(int_arm_stc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8]>; -defm STC2L : LdSt2Cop<0, 1, "stc2l", [(int_arm_stc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8]>; +defm STC2 : LdSt2Cop<0, 0, "stc2", [(int_arm_stc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; +defm STC2L : LdSt2Cop<0, 1, "stc2l", [(int_arm_stc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>; //===----------------------------------------------------------------------===// // Move between coprocessor and ARM core register. @@ -5132,7 +5133,7 @@ def MCR2 : MovRCopro2<"mcr2", 0 /* from ARM core register to coprocessor */, c_imm:$CRm, imm0_7:$opc2), [(int_arm_mcr2 imm:$cop, imm:$opc1, GPR:$Rt, imm:$CRn, imm:$CRm, imm:$opc2)]>, - Requires<[PreV8]>; + Requires<[IsARM,PreV8]>; def : ARMInstAlias<"mcr2 $cop, $opc1, $Rt, $CRn, $CRm", (MCR2 p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, 0)>; @@ -5140,7 +5141,7 @@ def MRC2 : MovRCopro2<"mrc2", 1 /* from coprocessor to ARM core register */, (outs GPRwithAPSR:$Rt), (ins p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), []>, - Requires<[PreV8]>; + Requires<[IsARM,PreV8]>; def : ARMInstAlias<"mrc2 $cop, $opc1, $Rt, $CRn, $CRm", (MRC2 GPRwithAPSR:$Rt, p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, 0)>; @@ -5183,7 +5184,7 @@ class MovRRCopro2 pattern = []> : ABXI<0b1100, oops, iops, NoItinerary, !strconcat(opc, "\t$cop, $opc1, $Rt, $Rt2, $CRm"), pattern>, - Requires<[PreV8]> { + Requires<[IsARM,PreV8]> { let Inst{31-28} = 0b1111; let Inst{23-21} = 0b010; let Inst{20} = direction; diff --git a/test/CodeGen/ARM/2009-05-18-InlineAsmMem.ll b/test/CodeGen/ARM/2009-05-18-InlineAsmMem.ll index 5d59fc64d92..e5c2fb4d67a 100644 --- a/test/CodeGen/ARM/2009-05-18-InlineAsmMem.ll +++ b/test/CodeGen/ARM/2009-05-18-InlineAsmMem.ll @@ -1,5 +1,4 @@ ; RUN: llc -mtriple=arm-eabi %s -o - | FileCheck %s -; RUN: llc -mtriple=thumb-eabi %s -o - | FileCheck %s ; PR4091 define void @foo(i32 %i, i32* %p) nounwind { diff --git a/test/CodeGen/ARM/intrinsics-coprocessor.ll b/test/CodeGen/ARM/intrinsics-coprocessor.ll index 8fea49b39fb..5352471238f 100644 --- a/test/CodeGen/ARM/intrinsics-coprocessor.ll +++ b/test/CodeGen/ARM/intrinsics-coprocessor.ll @@ -1,5 +1,4 @@ ; RUN: llc < %s -mtriple=armv7-eabi -mcpu=cortex-a8 | FileCheck %s -; RUN: llc < %s -march=thumb -mtriple=thumbv7-eabi -mcpu=cortex-a8 | FileCheck %s define void @coproc(i8* %i) nounwind { entry: diff --git a/test/CodeGen/Thumb2/intrinsics-coprocessor.ll b/test/CodeGen/Thumb2/intrinsics-coprocessor.ll new file mode 100644 index 00000000000..248ec223a61 --- /dev/null +++ b/test/CodeGen/Thumb2/intrinsics-coprocessor.ll @@ -0,0 +1,93 @@ +; RUN: llc < %s -march=thumb -mtriple=thumbv7-eabi -mcpu=cortex-a8 -show-mc-encoding | FileCheck %s +define void @coproc(i8* %i) nounwind { +entry: + ; CHECK: mrc p7, #1, r{{[0-9]+}}, c1, c1, #4 + %0 = tail call i32 @llvm.arm.mrc(i32 7, i32 1, i32 1, i32 1, i32 4) nounwind + ; CHECK: mcr p7, #1, r{{[0-9]+}}, c1, c1, #4 + tail call void @llvm.arm.mcr(i32 7, i32 1, i32 %0, i32 1, i32 1, i32 4) nounwind + ; CHECK: mrc2 p7, #1, r{{[0-9]+}}, c1, c1, #4 + %1 = tail call i32 @llvm.arm.mrc2(i32 7, i32 1, i32 1, i32 1, i32 4) nounwind + ; CHECK: mcr2 p7, #1, r{{[0-9]+}}, c1, c1, #4 + tail call void @llvm.arm.mcr2(i32 7, i32 1, i32 %1, i32 1, i32 1, i32 4) nounwind + ; CHECK: mcrr p7, #1, r{{[0-9]+}}, r{{[0-9]+}}, c1 + tail call void @llvm.arm.mcrr(i32 7, i32 1, i32 %0, i32 %1, i32 1) nounwind + ; CHECK: mcrr2 p7, #1, r{{[0-9]+}}, r{{[0-9]+}}, c1 + tail call void @llvm.arm.mcrr2(i32 7, i32 1, i32 %0, i32 %1, i32 1) nounwind + ; CHECK: cdp p7, #3, c1, c1, c1, #5 + tail call void @llvm.arm.cdp(i32 7, i32 3, i32 1, i32 1, i32 1, i32 5) nounwind + ; CHECK: cdp2 p7, #3, c1, c1, c1, #5 + tail call void @llvm.arm.cdp2(i32 7, i32 3, i32 1, i32 1, i32 1, i32 5) nounwind + ; CHECK: ldc p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.ldc(i32 7, i32 3, i8* %i) nounwind + ; CHECK: ldcl p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.ldcl(i32 7, i32 3, i8* %i) nounwind + ; CHECK: ldc2 p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.ldc2(i32 7, i32 3, i8* %i) nounwind + ; CHECK: ldc2l p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.ldc2l(i32 7, i32 3, i8* %i) nounwind + ; CHECK: stc p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.stc(i32 7, i32 3, i8* %i) nounwind + ; CHECK: stcl p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.stcl(i32 7, i32 3, i8* %i) nounwind + ; CHECK: stc2 p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.stc2(i32 7, i32 3, i8* %i) nounwind + ; CHECK: stc2l p7, c3, [r{{[0-9]+}}] + tail call void @llvm.arm.stc2l(i32 7, i32 3, i8* %i) nounwind + ; CHECK: mrrc p1, #2, r{{[0-9]+}}, r{{[0-9]+}}, c3 + %2 = tail call { i32, i32 } @llvm.arm.mrrc(i32 1, i32 2, i32 3) nounwind + ; CHECK: mrrc2 p1, #2, r{{[0-9]+}}, r{{[0-9]+}}, c3 + %3 = tail call { i32, i32 } @llvm.arm.mrrc2(i32 1, i32 2, i32 3) nounwind + ret void +} + +define hidden void @cond_cdp(i32 %a) { +; CHECK-LABEL: cond_cdp: +entry: + %tobool = icmp eq i32 %a, 0 + br i1 %tobool, label %if.end, label %if.then + +if.then: +; CHECK: it ne +; CHECK: cdpne p15, #0, c0, c0, c0, #0 @ encoding: [0x00,0xee,0x00,0x0f] + tail call void @llvm.arm.cdp(i32 15, i32 0, i32 0, i32 0, i32 0, i32 0) + br label %if.end + +if.end: + ret void +} + +declare void @llvm.arm.ldc(i32, i32, i8*) nounwind + +declare void @llvm.arm.ldcl(i32, i32, i8*) nounwind + +declare void @llvm.arm.ldc2(i32, i32, i8*) nounwind + +declare void @llvm.arm.ldc2l(i32, i32, i8*) nounwind + +declare void @llvm.arm.stc(i32, i32, i8*) nounwind + +declare void @llvm.arm.stcl(i32, i32, i8*) nounwind + +declare void @llvm.arm.stc2(i32, i32, i8*) nounwind + +declare void @llvm.arm.stc2l(i32, i32, i8*) nounwind + +declare void @llvm.arm.cdp2(i32, i32, i32, i32, i32, i32) nounwind + +declare void @llvm.arm.cdp(i32, i32, i32, i32, i32, i32) nounwind + +declare void @llvm.arm.mcrr2(i32, i32, i32, i32, i32) nounwind + +declare void @llvm.arm.mcrr(i32, i32, i32, i32, i32) nounwind + +declare void @llvm.arm.mcr2(i32, i32, i32, i32, i32, i32) nounwind + +declare i32 @llvm.arm.mrc2(i32, i32, i32, i32, i32) nounwind + +declare void @llvm.arm.mcr(i32, i32, i32, i32, i32, i32) nounwind + +declare i32 @llvm.arm.mrc(i32, i32, i32, i32, i32) nounwind + +declare { i32, i32 } @llvm.arm.mrrc(i32, i32, i32) nounwind + +declare { i32, i32 } @llvm.arm.mrrc2(i32, i32, i32) nounwind diff --git a/test/MC/ARM/thumb2-diagnostics.s b/test/MC/ARM/thumb2-diagnostics.s index 38cc74dee56..96ba1799ae9 100644 --- a/test/MC/ARM/thumb2-diagnostics.s +++ b/test/MC/ARM/thumb2-diagnostics.s @@ -117,4 +117,10 @@ foo2: @ CHECK-ERRORS: error: invalid operand for instruction @ CHECK-ERRORS: error: instruction requires: arm-mode @ CHECK-ERRORS: error: immediate value expected for vector index +@ CHECK-ERRORS: error: instruction requires: arm-mode + + @ SWP(B) is an ARM-only instruction + swp r0, r1, [r2] + swpb r3, r4, [r5] +@ CHECK-ERRORS: error: instruction requires: arm-mode @ CHECK-ERRORS: error: instruction requires: arm-mode -- 2.50.1