Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/test/CodeGen/AArch64/GlobalISel/merge-stores-truncating.ll
- This file was added.
; 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, i8* %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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @trunc_i32_to_i8(i32 %x, i8* %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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
%p2 = getelementptr inbounds i8, i8* %p, i64 2 | |||||
store i8 %t3, i8* %p2, align 1 | |||||
%p3 = getelementptr inbounds i8, i8* %p, i64 3 | |||||
store i8 %t4, i8* %p3, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @trunc_i32_to_i16(i32 %x, i16* %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, i16* %p, align 2 | |||||
%p1 = getelementptr inbounds i16, i16* %p, i64 1 | |||||
store i16 %t2, i16* %p1, align 2 | |||||
ret void | |||||
} | |||||
define dso_local void @be_i32_to_i16(i32 %x, i16* %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, i16* %p0, i64 1 | |||||
store i16 %t0, i16* %p1, align 2 | |||||
store i16 %t1, i16* %p0, align 2 | |||||
ret void | |||||
} | |||||
define dso_local void @be_i32_to_i16_order(i32 %x, i16* %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, i16* %p0, i64 1 | |||||
store i16 %t1, i16* %p0, align 2 | |||||
store i16 %t0, i16* %p1, align 2 | |||||
ret void | |||||
} | |||||
define dso_local void @trunc_i64_to_i8(i64 %x, i8* %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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
%p2 = getelementptr inbounds i8, i8* %p, i64 2 | |||||
store i8 %t3, i8* %p2, align 1 | |||||
%p3 = getelementptr inbounds i8, i8* %p, i64 3 | |||||
store i8 %t4, i8* %p3, align 1 | |||||
%p4 = getelementptr inbounds i8, i8* %p, i64 4 | |||||
store i8 %t5, i8* %p4, align 1 | |||||
%p5 = getelementptr inbounds i8, i8* %p, i64 5 | |||||
store i8 %t6, i8* %p5, align 1 | |||||
%p6 = getelementptr inbounds i8, i8* %p, i64 6 | |||||
store i8 %t7, i8* %p6, align 1 | |||||
%p7 = getelementptr inbounds i8, i8* %p, i64 7 | |||||
store i8 %t8, i8* %p7, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @trunc_i64_to_i16(i64 %x, i16* %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, i16* %p, align 2 | |||||
%p1 = getelementptr inbounds i16, i16* %p, i64 1 | |||||
store i16 %t2, i16* %p1, align 2 | |||||
%p2 = getelementptr inbounds i16, i16* %p, i64 2 | |||||
store i16 %t3, i16* %p2, align 2 | |||||
%p3 = getelementptr inbounds i16, i16* %p, i64 3 | |||||
store i16 %t4, i16* %p3, align 2 | |||||
ret void | |||||
} | |||||
define dso_local void @trunc_i64_to_i32(i64 %x, i32* %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, i32* %p, align 4 | |||||
%p1 = getelementptr inbounds i32, i32* %p, i64 1 | |||||
store i32 %t2, i32* %p1, align 4 | |||||
ret void | |||||
} | |||||
define dso_local void @be_i64_to_i32(i64 %x, i32* %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, i32* %p0, i64 1 | |||||
store i32 %t0, i32* %p1, align 4 | |||||
store i32 %t1, i32* %p0, align 4 | |||||
ret void | |||||
} | |||||
define dso_local void @be_i64_to_i32_order(i64 %x, i32* %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, i32* %p0, i64 1 | |||||
store i32 %t1, i32* %p0, align 4 | |||||
store i32 %t0, i32* %p1, align 4 | |||||
ret void | |||||
} | |||||
; Negative tests. | |||||
define void @merge_hole(i32 %x, i8* %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 | |||||
%pcast = bitcast i8* %p to i16* | |||||
%p2 = getelementptr inbounds i16, i16* %pcast, i64 1 | |||||
%x3 = trunc i32 %x to i8 | |||||
store i8 %x3, i8* %p, align 1 | |||||
%sh = lshr i32 %x, 16 | |||||
%x01 = trunc i32 %sh to i16 | |||||
store i16 %x01, i16* %p2, align 1 | |||||
ret void | |||||
} | |||||
define void @merge_hole2(i32 %x, i8* %p) { | |||||
; CHECK-LABEL: merge_hole2: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: lsr w8, w0, #16 | |||||
; CHECK-NEXT: strh w8, [x1, #2] | |||||
; CHECK-NEXT: strb w0, [x1] | |||||
; CHECK-NEXT: ret | |||||
%pcast = bitcast i8* %p to i16* | |||||
%p2 = getelementptr inbounds i16, i16* %pcast, i64 1 | |||||
%sh = lshr i32 %x, 16 | |||||
%x01 = trunc i32 %sh to i16 | |||||
store i16 %x01, i16* %p2, align 1 | |||||
%x3 = trunc i32 %x to i8 | |||||
store i8 %x3, i8* %p, align 1 | |||||
ret void | |||||
} | |||||
define void @merge_hole3(i32 %x, i8* %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, i8* %p, i64 1 | |||||
%pcast = bitcast i8* %p to i16* | |||||
%p2 = getelementptr inbounds i16, i16* %pcast, i64 1 | |||||
%x3 = trunc i32 %x to i8 | |||||
store i8 %x3, i8* %p1, align 1 | |||||
%sh = lshr i32 %x, 16 | |||||
%x01 = trunc i32 %sh to i16 | |||||
store i16 %x01, i16* %p2, align 1 | |||||
ret void | |||||
} | |||||
define void @merge_hole4(i32 %x, i8* %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 | |||||
%pcast = bitcast i8* %p to i16* | |||||
%p2 = getelementptr inbounds i8, i8* %p, i64 2 | |||||
%x3 = trunc i32 %x to i8 | |||||
store i8 %x3, i8* %p2, align 1 | |||||
%sh = lshr i32 %x, 16 | |||||
%x01 = trunc i32 %sh to i16 | |||||
store i16 %x01, i16* %pcast, align 1 | |||||
ret void | |||||
} | |||||
define dso_local i32 @load_between_stores(i32 %x, i16* %p, i32 *%ptr) { | |||||
; CHECK-LABEL: load_between_stores: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: strh w0, [x1] | |||||
; CHECK-NEXT: ldr w8, [x2] | |||||
; CHECK-NEXT: lsr w9, w0, #16 | |||||
; 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, i16* %p, align 2 | |||||
%ld = load i32, i32 *%ptr | |||||
%p1 = getelementptr inbounds i16, i16* %p, i64 1 | |||||
store i16 %t2, i16* %p1, align 2 | |||||
ret i32 %ld | |||||
} | |||||
define dso_local void @invalid_shift(i16 %x, i8* %p) { | |||||
; CHECK-LABEL: invalid_shift: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: and w8, w0, #0xffff | |||||
; CHECK-NEXT: lsr w8, w8, #4 | |||||
; 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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @missing_store(i32 %x, i8* %p) { | |||||
; CHECK-LABEL: missing_store: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: lsr w8, w0, #8 | |||||
; CHECK-NEXT: lsr w9, w0, #24 | |||||
; CHECK-NEXT: strb w0, [x1] | |||||
; CHECK-NEXT: strb w8, [x1, #1] | |||||
; CHECK-NEXT: strb w9, [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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
%p3 = getelementptr inbounds i8, i8* %p, i64 3 | |||||
store i8 %t4, i8* %p3, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @different_base_reg(i16 %x, i8* %p, i8 *%p2) { | |||||
; CHECK-LABEL: different_base_reg: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: and w8, w0, #0xffff | |||||
; CHECK-NEXT: lsr w8, w8, #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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p2, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
ret void | |||||
} | |||||
define dso_local void @second_store_is_volatile(i16 %x, i8* %p) { | |||||
; CHECK-LABEL: second_store_is_volatile: | |||||
; CHECK: ; %bb.0: | |||||
; CHECK-NEXT: and w8, w0, #0xffff | |||||
; CHECK-NEXT: lsr w8, w8, #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, i8* %p, align 1 | |||||
%p1 = getelementptr inbounds i8, i8* %p, i64 1 | |||||
store i8 %t2, i8* %p1, align 1 | |||||
ret void | |||||
} |