378 lines
11 KiB
LLVM
378 lines
11 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s -mtriple=aarch64-apple-ios -global-isel -global-isel-abort=1 | FileCheck %s
|
|
|
|
define dso_local void @trunc_i16_to_i8(i16 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i16_to_i8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: strh w0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i16 %x to i8
|
|
%sh = lshr i16 %x, 8
|
|
%t2 = trunc i16 %sh to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @trunc_i32_to_i8(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i32_to_i8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: str w0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i32 %x to i8
|
|
%sh1 = lshr i32 %x, 8
|
|
%t2 = trunc i32 %sh1 to i8
|
|
%sh2 = lshr i32 %x, 16
|
|
%t3 = trunc i32 %sh2 to i8
|
|
%sh3 = lshr i32 %x, 24
|
|
%t4 = trunc i32 %sh3 to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
%p2 = getelementptr inbounds i8, ptr %p, i64 2
|
|
store i8 %t3, ptr %p2, align 1
|
|
%p3 = getelementptr inbounds i8, ptr %p, i64 3
|
|
store i8 %t4, ptr %p3, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @trunc_i32_to_i16(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i32_to_i16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: str w0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i32 %x to i16
|
|
%sh = lshr i32 %x, 16
|
|
%t2 = trunc i32 %sh to i16
|
|
store i16 %t1, ptr %p, align 2
|
|
%p1 = getelementptr inbounds i16, ptr %p, i64 1
|
|
store i16 %t2, ptr %p1, align 2
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @be_i32_to_i16(i32 %x, ptr %p0) {
|
|
; CHECK-LABEL: be_i32_to_i16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ror w8, w0, #16
|
|
; CHECK-NEXT: str w8, [x1]
|
|
; CHECK-NEXT: ret
|
|
%sh1 = lshr i32 %x, 16
|
|
%t0 = trunc i32 %x to i16
|
|
%t1 = trunc i32 %sh1 to i16
|
|
%p1 = getelementptr inbounds i16, ptr %p0, i64 1
|
|
store i16 %t0, ptr %p1, align 2
|
|
store i16 %t1, ptr %p0, align 2
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @be_i32_to_i16_order(i32 %x, ptr %p0) {
|
|
; CHECK-LABEL: be_i32_to_i16_order:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ror w8, w0, #16
|
|
; CHECK-NEXT: str w8, [x1]
|
|
; CHECK-NEXT: ret
|
|
%sh1 = lshr i32 %x, 16
|
|
%t0 = trunc i32 %x to i16
|
|
%t1 = trunc i32 %sh1 to i16
|
|
%p1 = getelementptr inbounds i16, ptr %p0, i64 1
|
|
store i16 %t1, ptr %p0, align 2
|
|
store i16 %t0, ptr %p1, align 2
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @trunc_i64_to_i8(i64 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i64_to_i8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: str x0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i64 %x to i8
|
|
%sh1 = lshr i64 %x, 8
|
|
%t2 = trunc i64 %sh1 to i8
|
|
%sh2 = lshr i64 %x, 16
|
|
%t3 = trunc i64 %sh2 to i8
|
|
%sh3 = lshr i64 %x, 24
|
|
%t4 = trunc i64 %sh3 to i8
|
|
%sh4 = lshr i64 %x, 32
|
|
%t5 = trunc i64 %sh4 to i8
|
|
%sh5 = lshr i64 %x, 40
|
|
%t6 = trunc i64 %sh5 to i8
|
|
%sh6 = lshr i64 %x, 48
|
|
%t7 = trunc i64 %sh6 to i8
|
|
%sh7 = lshr i64 %x, 56
|
|
%t8 = trunc i64 %sh7 to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
%p2 = getelementptr inbounds i8, ptr %p, i64 2
|
|
store i8 %t3, ptr %p2, align 1
|
|
%p3 = getelementptr inbounds i8, ptr %p, i64 3
|
|
store i8 %t4, ptr %p3, align 1
|
|
%p4 = getelementptr inbounds i8, ptr %p, i64 4
|
|
store i8 %t5, ptr %p4, align 1
|
|
%p5 = getelementptr inbounds i8, ptr %p, i64 5
|
|
store i8 %t6, ptr %p5, align 1
|
|
%p6 = getelementptr inbounds i8, ptr %p, i64 6
|
|
store i8 %t7, ptr %p6, align 1
|
|
%p7 = getelementptr inbounds i8, ptr %p, i64 7
|
|
store i8 %t8, ptr %p7, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @trunc_i64_to_i16(i64 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i64_to_i16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: str x0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i64 %x to i16
|
|
%sh1 = lshr i64 %x, 16
|
|
%t2 = trunc i64 %sh1 to i16
|
|
%sh2 = lshr i64 %x, 32
|
|
%t3 = trunc i64 %sh2 to i16
|
|
%sh3 = lshr i64 %x, 48
|
|
%t4 = trunc i64 %sh3 to i16
|
|
store i16 %t1, ptr %p, align 2
|
|
%p1 = getelementptr inbounds i16, ptr %p, i64 1
|
|
store i16 %t2, ptr %p1, align 2
|
|
%p2 = getelementptr inbounds i16, ptr %p, i64 2
|
|
store i16 %t3, ptr %p2, align 2
|
|
%p3 = getelementptr inbounds i16, ptr %p, i64 3
|
|
store i16 %t4, ptr %p3, align 2
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @trunc_i64_to_i32(i64 %x, ptr %p) {
|
|
; CHECK-LABEL: trunc_i64_to_i32:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: str x0, [x1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i64 %x to i32
|
|
%sh = lshr i64 %x, 32
|
|
%t2 = trunc i64 %sh to i32
|
|
store i32 %t1, ptr %p, align 4
|
|
%p1 = getelementptr inbounds i32, ptr %p, i64 1
|
|
store i32 %t2, ptr %p1, align 4
|
|
ret void
|
|
}
|
|
define dso_local void @be_i64_to_i32(i64 %x, ptr %p0) {
|
|
; CHECK-LABEL: be_i64_to_i32:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ror x8, x0, #32
|
|
; CHECK-NEXT: str x8, [x1]
|
|
; CHECK-NEXT: ret
|
|
%sh1 = lshr i64 %x, 32
|
|
%t0 = trunc i64 %x to i32
|
|
%t1 = trunc i64 %sh1 to i32
|
|
%p1 = getelementptr inbounds i32, ptr %p0, i64 1
|
|
store i32 %t0, ptr %p1, align 4
|
|
store i32 %t1, ptr %p0, align 4
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @be_i64_to_i32_order(i64 %x, ptr %p0) {
|
|
; CHECK-LABEL: be_i64_to_i32_order:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ror x8, x0, #32
|
|
; CHECK-NEXT: str x8, [x1]
|
|
; CHECK-NEXT: ret
|
|
%sh1 = lshr i64 %x, 32
|
|
%t0 = trunc i64 %x to i32
|
|
%t1 = trunc i64 %sh1 to i32
|
|
%p1 = getelementptr inbounds i32, ptr %p0, i64 1
|
|
store i32 %t1, ptr %p0, align 4
|
|
store i32 %t0, ptr %p1, align 4
|
|
ret void
|
|
}
|
|
|
|
; Negative tests.
|
|
|
|
define void @merge_hole(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: merge_hole:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr w8, w0, #16
|
|
; CHECK-NEXT: strb w0, [x1]
|
|
; CHECK-NEXT: strh w8, [x1, #2]
|
|
; CHECK-NEXT: ret
|
|
%p2 = getelementptr inbounds i16, ptr %p, i64 1
|
|
%x3 = trunc i32 %x to i8
|
|
store i8 %x3, ptr %p, align 1
|
|
%sh = lshr i32 %x, 16
|
|
%x01 = trunc i32 %sh to i16
|
|
store i16 %x01, ptr %p2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @merge_hole2(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: merge_hole2:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr w8, w0, #16
|
|
; CHECK-NEXT: strb w0, [x1]
|
|
; CHECK-NEXT: strh w8, [x1, #2]
|
|
; CHECK-NEXT: ret
|
|
%p2 = getelementptr inbounds i16, ptr %p, i64 1
|
|
%sh = lshr i32 %x, 16
|
|
%x01 = trunc i32 %sh to i16
|
|
store i16 %x01, ptr %p2, align 1
|
|
%x3 = trunc i32 %x to i8
|
|
store i8 %x3, ptr %p, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @merge_hole3(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: merge_hole3:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr w8, w0, #16
|
|
; CHECK-NEXT: strb w0, [x1, #1]
|
|
; CHECK-NEXT: strh w8, [x1, #2]
|
|
; CHECK-NEXT: ret
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
%p2 = getelementptr inbounds i16, ptr %p, i64 1
|
|
%x3 = trunc i32 %x to i8
|
|
store i8 %x3, ptr %p1, align 1
|
|
%sh = lshr i32 %x, 16
|
|
%x01 = trunc i32 %sh to i16
|
|
store i16 %x01, ptr %p2, align 1
|
|
ret void
|
|
}
|
|
|
|
define void @merge_hole4(i32 %x, ptr %p) {
|
|
; CHECK-LABEL: merge_hole4:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr w8, w0, #16
|
|
; CHECK-NEXT: strb w0, [x1, #2]
|
|
; CHECK-NEXT: strh w8, [x1]
|
|
; CHECK-NEXT: ret
|
|
%p2 = getelementptr inbounds i8, ptr %p, i64 2
|
|
%x3 = trunc i32 %x to i8
|
|
store i8 %x3, ptr %p2, align 1
|
|
%sh = lshr i32 %x, 16
|
|
%x01 = trunc i32 %sh to i16
|
|
store i16 %x01, ptr %p, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local i32 @load_between_stores(i32 %x, ptr %p, ptr %ptr) {
|
|
; CHECK-LABEL: load_between_stores:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: strh w0, [x1]
|
|
; CHECK-NEXT: lsr w9, w0, #16
|
|
; CHECK-NEXT: ldr w8, [x2]
|
|
; CHECK-NEXT: strh w9, [x1, #2]
|
|
; CHECK-NEXT: mov w0, w8
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i32 %x to i16
|
|
%sh = lshr i32 %x, 16
|
|
%t2 = trunc i32 %sh to i16
|
|
store i16 %t1, ptr %p, align 2
|
|
%ld = load i32, ptr %ptr
|
|
%p1 = getelementptr inbounds i16, ptr %p, i64 1
|
|
store i16 %t2, ptr %p1, align 2
|
|
ret i32 %ld
|
|
}
|
|
|
|
define dso_local void @invalid_shift(i16 %x, ptr %p) {
|
|
; CHECK-LABEL: invalid_shift:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ubfx w8, w0, #4, #12
|
|
; CHECK-NEXT: strb w0, [x1]
|
|
; CHECK-NEXT: strb w8, [x1, #1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i16 %x to i8
|
|
%sh = lshr i16 %x, 4
|
|
%t2 = trunc i16 %sh to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @missing_store(i32 %x, ptr %p) {
|
|
; The missing store of shift 16 means we can't merge to 32 bit store,
|
|
; but we can still partially merge to a 16 bit one.
|
|
; CHECK-LABEL: missing_store:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr w8, w0, #24
|
|
; CHECK-NEXT: strh w0, [x1]
|
|
; CHECK-NEXT: strb w8, [x1, #3]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i32 %x to i8
|
|
%sh1 = lshr i32 %x, 8
|
|
%t2 = trunc i32 %sh1 to i8
|
|
%sh3 = lshr i32 %x, 24
|
|
%t4 = trunc i32 %sh3 to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
%p3 = getelementptr inbounds i8, ptr %p, i64 3
|
|
store i8 %t4, ptr %p3, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @different_base_reg(i16 %x, ptr %p, ptr %p2) {
|
|
; CHECK-LABEL: different_base_reg:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ubfx w8, w0, #8, #8
|
|
; CHECK-NEXT: strb w0, [x1]
|
|
; CHECK-NEXT: strb w8, [x2, #1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i16 %x to i8
|
|
%sh = lshr i16 %x, 8
|
|
%t2 = trunc i16 %sh to i8
|
|
store i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p2, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @second_store_is_volatile(i16 %x, ptr %p) {
|
|
; CHECK-LABEL: second_store_is_volatile:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: ubfx w8, w0, #8, #8
|
|
; CHECK-NEXT: strb w0, [x1]
|
|
; CHECK-NEXT: strb w8, [x1, #1]
|
|
; CHECK-NEXT: ret
|
|
%t1 = trunc i16 %x to i8
|
|
%sh = lshr i16 %x, 8
|
|
%t2 = trunc i16 %sh to i8
|
|
store volatile i8 %t1, ptr %p, align 1
|
|
%p1 = getelementptr inbounds i8, ptr %p, i64 1
|
|
store i8 %t2, ptr %p1, align 1
|
|
ret void
|
|
}
|
|
|
|
declare void @use_ptr(ptr)
|
|
|
|
define dso_local void @trunc_from_larger_src_val(i64 %hold.4.lcssa, ptr %check1792) {
|
|
; Here we can merge these i8 stores into a single i32 store, but first we need
|
|
; to truncate the i64 value to i32.
|
|
; CHECK-LABEL: trunc_from_larger_src_val:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: sub sp, sp, #32
|
|
; CHECK-NEXT: stp x29, x30, [sp, #16] ; 16-byte Folded Spill
|
|
; CHECK-NEXT: .cfi_def_cfa_offset 32
|
|
; CHECK-NEXT: .cfi_offset w30, -8
|
|
; CHECK-NEXT: .cfi_offset w29, -16
|
|
; CHECK-NEXT: str w0, [sp, #12]
|
|
; CHECK-NEXT: add x0, sp, #12
|
|
; CHECK-NEXT: bl _use_ptr
|
|
; CHECK-NEXT: ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
|
|
; CHECK-NEXT: add sp, sp, #32
|
|
; CHECK-NEXT: ret
|
|
%hbuf = alloca [4 x i8], align 1
|
|
%arrayidx177 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 1
|
|
%arrayidx234 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 2
|
|
%arrayidx237 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 3
|
|
%conv227 = trunc i64 %hold.4.lcssa to i8
|
|
store i8 %conv227, ptr %hbuf, align 1
|
|
%shr229 = lshr i64 %hold.4.lcssa, 8
|
|
%conv230 = trunc i64 %shr229 to i8
|
|
store i8 %conv230, ptr %arrayidx177, align 1
|
|
%shr232 = lshr i64 %hold.4.lcssa, 16
|
|
%conv233 = trunc i64 %shr232 to i8
|
|
store i8 %conv233, ptr %arrayidx234, align 1
|
|
%shr235 = lshr i64 %hold.4.lcssa, 24
|
|
%conv236 = trunc i64 %shr235 to i8
|
|
store i8 %conv236, ptr %arrayidx237, align 1
|
|
call void @use_ptr(ptr noundef nonnull %hbuf)
|
|
ret void
|
|
}
|