blob: 4825957d2270ab6a6ade0026da40c4516ed5a31c [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -mtriple=amdgpu7.00-amd-amdhsa -passes=sroa,amdgpu-promote-alloca < %s | FileCheck %s
; An object written one element at a time but read back in wider pieces still
; promotes: the wide access is split across elements the same way a vector
; access is.
define amdgpu_kernel void @store_i32_load_i64(ptr addrspace(1) %out, i32 %i, i32 %v) {
; CHECK-LABEL: define amdgpu_kernel void @store_i32_load_i64(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], i32 [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = freeze <8 x i32> poison
; CHECK-NEXT: [[TMP1:%.*]] = insertelement <8 x i32> [[A]], i32 [[V]], i32 [[I]]
; CHECK-NEXT: [[J:%.*]] = shl i32 [[I]], 1
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <8 x i32> [[TMP1]] to <4 x i64>
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[J]], 1
; CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x i64> [[TMP2]], i32 [[TMP3]]
; CHECK-NEXT: store i64 [[TMP4]], ptr addrspace(1) [[OUT]], align 8
; CHECK-NEXT: ret void
;
%a = alloca [8 x i32], align 16, addrspace(5)
%p = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %i
store i32 %v, ptr addrspace(5) %p, align 4
%j = shl i32 %i, 1
%q = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %j
%l = load i64, ptr addrspace(5) %q, align 8
store i64 %l, ptr addrspace(1) %out, align 8
ret void
}
; The same in the other direction: a wide store and narrow loads.
define amdgpu_kernel void @store_i64_load_i32(ptr addrspace(1) %out, i32 %i, i64 %v) {
; CHECK-LABEL: define amdgpu_kernel void @store_i64_load_i32(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], i64 [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = freeze <8 x i32> poison
; CHECK-NEXT: [[J:%.*]] = shl i32 [[I]], 1
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[V]] to <2 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i32> [[TMP1]], i64 0
; CHECK-NEXT: [[TMP3:%.*]] = insertelement <8 x i32> [[A]], i32 [[TMP2]], i32 [[J]]
; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[J]], 1
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x i32> [[TMP1]], i64 1
; CHECK-NEXT: [[TMP6:%.*]] = insertelement <8 x i32> [[TMP3]], i32 [[TMP5]], i32 [[TMP4]]
; CHECK-NEXT: [[TMP7:%.*]] = extractelement <8 x i32> [[TMP6]], i32 [[I]]
; CHECK-NEXT: store i32 [[TMP7]], ptr addrspace(1) [[OUT]], align 4
; CHECK-NEXT: ret void
;
%a = alloca [8 x i32], align 16, addrspace(5)
%j = shl i32 %i, 1
%p = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %j
store i64 %v, ptr addrspace(5) %p, align 8
%q = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %i
%l = load i32, ptr addrspace(5) %q, align 4
store i32 %l, ptr addrspace(1) %out, align 4
ret void
}
; A span that is not a power of two: i96 covers three elements
define amdgpu_kernel void @store_i96_load_i32(ptr addrspace(1) %out, i32 %i, i96 %v) {
; CHECK-LABEL: define amdgpu_kernel void @store_i96_load_i32(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], i96 [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = freeze <8 x i32> poison
; CHECK-NEXT: [[J:%.*]] = mul i32 [[I]], 3
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i96 [[V]] to <3 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = extractelement <3 x i32> [[TMP1]], i64 0
; CHECK-NEXT: [[TMP3:%.*]] = insertelement <8 x i32> [[A]], i32 [[TMP2]], i32 [[J]]
; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[J]], 1
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP1]], i64 1
; CHECK-NEXT: [[TMP6:%.*]] = insertelement <8 x i32> [[TMP3]], i32 [[TMP5]], i32 [[TMP4]]
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[J]], 2
; CHECK-NEXT: [[TMP8:%.*]] = extractelement <3 x i32> [[TMP1]], i64 2
; CHECK-NEXT: [[TMP9:%.*]] = insertelement <8 x i32> [[TMP6]], i32 [[TMP8]], i32 [[TMP7]]
; CHECK-NEXT: [[TMP10:%.*]] = extractelement <8 x i32> [[TMP9]], i32 [[I]]
; CHECK-NEXT: store i32 [[TMP10]], ptr addrspace(1) [[OUT]], align 4
; CHECK-NEXT: ret void
;
%a = alloca [8 x i32], align 16, addrspace(5)
%j = mul i32 %i, 3
%p = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %j
store i96 %v, ptr addrspace(5) %p, align 4
%q = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %i
%l = load i32, ptr addrspace(5) %q, align 4
store i32 %l, ptr addrspace(1) %out, align 4
ret void
}
; <3 x i32> has the same 12-byte footprint as i96 and already went down the
; subvector path before this change: the two must expand identically.
define amdgpu_kernel void @store_v3i32_load_i32(ptr addrspace(1) %out, i32 %i, <3 x i32> %v) {
; CHECK-LABEL: define amdgpu_kernel void @store_v3i32_load_i32(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], <3 x i32> [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = freeze <8 x i32> poison
; CHECK-NEXT: [[J:%.*]] = mul i32 [[I]], 3
; CHECK-NEXT: [[TMP1:%.*]] = extractelement <3 x i32> [[V]], i64 0
; CHECK-NEXT: [[TMP2:%.*]] = insertelement <8 x i32> [[A]], i32 [[TMP1]], i32 [[J]]
; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[J]], 1
; CHECK-NEXT: [[TMP4:%.*]] = extractelement <3 x i32> [[V]], i64 1
; CHECK-NEXT: [[TMP5:%.*]] = insertelement <8 x i32> [[TMP2]], i32 [[TMP4]], i32 [[TMP3]]
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[J]], 2
; CHECK-NEXT: [[TMP7:%.*]] = extractelement <3 x i32> [[V]], i64 2
; CHECK-NEXT: [[TMP8:%.*]] = insertelement <8 x i32> [[TMP5]], i32 [[TMP7]], i32 [[TMP6]]
; CHECK-NEXT: [[TMP9:%.*]] = extractelement <8 x i32> [[TMP8]], i32 [[I]]
; CHECK-NEXT: store i32 [[TMP9]], ptr addrspace(1) [[OUT]], align 4
; CHECK-NEXT: ret void
;
%a = alloca [8 x i32], align 16, addrspace(5)
%j = mul i32 %i, 3
%p = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %j
store <3 x i32> %v, ptr addrspace(5) %p, align 4
%q = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %i
%l = load i32, ptr addrspace(5) %q, align 4
store i32 %l, ptr addrspace(1) %out, align 4
ret void
}
; Negative: i48 spans six bytes, which is not a whole number of i32 elements.
define amdgpu_kernel void @unaligned_span_not_promoted(ptr addrspace(1) %out, i32 %i, i32 %v) {
; CHECK-LABEL: define amdgpu_kernel void @unaligned_span_not_promoted(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], i32 [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = alloca [8 x i32], align 16, addrspace(5)
; CHECK-NEXT: [[P:%.*]] = getelementptr [8 x i32], ptr addrspace(5) [[A]], i32 0, i32 [[I]]
; CHECK-NEXT: store i32 [[V]], ptr addrspace(5) [[P]], align 4
; CHECK-NEXT: [[J:%.*]] = shl i32 [[I]], 1
; CHECK-NEXT: [[Q:%.*]] = getelementptr [8 x i32], ptr addrspace(5) [[A]], i32 0, i32 [[J]]
; CHECK-NEXT: [[L:%.*]] = load i48, ptr addrspace(5) [[Q]], align 8
; CHECK-NEXT: store i48 [[L]], ptr addrspace(1) [[OUT]], align 8
; CHECK-NEXT: ret void
;
%a = alloca [8 x i32], align 16, addrspace(5)
%p = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %i
store i32 %v, ptr addrspace(5) %p, align 4
%j = shl i32 %i, 1
%q = getelementptr [8 x i32], ptr addrspace(5) %a, i32 0, i32 %j
%l = load i48, ptr addrspace(5) %q, align 8
store i48 %l, ptr addrspace(1) %out, align 8
ret void
}
; Negative: i33 is stored in five bytes but only 33 of those bits are value
; bits, so there is no bitcast between it and a run of five elements.
define amdgpu_kernel void @padded_access_not_promoted(ptr addrspace(1) %out, i32 %i, i8 %v) {
; CHECK-LABEL: define amdgpu_kernel void @padded_access_not_promoted(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], i8 [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = alloca [16 x i8], align 16, addrspace(5)
; CHECK-NEXT: [[P:%.*]] = getelementptr [16 x i8], ptr addrspace(5) [[A]], i32 0, i32 [[I]]
; CHECK-NEXT: store i8 [[V]], ptr addrspace(5) [[P]], align 1
; CHECK-NEXT: [[J:%.*]] = mul i32 [[I]], 5
; CHECK-NEXT: [[Q:%.*]] = getelementptr [16 x i8], ptr addrspace(5) [[A]], i32 0, i32 [[J]]
; CHECK-NEXT: [[L:%.*]] = load i33, ptr addrspace(5) [[Q]], align 1
; CHECK-NEXT: store i33 [[L]], ptr addrspace(1) [[OUT]], align 8
; CHECK-NEXT: ret void
;
%a = alloca [16 x i8], align 16, addrspace(5)
%p = getelementptr [16 x i8], ptr addrspace(5) %a, i32 0, i32 %i
store i8 %v, ptr addrspace(5) %p, align 1
%j = mul i32 %i, 5
%q = getelementptr [16 x i8], ptr addrspace(5) %a, i32 0, i32 %j
%l = load i33, ptr addrspace(5) %q, align 1
store i33 %l, ptr addrspace(1) %out, align 8
ret void
}
; The elements do not have to be integers: an i64 spans two 32-bit pointers,
; and the pieces are recovered with a ptrtoint rather than a plain bitcast.
define amdgpu_kernel void @store_ptr_load_i64(ptr addrspace(1) %out, i32 %i, ptr addrspace(5) %v) {
; CHECK-LABEL: define amdgpu_kernel void @store_ptr_load_i64(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], ptr addrspace(5) [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = freeze <8 x ptr addrspace(5)> poison
; CHECK-NEXT: [[TMP1:%.*]] = insertelement <8 x ptr addrspace(5)> [[A]], ptr addrspace(5) [[V]], i32 [[I]]
; CHECK-NEXT: [[J:%.*]] = shl i32 [[I]], 1
; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint <8 x ptr addrspace(5)> [[TMP1]] to <8 x i32>
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i32> [[TMP2]] to <4 x i64>
; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 [[J]], 1
; CHECK-NEXT: [[TMP5:%.*]] = extractelement <4 x i64> [[TMP3]], i32 [[TMP4]]
; CHECK-NEXT: store i64 [[TMP5]], ptr addrspace(1) [[OUT]], align 8
; CHECK-NEXT: ret void
;
%a = alloca [8 x ptr addrspace(5)], align 16, addrspace(5)
%p = getelementptr [8 x ptr addrspace(5)], ptr addrspace(5) %a, i32 0, i32 %i
store ptr addrspace(5) %v, ptr addrspace(5) %p, align 4
%j = shl i32 %i, 1
%q = getelementptr [8 x ptr addrspace(5)], ptr addrspace(5) %a, i32 0, i32 %j
%l = load i64, ptr addrspace(5) %q, align 8
store i64 %l, ptr addrspace(1) %out, align 8
ret void
}
; Negative: a double is the same size as a 64-bit pointer, so it covers exactly
; one element and is not split. There is no cast between the two types, so the
; access is still rejected.
define amdgpu_kernel void @same_size_element_not_castable(ptr addrspace(1) %out, i32 %i, ptr %v) {
; CHECK-LABEL: define amdgpu_kernel void @same_size_element_not_castable(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i32 [[I:%.*]], ptr [[V:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = alloca [8 x ptr], align 16, addrspace(5)
; CHECK-NEXT: [[P:%.*]] = getelementptr [8 x ptr], ptr addrspace(5) [[A]], i32 0, i32 [[I]]
; CHECK-NEXT: store ptr [[V]], ptr addrspace(5) [[P]], align 8
; CHECK-NEXT: [[J:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: [[Q:%.*]] = getelementptr [8 x ptr], ptr addrspace(5) [[A]], i32 0, i32 [[J]]
; CHECK-NEXT: [[L:%.*]] = load double, ptr addrspace(5) [[Q]], align 8
; CHECK-NEXT: store double [[L]], ptr addrspace(1) [[OUT]], align 8
; CHECK-NEXT: ret void
;
%a = alloca [8 x ptr], align 16, addrspace(5)
%p = getelementptr [8 x ptr], ptr addrspace(5) %a, i32 0, i32 %i
store ptr %v, ptr addrspace(5) %p, align 8
%j = add i32 %i, 1
%q = getelementptr [8 x ptr], ptr addrspace(5) %a, i32 0, i32 %j
%l = load double, ptr addrspace(5) %q, align 8
store double %l, ptr addrspace(1) %out, align 8
ret void
}