| ; 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(ptr %p, i32 %n) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 %n | |
| %0 = load i8, ptr %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(ptr %p, i32 %n) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 %n | |
| %0 = load i16, ptr %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(ptr %p, i32 %n) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 %n | |
| %0 = load i8, ptr %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(ptr %p, i32 %n) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 %n | |
| %0 = load i16, ptr %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(ptr %p, i32 %n) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 %n | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| ret i32 %0 | |
| } | |
| ; CHECK-LABEL: strb_rr | |
| ; CHECK: strb r2, [r0, r1] | |
| define void @strb_rr(ptr %p, i32 %n, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 %n | |
| store i8 %conv, ptr %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(ptr %p, i32 %n, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 %n | |
| store i16 %conv, ptr %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(ptr %p, i32 %n, i32 %x) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 %n | |
| store i32 %x, ptr %arrayidx, align 4 | |
| ret void | |
| } | |
| ; Immediate offset of zero | |
| ; CHECK-LABEL: ldrsb_ri_zero | |
| ; CHECK-T1: movs r1, #0 | |
| ; CHECK-T1: ldrsb r0, [r0, r1] | |
| ; CHECK-T2: ldrsb.w r0, [r0] | |
| define i32 @ldrsb_ri_zero(ptr %p) { | |
| entry: | |
| %0 = load i8, ptr %p, align 1 | |
| %conv = sext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| ; CHECK-LABEL: ldrsh_ri_zero | |
| ; CHECK-T1: movs r1, #0 | |
| ; CHECK-T1: ldrsh r0, [r0, r1] | |
| ; CHECK-T2: ldrsh.w r0, [r0] | |
| define i32 @ldrsh_ri_zero(ptr %p) { | |
| entry: | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %0 = load i32, ptr %p, align 4 | |
| ret i32 %0 | |
| } | |
| ; CHECK-LABEL: strb_ri_zero | |
| ; CHECK: strb r1, [r0] | |
| define void @strb_ri_zero(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| store i8 %conv, ptr %p, align 1 | |
| ret void | |
| } | |
| ; CHECK-LABEL: strh_ri_zero | |
| ; CHECK: strh r1, [r0] | |
| define void @strh_ri_zero(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| store i16 %conv, ptr %p, align 2 | |
| ret void | |
| } | |
| ; CHECK-LABEL: str_ri_zero | |
| ; CHECK: str r1, [r0] | |
| define void @str_ri_zero(ptr %p, i32 %x) { | |
| entry: | |
| store i32 %x, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 31 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 31 | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 31 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 31 | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 31 | |
| %0 = load i32, ptr %arrayidx, align 4 | |
| ret i32 %0 | |
| } | |
| ; CHECK-LABEL: strb_ri_t1_max | |
| ; CHECK: strb r1, [r0, #31] | |
| define void @strb_ri_t1_max(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 31 | |
| store i8 %conv, ptr %arrayidx, align 1 | |
| ret void | |
| } | |
| ; CHECK-LABEL: strh_ri_t1_max | |
| ; CHECK: strh r1, [r0, #62] | |
| define void @strh_ri_t1_max(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 31 | |
| store i16 %conv, ptr %arrayidx, align 2 | |
| ret void | |
| } | |
| ; CHECK-LABEL: str_ri_t1_max | |
| ; CHECK: str r1, [r0, #124] | |
| define void @str_ri_t1_max(ptr %p, i32 %x) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 31 | |
| store i32 %x, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 32 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 32 | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 32 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 32 | |
| %0 = load i16, ptr %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(ptr %p) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 32 | |
| %0 = load i32, ptr %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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %arrayidx = getelementptr inbounds i8, ptr %p, i32 32 | |
| store i8 %conv, ptr %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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %arrayidx = getelementptr inbounds i16, ptr %p, i32 32 | |
| store i16 %conv, ptr %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(ptr %p, i32 %x) { | |
| entry: | |
| %arrayidx = getelementptr inbounds i32, ptr %p, i32 32 | |
| store i32 %x, ptr %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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = sext i16 %0 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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = zext i16 %0 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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| %0 = load i32, ptr %add.ptr, align 4 | |
| ret i32 %0 | |
| } | |
| ; 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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| store i8 %conv, ptr %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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| store i16 %conv, ptr %add.ptr, 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(ptr %p, i32 %x) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4095 | |
| store i32 %x, ptr %add.ptr, 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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = sext i16 %0 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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| %0 = load i8, ptr %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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = zext i16 %0 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(ptr %p) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| %0 = load i32, ptr %add.ptr, align 4 | |
| ret i32 %0 | |
| } | |
| ; 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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| store i8 %conv, ptr %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(ptr %p, i32 %x) { | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| store i16 %conv, ptr %add.ptr, 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(ptr %p, i32 %x) { | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 4096 | |
| store i32 %x, ptr %add.ptr, align 4 | |
| ret void | |
| } | |
| ; Negative offset | |
| define i32 @ldrsb_ri_negative(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsb_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #0 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsb r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsb_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrsb r0, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = sext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrsh_ri_negative(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsh_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #0 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsh r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsh_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrsh r0, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = sext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrb_ri_negative(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrb_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: ldrb r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrb_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrb r0, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = zext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrh_ri_negative(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrh_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: ldrh r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrh_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrh r0, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = zext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldr_ri_negative(ptr %p) { | |
| ; CHECK-T1-LABEL: ldr_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: ldr r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldr_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldr r0, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| %0 = load i32, ptr %add.ptr, align 4 | |
| ret i32 %0 | |
| } | |
| define void @strb_ri_negative(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strb_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: strb r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strb_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: strb r1, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| store i8 %conv, ptr %add.ptr, align 1 | |
| ret void | |
| } | |
| define void @strh_ri_negative(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strh_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: strh r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strh_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: strh r1, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| store i16 %conv, ptr %add.ptr, align 2 | |
| ret void | |
| } | |
| define void @str_ri_negative(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: str_ri_negative: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, r0, #1 | |
| ; CHECK-T1-NEXT: str r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: str_ri_negative: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: str r1, [r0, #-1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -1 | |
| store i32 %x, ptr %add.ptr, align 4 | |
| ret void | |
| } | |
| ; Negative 255 offset | |
| define i32 @ldrsb_ri_negative255(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsb_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #254 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsb r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsb_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrsb r0, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = sext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrsh_ri_negative255(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsh_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #254 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsh r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsh_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrsh r0, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = sext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrb_ri_negative255(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrb_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: ldrb r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrb_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrb r0, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = zext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrh_ri_negative255(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrh_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: ldrh r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrh_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldrh r0, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = zext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldr_ri_negative255(ptr %p) { | |
| ; CHECK-T1-LABEL: ldr_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: ldr r0, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldr_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: ldr r0, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| %0 = load i32, ptr %add.ptr, align 4 | |
| ret i32 %0 | |
| } | |
| define void @strb_ri_negative255(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strb_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: strb r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strb_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: strb r1, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| store i8 %conv, ptr %add.ptr, align 1 | |
| ret void | |
| } | |
| define void @strh_ri_negative255(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strh_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: strh r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strh_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: strh r1, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| store i16 %conv, ptr %add.ptr, align 2 | |
| ret void | |
| } | |
| define void @str_ri_negative255(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: str_ri_negative255: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: subs r0, #255 | |
| ; CHECK-T1-NEXT: str r1, [r0] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: str_ri_negative255: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: str r1, [r0, #-255] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -255 | |
| store i32 %x, ptr %add.ptr, align 4 | |
| ret void | |
| } | |
| ; Negative 256 offset | |
| define i32 @ldrsb_ri_negative256(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsb_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #255 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsb r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsb_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r1, #255 | |
| ; CHECK-T2-NEXT: ldrsb r0, [r0, r1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = sext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrsh_ri_negative256(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrsh_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #255 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrsh r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrsh_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r1, #255 | |
| ; CHECK-T2-NEXT: ldrsh r0, [r0, r1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = sext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrb_ri_negative256(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrb_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #255 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrb r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrb_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r1, #255 | |
| ; CHECK-T2-NEXT: ldrb r0, [r0, r1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| %0 = load i8, ptr %add.ptr, align 1 | |
| %conv = zext i8 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldrh_ri_negative256(ptr %p) { | |
| ; CHECK-T1-LABEL: ldrh_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #255 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldrh r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldrh_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r1, #255 | |
| ; CHECK-T2-NEXT: ldrh r0, [r0, r1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| %0 = load i16, ptr %add.ptr, align 2 | |
| %conv = zext i16 %0 to i32 | |
| ret i32 %conv | |
| } | |
| define i32 @ldr_ri_negative256(ptr %p) { | |
| ; CHECK-T1-LABEL: ldr_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r1, #255 | |
| ; CHECK-T1-NEXT: mvns r1, r1 | |
| ; CHECK-T1-NEXT: ldr r0, [r0, r1] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: ldr_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r1, #255 | |
| ; CHECK-T2-NEXT: ldr r0, [r0, r1] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| %0 = load i32, ptr %add.ptr, align 4 | |
| ret i32 %0 | |
| } | |
| define void @strb_ri_negative256(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strb_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r2, #255 | |
| ; CHECK-T1-NEXT: mvns r2, r2 | |
| ; CHECK-T1-NEXT: strb r1, [r0, r2] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strb_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r2, #255 | |
| ; CHECK-T2-NEXT: strb r1, [r0, r2] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i8 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| store i8 %conv, ptr %add.ptr, align 1 | |
| ret void | |
| } | |
| define void @strh_ri_negative256(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: strh_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r2, #255 | |
| ; CHECK-T1-NEXT: mvns r2, r2 | |
| ; CHECK-T1-NEXT: strh r1, [r0, r2] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: strh_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r2, #255 | |
| ; CHECK-T2-NEXT: strh r1, [r0, r2] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %conv = trunc i32 %x to i16 | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| store i16 %conv, ptr %add.ptr, align 2 | |
| ret void | |
| } | |
| define void @str_ri_negative256(ptr %p, i32 %x) { | |
| ; CHECK-T1-LABEL: str_ri_negative256: | |
| ; CHECK-T1: @ %bb.0: @ %entry | |
| ; CHECK-T1-NEXT: movs r2, #255 | |
| ; CHECK-T1-NEXT: mvns r2, r2 | |
| ; CHECK-T1-NEXT: str r1, [r0, r2] | |
| ; CHECK-T1-NEXT: bx lr | |
| ; | |
| ; CHECK-T2-LABEL: str_ri_negative256: | |
| ; CHECK-T2: @ %bb.0: @ %entry | |
| ; CHECK-T2-NEXT: mvn r2, #255 | |
| ; CHECK-T2-NEXT: str r1, [r0, r2] | |
| ; CHECK-T2-NEXT: bx lr | |
| entry: | |
| %add.ptr = getelementptr inbounds i8, ptr %p, i32 -256 | |
| store i32 %x, ptr %add.ptr, align 4 | |
| ret void | |
| } |