blob: db259c60cc70120a708e72184219719853aa65ab [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -amdgpu-lower-buffer-fat-pointers < %s | FileCheck %s
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers < %s | FileCheck %s
target triple = "amdgpu9.00--"
define void @scalar_copy(ptr %a, ptr %b) {
; CHECK-LABEL: define void @scalar_copy
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[X:%.*]] = load i160, ptr [[A]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[X]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[X_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[X_PTR_OFF:%.*]] = trunc i160 [[X]] to i32
; CHECK-NEXT: [[B11:%.*]] = getelementptr i8, ptr [[B]], i64 32
; CHECK-NEXT: store i160 [[X]], ptr [[B11]], align 32
; CHECK-NEXT: ret void
;
%x = load ptr addrspace(7), ptr %a
%b1 = getelementptr ptr addrspace(7), ptr %b, i64 1
store ptr addrspace(7) %x, ptr %b1
ret void
}
define void @vector_copy(ptr %a, ptr %b) {
; CHECK-LABEL: define void @vector_copy
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[X:%.*]] = load <4 x i160>, ptr [[A]], align 128
; CHECK-NEXT: [[TMP1:%.*]] = lshr <4 x i160> [[X]], splat (i160 32)
; CHECK-NEXT: [[TMP2:%.*]] = trunc <4 x i160> [[TMP1]] to <4 x i128>
; CHECK-NEXT: [[X_PTR_RSRC:%.*]] = inttoptr <4 x i128> [[TMP2]] to <4 x ptr addrspace(8)>
; CHECK-NEXT: [[X_PTR_OFF:%.*]] = trunc <4 x i160> [[X]] to <4 x i32>
; CHECK-NEXT: [[B11:%.*]] = getelementptr i8, ptr [[B]], i64 256
; CHECK-NEXT: store <4 x i160> [[X]], ptr [[B11]], align 128
; CHECK-NEXT: ret void
;
%x = load <4 x ptr addrspace(7)>, ptr %a
%b1 = getelementptr <4 x ptr addrspace(7)>, ptr %b, i64 2
store <4 x ptr addrspace(7)> %x, ptr %b1
ret void
}
define void @alloca(ptr %a, ptr %b) {
; CHECK-LABEL: define void @alloca
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [160 x i8], align 32, addrspace(5)
; CHECK-NEXT: [[X:%.*]] = load i160, ptr [[A]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[X]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[X_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[X_PTR_OFF:%.*]] = trunc i160 [[X]] to i32
; CHECK-NEXT: [[L1:%.*]] = getelementptr i8, ptr addrspace(5) [[ALLOCA]], i32 32
; CHECK-NEXT: store i160 [[X]], ptr addrspace(5) [[L1]], align 32
; CHECK-NEXT: [[Y:%.*]] = load i160, ptr addrspace(5) [[L1]], align 32
; CHECK-NEXT: [[TMP3:%.*]] = lshr i160 [[Y]], 32
; CHECK-NEXT: [[TMP4:%.*]] = trunc i160 [[TMP3]] to i128
; CHECK-NEXT: [[Y_PTR_RSRC:%.*]] = inttoptr i128 [[TMP4]] to ptr addrspace(8)
; CHECK-NEXT: [[Y_PTR_OFF:%.*]] = trunc i160 [[Y]] to i32
; CHECK-NEXT: store i160 [[Y]], ptr [[B]], align 32
; CHECK-NEXT: ret void
;
%alloca = alloca [5 x ptr addrspace(7)], addrspace(5)
%x = load ptr addrspace(7), ptr %a
%l = getelementptr ptr addrspace(7), ptr addrspace(5) %alloca, i32 1
store ptr addrspace(7) %x, ptr addrspace(5) %l
%y = load ptr addrspace(7), ptr addrspace(5) %l
store ptr addrspace(7) %y, ptr %b
ret void
}
define void @complex_copy(ptr %a, ptr %b) {
; CHECK-LABEL: define void @complex_copy
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[X_0_0:%.*]] = load i160, ptr [[A]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[X_0_0]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[X_0_0_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[X_0_0_PTR_OFF:%.*]] = trunc i160 [[X_0_0]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[X_0_0_PTR_RSRC]], 0
; CHECK-NEXT: [[X_0_0_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[X_0_0_PTR_OFF]], 1
; CHECK-NEXT: [[X_0_0_AGG:%.*]] = insertvalue { [2 x { ptr addrspace(8), i32 }], i32, { ptr addrspace(8), i32 } } poison, { ptr addrspace(8), i32 } [[X_0_0_PTR]], 0, 0
; CHECK-NEXT: [[A_OFF_32:%.*]] = getelementptr nuw i8, ptr [[A]], i64 32
; CHECK-NEXT: [[X_0_1:%.*]] = load i160, ptr [[A_OFF_32]], align 32
; CHECK-NEXT: [[TMP4:%.*]] = lshr i160 [[X_0_1]], 32
; CHECK-NEXT: [[TMP5:%.*]] = trunc i160 [[TMP4]] to i128
; CHECK-NEXT: [[X_0_1_PTR_RSRC:%.*]] = inttoptr i128 [[TMP5]] to ptr addrspace(8)
; CHECK-NEXT: [[X_0_1_PTR_OFF:%.*]] = trunc i160 [[X_0_1]] to i32
; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[X_0_1_PTR_RSRC]], 0
; CHECK-NEXT: [[X_0_1_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP6]], i32 [[X_0_1_PTR_OFF]], 1
; CHECK-NEXT: [[X_0_1_AGG:%.*]] = insertvalue { [2 x { ptr addrspace(8), i32 }], i32, { ptr addrspace(8), i32 } } [[X_0_0_AGG]], { ptr addrspace(8), i32 } [[X_0_1_PTR]], 0, 1
; CHECK-NEXT: [[A_OFF_64:%.*]] = getelementptr nuw i8, ptr [[A]], i64 64
; CHECK-NEXT: [[X_1:%.*]] = load i32, ptr [[A_OFF_64]], align 32
; CHECK-NEXT: [[X_1_AGG:%.*]] = insertvalue { [2 x { ptr addrspace(8), i32 }], i32, { ptr addrspace(8), i32 } } [[X_0_1_AGG]], i32 [[X_1]], 1
; CHECK-NEXT: [[A_OFF_96:%.*]] = getelementptr nuw i8, ptr [[A]], i64 96
; CHECK-NEXT: [[X_2:%.*]] = load i160, ptr [[A_OFF_96]], align 32
; CHECK-NEXT: [[TMP7:%.*]] = lshr i160 [[X_2]], 32
; CHECK-NEXT: [[TMP8:%.*]] = trunc i160 [[TMP7]] to i128
; CHECK-NEXT: [[X_2_PTR_RSRC:%.*]] = inttoptr i128 [[TMP8]] to ptr addrspace(8)
; CHECK-NEXT: [[X_2_PTR_OFF:%.*]] = trunc i160 [[X_2]] to i32
; CHECK-NEXT: [[TMP9:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[X_2_PTR_RSRC]], 0
; CHECK-NEXT: [[X_2_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP9]], i32 [[X_2_PTR_OFF]], 1
; CHECK-NEXT: [[X_2_AGG:%.*]] = insertvalue { [2 x { ptr addrspace(8), i32 }], i32, { ptr addrspace(8), i32 } } [[X_1_AGG]], { ptr addrspace(8), i32 } [[X_2_PTR]], 2
; CHECK-NEXT: store i160 [[X_0_0]], ptr [[B]], align 32
; CHECK-NEXT: [[B_OFF_32:%.*]] = getelementptr nuw i8, ptr [[B]], i64 32
; CHECK-NEXT: store i160 [[X_0_1]], ptr [[B_OFF_32]], align 32
; CHECK-NEXT: [[B_OFF_64:%.*]] = getelementptr nuw i8, ptr [[B]], i64 64
; CHECK-NEXT: store i32 [[X_1]], ptr [[B_OFF_64]], align 32
; CHECK-NEXT: [[B_OFF_96:%.*]] = getelementptr nuw i8, ptr [[B]], i64 96
; CHECK-NEXT: store i160 [[X_2]], ptr [[B_OFF_96]], align 32
; CHECK-NEXT: ret void
;
%x = load {[2 x ptr addrspace(7)], i32, ptr addrspace(7)}, ptr %a
store {[2 x ptr addrspace(7)], i32, ptr addrspace(7)} %x, ptr %b
ret void
}
;; The conversion of %p for the store in %then must not be reused by the
;; store in %else, since neither block dominates the other.
define void @two_stores_same_value(i1 %cond, ptr addrspace(7) %p, ptr %a, ptr %b) {
; CHECK-LABEL: define void @two_stores_same_value
; CHECK-SAME: (i1 [[COND:%.*]], { ptr addrspace(8), i32 } [[P:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 0
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 1
; CHECK-NEXT: br i1 [[COND]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: [[P_INT_RSRC:%.*]] = ptrtoint ptr addrspace(8) [[P_RSRC]] to i160
; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i160 [[P_INT_RSRC]], 32
; CHECK-NEXT: [[P_INT_OFF:%.*]] = zext i32 [[P_OFF]] to i160
; CHECK-NEXT: [[P_INT:%.*]] = or i160 [[TMP0]], [[P_INT_OFF]]
; CHECK-NEXT: store i160 [[P_INT]], ptr [[A]], align 32
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: else:
; CHECK-NEXT: [[P_INT1_RSRC:%.*]] = ptrtoint ptr addrspace(8) [[P_RSRC]] to i160
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i160 [[P_INT1_RSRC]], 32
; CHECK-NEXT: [[P_INT1_OFF:%.*]] = zext i32 [[P_OFF]] to i160
; CHECK-NEXT: [[P_INT1:%.*]] = or i160 [[TMP1]], [[P_INT1_OFF]]
; CHECK-NEXT: store i160 [[P_INT1]], ptr [[B]], align 32
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %then, label %else
then:
store ptr addrspace(7) %p, ptr %a
br label %exit
else:
store ptr addrspace(7) %p, ptr %b
br label %exit
exit:
ret void
}
%struct.has_p7 = type { i32, ptr addrspace(7) }
;; ptr addrspace(7)'s 256-bit alignment puts field 1 at byte offset 32;
;; instcombine bakes that into an i8 GEP before this pass runs, so both
;; functions below must load at offset 32.
define ptr addrspace(7) @struct_field_baked_offset(ptr addrspace(5) %agg) {
; CHECK-LABEL: define { ptr addrspace(8), i32 } @struct_field_baked_offset
; CHECK-SAME: (ptr addrspace(5) [[AGG:%.*]]) {
; CHECK-NEXT: [[F:%.*]] = getelementptr inbounds i8, ptr addrspace(5) [[AGG]], i32 32
; CHECK-NEXT: [[P:%.*]] = load i160, ptr addrspace(5) [[F]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[P]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[P_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[P_PTR_OFF:%.*]] = trunc i160 [[P]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[P_PTR_RSRC]], 0
; CHECK-NEXT: [[P_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[P_PTR_OFF]], 1
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[P_PTR]]
;
%f = getelementptr inbounds i8, ptr addrspace(5) %agg, i32 32
%p = load ptr addrspace(7), ptr addrspace(5) %f, align 32
ret ptr addrspace(7) %p
}
define ptr addrspace(7) @struct_field_gep(ptr addrspace(5) %agg) {
; CHECK-LABEL: define { ptr addrspace(8), i32 } @struct_field_gep
; CHECK-SAME: (ptr addrspace(5) [[AGG:%.*]]) {
; CHECK-NEXT: [[F1:%.*]] = getelementptr inbounds i8, ptr addrspace(5) [[AGG]], i32 32
; CHECK-NEXT: [[P:%.*]] = load i160, ptr addrspace(5) [[F1]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[P]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[P_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[P_PTR_OFF:%.*]] = trunc i160 [[P]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[P_PTR_RSRC]], 0
; CHECK-NEXT: [[P_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[P_PTR_OFF]], 1
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[P_PTR]]
;
%f = getelementptr inbounds %struct.has_p7, ptr addrspace(5) %agg, i32 0, i32 1
%p = load ptr addrspace(7), ptr addrspace(5) %f, align 32
ret ptr addrspace(7) %p
}
define void @struct_copy(ptr addrspace(5) %a, ptr addrspace(5) %b) {
; CHECK-LABEL: define void @struct_copy
; CHECK-SAME: (ptr addrspace(5) [[A:%.*]], ptr addrspace(5) [[B:%.*]]) {
; CHECK-NEXT: [[X_0:%.*]] = load i32, ptr addrspace(5) [[A]], align 32
; CHECK-NEXT: [[X_0_AGG:%.*]] = insertvalue [[TMP0:%.*]] poison, i32 [[X_0]], 0
; CHECK-NEXT: [[A_OFF_32:%.*]] = getelementptr nuw i8, ptr addrspace(5) [[A]], i32 32
; CHECK-NEXT: [[X_1:%.*]] = load i160, ptr addrspace(5) [[A_OFF_32]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[X_1]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[X_1_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[X_1_PTR_OFF:%.*]] = trunc i160 [[X_1]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[X_1_PTR_RSRC]], 0
; CHECK-NEXT: [[X_1_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[X_1_PTR_OFF]], 1
; CHECK-NEXT: [[X_1_AGG:%.*]] = insertvalue [[TMP0]] [[X_0_AGG]], { ptr addrspace(8), i32 } [[X_1_PTR]], 1
; CHECK-NEXT: store i32 [[X_0]], ptr addrspace(5) [[B]], align 32
; CHECK-NEXT: [[B_OFF_32:%.*]] = getelementptr nuw i8, ptr addrspace(5) [[B]], i32 32
; CHECK-NEXT: store i160 [[X_1]], ptr addrspace(5) [[B_OFF_32]], align 32
; CHECK-NEXT: ret void
;
%x = load %struct.has_p7, ptr addrspace(5) %a, align 32
store %struct.has_p7 %x, ptr addrspace(5) %b, align 32
ret void
}
;; sizeof(%struct.has_p7) is 64; a frontend-emitted memcpy of that constant
;; size must not overrun the lowered alloca.
define void @struct_alloca_size() {
; CHECK-LABEL: define void @struct_alloca_size() {
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [64 x i8], align 32, addrspace(5)
; CHECK-NEXT: ret void
;
%alloca = alloca %struct.has_p7, align 32, addrspace(5)
ret void
}
;; Zero-sized members access no bytes and must not produce leaf accesses of
;; their own (the buffer intrinsics can't be mangled for {}).
define void @zero_size_member(ptr %a, ptr %b) {
; CHECK-LABEL: define void @zero_size_member
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT: [[X_0:%.*]] = load i160, ptr [[A]], align 32
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[X_0]], 32
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
; CHECK-NEXT: [[X_0_PTR_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
; CHECK-NEXT: [[X_0_PTR_OFF:%.*]] = trunc i160 [[X_0]] to i32
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[X_0_PTR_RSRC]], 0
; CHECK-NEXT: [[X_0_PTR:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[X_0_PTR_OFF]], 1
; CHECK-NEXT: [[X_0_AGG:%.*]] = insertvalue { { ptr addrspace(8), i32 }, {}, [0 x i32] } poison, { ptr addrspace(8), i32 } [[X_0_PTR]], 0
; CHECK-NEXT: store i160 [[X_0]], ptr [[B]], align 32
; CHECK-NEXT: ret void
;
%x = load { ptr addrspace(7), {}, [0 x i32] }, ptr %a
store { ptr addrspace(7), {}, [0 x i32] } %x, ptr %b
ret void
}
;; <4 x i160> has the same allocation size as <4 x p7>, so vector allocas
;; keep the remapped vector type instead of decaying to a byte array.
define void @vector_alloca() {
; CHECK-LABEL: define void @vector_alloca() {
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca <4 x i160>, align 128, addrspace(5)
; CHECK-NEXT: ret void
;
%alloca = alloca <4 x ptr addrspace(7)>, addrspace(5)
ret void
}
;; GEPs over p7 itself step by its 32-byte allocation size, not by the
;; 24-byte allocation size of i160.
define ptr addrspace(5) @gep_p7_stride(ptr addrspace(5) %p, i32 %i) {
; CHECK-LABEL: define ptr addrspace(5) @gep_p7_stride
; CHECK-SAME: (ptr addrspace(5) [[P:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT: [[Q_IDX:%.*]] = mul i32 [[I]], 32
; CHECK-NEXT: [[Q1:%.*]] = getelementptr i8, ptr addrspace(5) [[P]], i32 [[Q_IDX]]
; CHECK-NEXT: ret ptr addrspace(5) [[Q1]]
;
%q = getelementptr ptr addrspace(7), ptr addrspace(5) %p, i32 %i
ret ptr addrspace(5) %q
}