llvm/test/CodeGen/ARM/load.ll
John Brawn 4d88daed01 [ARM] Reorganise and simplify thumb-1 load/store selection
Other than PC-relative loads/store the patterns that match the various
load/store addressing modes have the same complexity, so the order that they
are matched is the order that they appear in the .td file.

Rearrange the instruction definitions in ARMInstrThumb.td, and make use of
AddedComplexity for PC-relative loads, so that the instruction matching order
is the order that results in the simplest selection logic. This also makes
register-offset load/store be selected when it should, as previously it was
only selected for too-large immediate offsets.

Differential Revision: http://reviews.llvm.org/D11800


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244882 91177308-0d34-0410-b5e6-96231b3b80d8
2015-08-13 10:48:22 +00:00

565 lines
14 KiB
LLVM

; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T1
; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T2
; Register offset
; CHECK-LABEL: ldrsb_rr
; CHECK: ldrsb r0, [r0, r1]
define i32 @ldrsb_rr(i8* %p, i32 %n) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
%0 = load i8, i8* %arrayidx, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_rr
; CHECK-T1: lsls r1, r1, #1
; CHECK-T1: ldrsh r0, [r0, r1]
; CHECK-T2: ldrsh.w r0, [r0, r1, lsl #1]
define i32 @ldrsh_rr(i16* %p, i32 %n) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
%0 = load i16, i16* %arrayidx, align 2
%conv = sext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_rr
; CHECK: ldrb r0, [r0, r1]
define i32 @ldrb_rr(i8* %p, i32 %n) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
%0 = load i8, i8* %arrayidx, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_rr
; CHECK-T1: lsls r1, r1, #1
; CHECK-T1: ldrh r0, [r0, r1]
; CHECK-T2: ldrh.w r0, [r0, r1, lsl #1]
define i32 @ldrh_rr(i16* %p, i32 %n) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
%0 = load i16, i16* %arrayidx, align 2
%conv = zext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_rr
; CHECK-T1: lsls r1, r1, #2
; CHECK-T1: ldr r0, [r0, r1]
; CHECK-T2: ldr.w r0, [r0, r1, lsl #2]
define i32 @ldr_rr(i32* %p, i32 %n) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
%0 = load i32, i32* %arrayidx, align 4
ret i32 %0
}
; CHECK-LABEL: strb_rr
; CHECK: strb r2, [r0, r1]
define void @strb_rr(i8* %p, i32 %n, i32 %x) {
entry:
%conv = trunc i32 %x to i8
%arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
store i8 %conv, i8* %arrayidx, align 1
ret void
}
; CHECK-LABEL: strh_rr
; CHECK-T1: lsls r1, r1, #1
; CHECK-T1: strh r2, [r0, r1]
; CHECK-T2: strh.w r2, [r0, r1, lsl #1]
define void @strh_rr(i16* %p, i32 %n, i32 %x) {
entry:
%conv = trunc i32 %x to i16
%arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
store i16 %conv, i16* %arrayidx, align 2
ret void
}
; CHECK-LABEL: str_rr
; CHECK-T1: lsls r1, r1, #2
; CHECK-T1: str r2, [r0, r1]
; CHECK-T2: str.w r2, [r0, r1, lsl #2]
define void @str_rr(i32* %p, i32 %n, i32 %x) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
store i32 %x, i32* %arrayidx, align 4
ret void
}
; Immediate offset of zero
; CHECK-LABEL: ldrsb_ri_zero
; CHECK-T1: ldrb r0, [r0]
; CHECK-T1: sxtb r0, r0
; CHECK-T2: ldrsb.w r0, [r0]
define i32 @ldrsb_ri_zero(i8* %p) {
entry:
%0 = load i8, i8* %p, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_ri_zero
; CHECK-T1: ldrh r0, [r0]
; CHECK-T1: sxth r0, r0
; CHECK-T2: ldrsh.w r0, [r0]
define i32 @ldrsh_ri_zero(i16* %p) {
entry:
%0 = load i16, i16* %p, align 2
%conv = sext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_ri_zero
; CHECK: ldrb r0, [r0]
define i32 @ldrb_ri_zero(i8* %p) {
entry:
%0 = load i8, i8* %p, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_ri_zero
; CHECK: ldrh r0, [r0]
define i32 @ldrh_ri_zero(i16* %p) {
entry:
%0 = load i16, i16* %p, align 2
%conv = zext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_ri_zero
; CHECK: ldr r0, [r0]
define i32 @ldr_ri_zero(i32* %p) {
entry:
%0 = load i32, i32* %p, align 4
ret i32 %0
}
; CHECK-LABEL: strb_ri_zero
; CHECK: strb r1, [r0]
define void @strb_ri_zero(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i8
store i8 %conv, i8* %p, align 1
ret void
}
; CHECK-LABEL: strh_ri_zero
; CHECK: strh r1, [r0]
define void @strh_ri_zero(i16* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i16
store i16 %conv, i16* %p, align 2
ret void
}
; CHECK-LABEL: str_ri_zero
; CHECK: str r1, [r0]
define void @str_ri_zero(i32* %p, i32 %x) {
entry:
store i32 %x, i32* %p, align 4
ret void
}
; Maximum Thumb-1 immediate offset
; CHECK-LABEL: ldrsb_ri_t1_max
; CHECK-T1: movs r1, #31
; CHECK-T1: ldrsb r0, [r0, r1]
; CHECK-T2: ldrsb.w r0, [r0, #31]
define i32 @ldrsb_ri_t1_max(i8* %p) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 31
%0 = load i8, i8* %arrayidx, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_ri_t1_max
; CHECK-T1: movs r1, #62
; CHECK-T1: ldrsh r0, [r0, r1]
; CHECK-T2: ldrsh.w r0, [r0, #62]
define i32 @ldrsh_ri_t1_max(i16* %p) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 31
%0 = load i16, i16* %arrayidx, align 2
%conv = sext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_ri_t1_max
; CHECK: ldrb r0, [r0, #31]
define i32 @ldrb_ri_t1_max(i8* %p) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 31
%0 = load i8, i8* %arrayidx, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_ri_t1_max
; CHECK: ldrh r0, [r0, #62]
define i32 @ldrh_ri_t1_max(i16* %p) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 31
%0 = load i16, i16* %arrayidx, align 2
%conv = zext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_ri_t1_max
; CHECK: ldr r0, [r0, #124]
define i32 @ldr_ri_t1_max(i32* %p) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 31
%0 = load i32, i32* %arrayidx, align 4
ret i32 %0
}
; CHECK-LABEL: strb_ri_t1_max
; CHECK: strb r1, [r0, #31]
define void @strb_ri_t1_max(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i8
%arrayidx = getelementptr inbounds i8, i8* %p, i32 31
store i8 %conv, i8* %arrayidx, align 1
ret void
}
; CHECK-LABEL: strh_ri_t1_max
; CHECK: strh r1, [r0, #62]
define void @strh_ri_t1_max(i16* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i16
%arrayidx = getelementptr inbounds i16, i16* %p, i32 31
store i16 %conv, i16* %arrayidx, align 2
ret void
}
; CHECK-LABEL: str_ri_t1_max
; CHECK: str r1, [r0, #124]
define void @str_ri_t1_max(i32* %p, i32 %x) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 31
store i32 %x, i32* %arrayidx, align 4
ret void
}
; One past maximum Thumb-1 immediate offset
; CHECK-LABEL: ldrsb_ri_t1_too_big
; CHECK-T1: movs r1, #32
; CHECK-T1: ldrsb r0, [r0, r1]
; CHECK-T2: ldrsb.w r0, [r0, #32]
define i32 @ldrsb_ri_t1_too_big(i8* %p) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 32
%0 = load i8, i8* %arrayidx, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_ri_t1_too_big
; CHECK-T1: movs r1, #64
; CHECK-T1: ldrsh r0, [r0, r1]
; CHECK-T2: ldrsh.w r0, [r0, #64]
define i32 @ldrsh_ri_t1_too_big(i16* %p) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 32
%0 = load i16, i16* %arrayidx, align 2
%conv = sext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_ri_t1_too_big
; CHECK-T1: movs r1, #32
; CHECK-T1: ldrb r0, [r0, r1]
; CHECK-T2: ldrb.w r0, [r0, #32]
define i32 @ldrb_ri_t1_too_big(i8* %p) {
entry:
%arrayidx = getelementptr inbounds i8, i8* %p, i32 32
%0 = load i8, i8* %arrayidx, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_ri_t1_too_big
; CHECK-T1: movs r1, #64
; CHECK-T1: ldrh r0, [r0, r1]
; CHECK-T2: ldrh.w r0, [r0, #64]
define i32 @ldrh_ri_t1_too_big(i16* %p) {
entry:
%arrayidx = getelementptr inbounds i16, i16* %p, i32 32
%0 = load i16, i16* %arrayidx, align 2
%conv = zext i16 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_ri_t1_too_big
; CHECK-T1: movs r1, #128
; CHECK-T1: ldr r0, [r0, r1]
; CHECK-T2: ldr.w r0, [r0, #128]
define i32 @ldr_ri_t1_too_big(i32* %p) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 32
%0 = load i32, i32* %arrayidx, align 4
ret i32 %0
}
; CHECK-LABEL: strb_ri_t1_too_big
; CHECK-T1: movs r2, #32
; CHECK-T1: strb r1, [r0, r2]
; CHECK-T2: strb.w r1, [r0, #32]
define void @strb_ri_t1_too_big(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i8
%arrayidx = getelementptr inbounds i8, i8* %p, i32 32
store i8 %conv, i8* %arrayidx, align 1
ret void
}
; CHECK-LABEL: strh_ri_t1_too_big
; CHECK-T1: movs r2, #64
; CHECK-T1: strh r1, [r0, r2]
; CHECK-T2: strh.w r1, [r0, #64]
define void @strh_ri_t1_too_big(i16* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i16
%arrayidx = getelementptr inbounds i16, i16* %p, i32 32
store i16 %conv, i16* %arrayidx, align 2
ret void
}
; CHECK-LABEL: str_ri_t1_too_big
; CHECK-T1: movs r2, #128
; CHECK-T1: str r1, [r0, r2]
; CHECK-T2: str.w r1, [r0, #128]
define void @str_ri_t1_too_big(i32* %p, i32 %x) {
entry:
%arrayidx = getelementptr inbounds i32, i32* %p, i32 32
store i32 %x, i32* %arrayidx, align 4
ret void
}
; Maximum Thumb-2 immediate offset
; CHECK-LABEL: ldrsb_ri_t2_max
; CHECK-T1: ldr r1, .LCP
; CHECK-T1: ldrsb r0, [r0, r1]
; CHECK-T2: ldrsb.w r0, [r0, #4095]
define i32 @ldrsb_ri_t2_max(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = load i8, i8* %add.ptr, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_ri_t2_max
; CHECK-T1: ldr r1, .LCP
; CHECK-T1: ldrsh r0, [r0, r1]
; CHECK-T2: ldrsh.w r0, [r0, #4095]
define i32 @ldrsh_ri_t2_max(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = bitcast i8* %add.ptr to i16*
%1 = load i16, i16* %0, align 2
%conv = sext i16 %1 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_ri_t2_max
; CHECK-T1: ldr r1, .LCP
; CHECK-T1: ldrb r0, [r0, r1]
; CHECK-T2: ldrb.w r0, [r0, #4095]
define i32 @ldrb_ri_t2_max(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = load i8, i8* %add.ptr, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_ri_t2_max
; CHECK-T1: ldr r1, .LCP
; CHECK-T1: ldrh r0, [r0, r1]
; CHECK-T2: ldrh.w r0, [r0, #4095]
define i32 @ldrh_ri_t2_max(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = bitcast i8* %add.ptr to i16*
%1 = load i16, i16* %0, align 2
%conv = zext i16 %1 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_ri_t2_max
; CHECK-T1: ldr r1, .LCP
; CHECK-T1: ldr r0, [r0, r1]
; CHECK-T2: ldr.w r0, [r0, #4095]
define i32 @ldr_ri_t2_max(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = bitcast i8* %add.ptr to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}
; CHECK-LABEL: strb_ri_t2_max
; CHECK-T1: ldr r2, .LCP
; CHECK-T1: strb r1, [r0, r2]
; CHECK-T2: strb.w r1, [r0, #4095]
define void @strb_ri_t2_max(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i8
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
store i8 %conv, i8* %add.ptr, align 1
ret void
}
; CHECK-LABEL: strh_ri_t2_max
; CHECK-T1: ldr r2, .LCP
; CHECK-T1: strh r1, [r0, r2]
; CHECK-T2: strh.w r1, [r0, #4095]
define void @strh_ri_t2_max(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i16
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = bitcast i8* %add.ptr to i16*
store i16 %conv, i16* %0, align 2
ret void
}
; CHECK-LABEL: str_ri_t2_max
; CHECK-T1: ldr r2, .LCP
; CHECK-T1: str r1, [r0, r2]
; CHECK-T2: str.w r1, [r0, #4095]
define void @str_ri_t2_max(i8* %p, i32 %x) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
%0 = bitcast i8* %add.ptr to i32*
store i32 %x, i32* %0, align 4
ret void
}
; One past maximum Thumb-2 immediate offset
; CHECK-LABEL: ldrsb_ri_t2_too_big
; CHECK-T1: movs r1, #1
; CHECK-T1: lsls r1, r1, #12
; CHECK-T2: mov.w r1, #4096
; CHECK: ldrsb r0, [r0, r1]
define i32 @ldrsb_ri_t2_too_big(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = load i8, i8* %add.ptr, align 1
%conv = sext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrsh_ri_t2_too_big
; CHECK-T1: movs r1, #1
; CHECK-T1: lsls r1, r1, #12
; CHECK-T2: mov.w r1, #4096
; CHECK: ldrsh r0, [r0, r1]
define i32 @ldrsh_ri_t2_too_big(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = bitcast i8* %add.ptr to i16*
%1 = load i16, i16* %0, align 2
%conv = sext i16 %1 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrb_ri_t2_too_big
; CHECK-T1: movs r1, #1
; CHECK-T1: lsls r1, r1, #12
; CHECK-T2: mov.w r1, #4096
; CHECK: ldrb r0, [r0, r1]
define i32 @ldrb_ri_t2_too_big(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = load i8, i8* %add.ptr, align 1
%conv = zext i8 %0 to i32
ret i32 %conv
}
; CHECK-LABEL: ldrh_ri_t2_too_big
; CHECK-T1: movs r1, #1
; CHECK-T1: lsls r1, r1, #12
; CHECK-T2: mov.w r1, #4096
; CHECK: ldrh r0, [r0, r1]
define i32 @ldrh_ri_t2_too_big(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = bitcast i8* %add.ptr to i16*
%1 = load i16, i16* %0, align 2
%conv = zext i16 %1 to i32
ret i32 %conv
}
; CHECK-LABEL: ldr_ri_t2_too_big
; CHECK-T1: movs r1, #1
; CHECK-T1: lsls r1, r1, #12
; CHECK-T2: mov.w r1, #4096
; CHECK: ldr r0, [r0, r1]
define i32 @ldr_ri_t2_too_big(i8* %p) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = bitcast i8* %add.ptr to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}
; CHECK-LABEL: strb_ri_t2_too_big
; CHECK-T1: movs r2, #1
; CHECK-T1: lsls r2, r2, #12
; CHECK-T2: mov.w r2, #4096
; CHECK: strb r1, [r0, r2]
define void @strb_ri_t2_too_big(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i8
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
store i8 %conv, i8* %add.ptr, align 1
ret void
}
; CHECK-LABEL: strh_ri_t2_too_big
; CHECK-T1: movs r2, #1
; CHECK-T1: lsls r2, r2, #12
; CHECK-T2: mov.w r2, #4096
; CHECK: strh r1, [r0, r2]
define void @strh_ri_t2_too_big(i8* %p, i32 %x) {
entry:
%conv = trunc i32 %x to i16
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = bitcast i8* %add.ptr to i16*
store i16 %conv, i16* %0, align 2
ret void
}
; CHECK-LABEL: str_ri_t2_too_big
; CHECK-T1: movs r2, #1
; CHECK-T1: lsls r2, r2, #12
; CHECK-T2: mov.w r2, #4096
; CHECK: str r1, [r0, r2]
define void @str_ri_t2_too_big(i8* %p, i32 %x) {
entry:
%add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
%0 = bitcast i8* %add.ptr to i32*
store i32 %x, i32* %0, align 4
ret void
}