blob: daa095209929c1683213a5b544f1ecc9a9dbe6fc [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=loongarch64 -mattr=-ual -verify-machineinstrs < %s | FileCheck %s --check-prefix=NOUAL
; RUN: llc -mtriple=loongarch64 -mattr=+ual -verify-machineinstrs < %s | FileCheck %s --check-prefix=UAL
; An i32 result does not require sign extension to i64: it becomes
; extloadi32 instead of sextloadi32. Select LDPTR.W rather than materializing
; the offset with ORI/LU12I.W and loading through LDX.W.
define i32 @anyext_2048(ptr %base) {
; NOUAL-LABEL: anyext_2048:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, 2048
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_2048:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, 2048
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 2048
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
define i32 @anyext_7960(ptr %base) {
; NOUAL-LABEL: anyext_7960:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, 7960
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_7960:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, 7960
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
define i32 @anyext_negative(ptr %base) {
; NOUAL-LABEL: anyext_negative:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, -2052
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_negative:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, -2052
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 -2052
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
define i32 @anyext_min(ptr %base) {
; NOUAL-LABEL: anyext_min:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, -32768
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_min:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, -32768
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 -32768
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
define i32 @anyext_max(ptr %base) {
; NOUAL-LABEL: anyext_max:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, 32764
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_max:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, 32764
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 32764
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
; Prefer LD.W for offsets that fit its signed 12-bit immediate.
define i32 @anyext_simm12(ptr %base) {
; NOUAL-LABEL: anyext_simm12:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ld.w $a0, $a0, 2044
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_simm12:
; UAL: # %bb.0:
; UAL-NEXT: ld.w $a0, $a0, 2044
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 2044
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
; Out-of-range offsets must not be encoded as LDPTR.W.
define i32 @anyext_overflow(ptr %base) {
; NOUAL-LABEL: anyext_overflow:
; NOUAL: # %bb.0:
; NOUAL-NEXT: lu12i.w $a1, 8
; NOUAL-NEXT: ldx.w $a0, $a0, $a1
; NOUAL-NEXT: ret
;
; UAL-LABEL: anyext_overflow:
; UAL: # %bb.0:
; UAL-NEXT: lu12i.w $a1, 8
; UAL-NEXT: ldx.w $a0, $a0, $a1
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 32768
%v = load volatile i32, ptr %p, align 4
ret i32 %v
}
; A zextloadi32 cannot be implemented by the sign-extending LDPTR.W.
define i64 @zext_is_not_ldptr(ptr %base) {
; NOUAL-LABEL: zext_is_not_ldptr:
; NOUAL: # %bb.0:
; NOUAL-NEXT: lu12i.w $a1, 1
; NOUAL-NEXT: ori $a1, $a1, 3864
; NOUAL-NEXT: ldx.wu $a0, $a0, $a1
; NOUAL-NEXT: ret
;
; UAL-LABEL: zext_is_not_ldptr:
; UAL: # %bb.0:
; UAL-NEXT: lu12i.w $a1, 1
; UAL-NEXT: ori $a1, $a1, 3864
; UAL-NEXT: ldx.wu $a0, $a0, $a1
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
%v = load volatile i32, ptr %p, align 4
%x = zext i32 %v to i64
ret i64 %x
}
; The following forms are already handled by existing upstream patterns.
define i64 @sext_already_supported(ptr %base) {
; NOUAL-LABEL: sext_already_supported:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.w $a0, $a0, 7960
; NOUAL-NEXT: ret
;
; UAL-LABEL: sext_already_supported:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a0, $a0, 7960
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
%v = load volatile i32, ptr %p, align 4
%x = sext i32 %v to i64
ret i64 %x
}
define i64 @load64_already_supported(ptr %base) {
; NOUAL-LABEL: load64_already_supported:
; NOUAL: # %bb.0:
; NOUAL-NEXT: ldptr.d $a0, $a0, 7960
; NOUAL-NEXT: ret
;
; UAL-LABEL: load64_already_supported:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.d $a0, $a0, 7960
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
%v = load volatile i64, ptr %p, align 8
ret i64 %v
}
define void @store32_already_supported(ptr %base, i32 %value) {
; NOUAL-LABEL: store32_already_supported:
; NOUAL: # %bb.0:
; NOUAL-NEXT: stptr.w $a1, $a0, 7960
; NOUAL-NEXT: ret
;
; UAL-LABEL: store32_already_supported:
; UAL: # %bb.0:
; UAL-NEXT: stptr.w $a1, $a0, 7960
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
store volatile i32 %value, ptr %p, align 4
ret void
}
define void @store64_already_supported(ptr %base, i64 %value) {
; NOUAL-LABEL: store64_already_supported:
; NOUAL: # %bb.0:
; NOUAL-NEXT: stptr.d $a1, $a0, 7960
; NOUAL-NEXT: ret
;
; UAL-LABEL: store64_already_supported:
; UAL: # %bb.0:
; UAL-NEXT: stptr.d $a1, $a0, 7960
; UAL-NEXT: ret
%p = getelementptr i8, ptr %base, i64 7960
store volatile i64 %value, ptr %p, align 8
ret void
}
; Nearby loads may share address materialization rather than
; independently selecting LDPTR.W for every offset.
; Ensure the first eligible load still selects LDPTR.W.
define i32 @four_nearby_loads(ptr %base) {
; NOUAL-LABEL: four_nearby_loads:
; NOUAL: # %bb.0:
; NOUAL-NEXT: lu12i.w $a1, 1
; NOUAL-NEXT: ori $a1, $a1, 3864
; NOUAL-NEXT: add.d $a1, $a0, $a1
; NOUAL-NEXT: ldptr.w $a0, $a0, 7960
; NOUAL-NEXT: ld.w $a2, $a1, 4
; NOUAL-NEXT: ld.w $a3, $a1, 8
; NOUAL-NEXT: ld.w $a1, $a1, 12
; NOUAL-NEXT: add.d $a0, $a0, $a2
; NOUAL-NEXT: add.d $a1, $a3, $a1
; NOUAL-NEXT: add.w $a0, $a0, $a1
; NOUAL-NEXT: ret
;
; UAL-LABEL: four_nearby_loads:
; UAL: # %bb.0:
; UAL-NEXT: ldptr.w $a1, $a0, 7960
; UAL-NEXT: ldptr.w $a2, $a0, 7964
; UAL-NEXT: ldptr.w $a3, $a0, 7968
; UAL-NEXT: ldptr.w $a0, $a0, 7972
; UAL-NEXT: add.d $a1, $a1, $a2
; UAL-NEXT: add.d $a0, $a3, $a0
; UAL-NEXT: add.w $a0, $a1, $a0
; UAL-NEXT: ret
%p0 = getelementptr i8, ptr %base, i64 7960
%p1 = getelementptr i8, ptr %base, i64 7964
%p2 = getelementptr i8, ptr %base, i64 7968
%p3 = getelementptr i8, ptr %base, i64 7972
%v0 = load volatile i32, ptr %p0, align 4
%v1 = load volatile i32, ptr %p1, align 4
%v2 = load volatile i32, ptr %p2, align 4
%v3 = load volatile i32, ptr %p3, align 4
%s0 = add i32 %v0, %v1
%s1 = add i32 %v2, %v3
%sum = add i32 %s0, %s1
ret i32 %sum
}