diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -10080,7 +10080,8 @@ assert(LD->isUnindexed() && "Loads should be unindexed at this point."); if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && - !Subtarget->isThumb1Only() && LD->isVolatile()) { + !Subtarget->isThumb1Only() && LD->isVolatile() && + LD->getAlign() >= Subtarget->getDualLoadStoreAlignment()) { SDLoc dl(N); SDValue Result = DAG.getMemIntrinsicNode( ARMISD::LDRD, dl, DAG.getVTList({MVT::i32, MVT::i32, MVT::Other}), @@ -10137,7 +10138,8 @@ assert(ST->isUnindexed() && "Stores should be unindexed at this point."); if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && - !Subtarget->isThumb1Only() && ST->isVolatile()) { + !Subtarget->isThumb1Only() && ST->isVolatile() && + ST->getAlign() >= Subtarget->getDualLoadStoreAlignment()) { SDNode *N = Op.getNode(); SDLoc dl(N); diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h --- a/llvm/lib/Target/ARM/ARMSubtarget.h +++ b/llvm/lib/Target/ARM/ARMSubtarget.h @@ -494,6 +494,11 @@ /// function for this subtarget. Align getStackAlignment() const { return stackAlignment; } + // Returns the required alignment for LDRD/STRD instructions + Align getDualLoadStoreAlignment() const { + return Align(hasV7Ops() || allowsUnalignedMem() ? 4 : 8); + } + unsigned getMaxInterleaveFactor() const { return MaxInterleaveFactor; } unsigned getPartialUpdateClearance() const { return PartialUpdateClearance; } diff --git a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll b/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll --- a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll +++ b/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll @@ -1,47 +1,136 @@ ; RUN: llc -mtriple=armv5e-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV5TE,CHECK ; RUN: llc -mtriple=thumbv6t2-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-T2,CHECK ; RUN: llc -mtriple=armv4t-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV4T,CHECK +; RUN: llc -mtriple=armv7-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV7,CHECK +; RUN: llc -mtriple=armv6-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV6,CHECK +; RUN: llc -mtriple=armv6-arm-none-eabi -mattr=+strict-align %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV6-STRICT,CHECK @x = common dso_local global i64 0, align 8 @y = common dso_local global i64 0, align 8 +@x_unaligned = common dso_local global i64 0, align 1 +@y_unaligned = common dso_local global i64 0, align 1 + +@x_aligned_4 = common dso_local global i64 0, align 4 +@y_aligned_4 = common dso_local global i64 0, align 4 + define void @test() { entry: ; CHECK-LABEL: test: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x ; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y ; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x ; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #4] ; CHECK-ARMV4T-NEXT: str [[R0]], [[[ADDR1]], #4] ; CHECK-ARMV4T-NEXT: str [[R1]], [[[ADDR1]]] + +; CHECK-ARMV7: movw [[ADDR0:r[0-9]+]], :lower16:x +; CHECK-ARMV7-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y +; CHECK-ARMV7-NEXT: movt [[ADDR0]], :upper16:x +; CHECK-ARMV7-NEXT: movt [[ADDR1]], :upper16:y +; CHECK-ARMV7-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV7-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] %0 = load volatile i64, ptr @x, align 8 store volatile i64 %0, ptr @y, align 8 ret void } +define void @test_unaligned() { +entry: +; CHECK-LABEL: test_unaligned: + +; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] +; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] +; CHECK-ARMV5TE-NEXT: ldr [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV5TE-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #4] +; CHECK-ARMV5TE-NEXT: str [[R0]], [[[ADDR1]], #4] +; CHECK-ARMV5TE-NEXT: str [[R1]], [[[ADDR1]]] + +; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x_unaligned +; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y_unaligned +; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x_unaligned +; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y_unaligned +; CHECK-T2-NEXT: ldr [[R1]], [[[ADDR0]]] +; CHECK-T2-NEXT: ldr [[R0]], [[[ADDR0]], #4] +; CHECK-T2-NEXT: str [[R0]], [[[ADDR1]], #4] +; CHECK-T2-NEXT: str [[R1]], [[[ADDR1]]] + +; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] +; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] +; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #4] +; CHECK-ARMV4T-NEXT: str [[R0]], [[[ADDR1]], #4] +; CHECK-ARMV4T-NEXT: str [[R1]], [[[ADDR1]]] + +; CHECK-ARMV7: movw [[ADDR0:r[0-9]+]], :lower16:x_unaligned +; CHECK-ARMV7-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y_unaligned +; CHECK-ARMV7-NEXT: movt [[ADDR0]], :upper16:x_unaligned +; CHECK-ARMV7-NEXT: movt [[ADDR1]], :upper16:y_unaligned +; CHECK-ARMV7-NEXT: ldr [[R1]], [[[ADDR0]]] +; CHECK-ARMV7-NEXT: ldr [[R0]], [[[ADDR0]], #4] +; CHECK-ARMV7-NEXT: str [[R0]], [[[ADDR1]], #4] +; CHECK-ARMV7-NEXT: str [[R1]], [[[ADDR1]]] + %0 = load volatile i64, ptr @x_unaligned, align 1 + store volatile i64 %0, ptr @y_unaligned, align 1 + ret void +} + +define void @test_align_4() { +entry: +; CHECK-LABEL: test_align_4: + +; CHECK-ARMV7: movw [[ADDR0:r[0-9]+]], :lower16:x_aligned_4 +; CHECK-ARMV7-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y_aligned_4 +; CHECK-ARMV7-NEXT: movt [[ADDR0]], :upper16:x_aligned_4 +; CHECK-ARMV7-NEXT: movt [[ADDR1]], :upper16:y_aligned_4 +; CHECK-ARMV7-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV7-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + +; CHECK-ARMV6: ldr [[ADDR0:r[0-9]+]] +; CHECK-ARMV6-NEXT: ldr [[ADDR1:r[0-9]+]] +; CHECK-ARMV6-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV6-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + +; CHECK-ARMV6-STRICT: ldr [[ADDR0:r[0-9]+]] +; CHECK-ARMV6-STRICT-NEXT: ldr [[ADDR1:r[0-9]+]] +; CHECK-ARMV6-STRICT-NEXT: ldr [[R1:r[0-9]+]], [[[ADDR0]]] +; CHECK-ARMV6-STRICT-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #4] +; CHECK-ARMV6-STRICT-NEXT: str [[R0]], [[[ADDR1]], #4] +; CHECK-ARMV6-STRICT-NEXT: str [[R1]], [[[ADDR1]]] + %0 = load volatile i64, ptr @x_aligned_4, align 4 + store volatile i64 %0, ptr @y_aligned_4, align 4 + ret void +} + define void @test_offset() { entry: ; CHECK-LABEL: test_offset: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]], #-4] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]], #-4] + ; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x ; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y ; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x ; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]], #-4] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]], #-4] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #-4] @@ -55,14 +144,17 @@ define void @test_offset_1() { ; CHECK-LABEL: test_offset_1: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]], #255] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]], #255] + ; CHECK-T2: adds [[ADDR0:r[0-9]+]], #255 ; CHECK-T2-NEXT: adds [[ADDR1:r[0-9]+]], #255 ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #255] @@ -77,18 +169,21 @@ define void @test_offset_2() { ; CHECK-LABEL: test_offset_2: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #256 ; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #256 ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x ; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y ; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x ; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]], #256] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]], #256] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #256] @@ -103,18 +198,21 @@ define void @test_offset_3() { ; CHECK-LABEL: test_offset_3: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #1020 ; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #1020 ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x ; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y ; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x ; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]], #1020] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]], #1020] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #1020] @@ -129,12 +227,14 @@ define void @test_offset_4() { ; CHECK-LABEL: test_offset_4: + ; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV5TE: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #1024 ; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #1024 ; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-T2: movw [[ADDR1:r[0-9]+]], :lower16:y ; CHECK-T2-NEXT: movw [[ADDR0:r[0-9]+]], :lower16:x ; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y @@ -143,6 +243,7 @@ ; CHECK-T2-NEXT: add.w [[ADDR1]], [[ADDR1]], #1024 ; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], [[[ADDR0]]] ; CHECK-T2-NEXT: strd [[R0]], [[R1]], [[[ADDR1]]] + ; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]] ; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], [[[ADDR0]], #1024] @@ -157,6 +258,7 @@ define i64 @test_stack() { ; CHECK-LABEL: test_stack: + ; CHECK-ARMV5TE: sub sp, sp, #80 ; CHECK-ARMV5TE-NEXT: mov [[R0:r[0-9]+]], #0 ; CHECK-ARMV5TE-NEXT: mov [[R1:r[0-9]+]], #1 @@ -164,6 +266,7 @@ ; CHECK-ARMV5TE-NEXT: ldrd r0, r1, [sp, #8] ; CHECK-ARMV5TE-NEXT: add sp, sp, #80 ; CHECK-ARMV5TE-NEXT: bx lr + ; CHECK-T2: sub sp, #80 ; CHECK-T2-NEXT: movs [[R0:r[0-9]+]], #0 ; CHECK-T2-NEXT: movs [[R1:r[0-9]+]], #1 @@ -171,6 +274,7 @@ ; CHECK-T2-NEXT: ldrd r0, r1, [sp, #8] ; CHECK-T2-NEXT: add sp, #80 ; CHECK-T2-NEXT: bx lr + ; CHECK-ARMV4T: sub sp, sp, #80 ; CHECK-ARMV4T-NEXT: mov [[R0:r[0-9]+]], #0 ; CHECK-ARMV4T-NEXT: str [[R0]], [sp, #12]