blob: a98ffa07f287ffdf15a51976ac4827ddf57136d9 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=nvptx-promote-param-align -S | FileCheck %s
target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64"
target triple = "nvptx64-nvidia-cuda"
%struct.S = type { i32, i32 }
@gfp = internal global ptr null
; Kernels aren't promoted, but byval params still get an explicit ABI align (4).
define ptx_kernel void @kernel_byval(ptr byval(%struct.S) align 1 %s) {
; CHECK-LABEL: define ptx_kernel void @kernel_byval(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; External functions aren't promoted, but the byval param still gets ABI align.
define void @extern_byval(ptr byval(%struct.S) %s) {
; CHECK-LABEL: define void @extern_byval(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; Internal byval: explicit ABI align (4) plus alignstack(16) promotion.
define internal void @internal_byval(ptr byval(%struct.S) %s) {
; CHECK-LABEL: define internal void @internal_byval(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 alignstack(16) [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; Already aligned above 16: unchanged.
define internal void @internal_byval_high_align(ptr byval(%struct.S) align 32 %s) {
; CHECK-LABEL: define internal void @internal_byval_high_align(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 32 [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; Internal aggregate (non-byval) parameter: promoted to alignstack(16).
define internal void @internal_aggr(%struct.S %s) {
; CHECK-LABEL: define internal void @internal_aggr(
; CHECK-SAME: [[STRUCT_S:%.*]] alignstack(16) [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; Scalars gain nothing from vectorization: untouched.
define internal void @internal_scalar(i32 %x, ptr %p) {
; CHECK-LABEL: define internal void @internal_scalar(
; CHECK-SAME: i32 [[X:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; Internal aggregate return value: promoted to alignstack(16).
define internal %struct.S @internal_ret() {
; CHECK-LABEL: define internal alignstack(16) %struct.S @internal_ret() {
; CHECK-NEXT: ret [[STRUCT_S:%.*]] zeroinitializer
;
ret %struct.S zeroinitializer
}
; An explicit stackalign takes precedence.
define internal void @internal_explicit_stackalign(%struct.S alignstack(8) %s) {
; CHECK-LABEL: define internal void @internal_explicit_stackalign(
; CHECK-SAME: [[STRUCT_S:%.*]] alignstack(8) [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
; The promoted alignment is propagated to constant-offset byval loads.
define internal void @internal_load_propagation(ptr byval(%struct.S) %s) {
; CHECK-LABEL: define internal void @internal_load_propagation(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 alignstack(16) [[S:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[S]], align 16
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[S]], i64 0, i32 1
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret void
;
%v1 = load i32, ptr %s, align 1
%gep = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1
%v2 = load i32, ptr %gep, align 1
ret void
}
; External byval loads get the ABI align (4) propagated, avoiding byte-wise loads.
define void @extern_load_propagation(ptr byval(%struct.S) %s) {
; CHECK-LABEL: define void @extern_load_propagation(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 [[S:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[S]], align 4
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[S]], i64 0, i32 1
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret void
;
%v1 = load i32, ptr %s, align 1
%gep = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1
%v2 = load i32, ptr %gep, align 1
ret void
}
; Kernel byval loads get the ABI align (4) propagated.
define ptx_kernel void @kernel_load_propagation(ptr byval(%struct.S) align 1 %s) {
; CHECK-LABEL: define ptx_kernel void @kernel_load_propagation(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 [[S:%.*]]) {
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[S]], align 4
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[S]], i64 0, i32 1
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: ret void
;
%v1 = load i32, ptr %s, align 1
%gep = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1
%v2 = load i32, ptr %gep, align 1
ret void
}
; The promoted alignment is mirrored onto direct call sites.
define internal %struct.S @callee(%struct.S %a) {
; CHECK-LABEL: define internal alignstack(16) %struct.S @callee(
; CHECK-SAME: [[STRUCT_S:%.*]] alignstack(16) [[A:%.*]]) {
; CHECK-NEXT: ret [[STRUCT_S]] [[A]]
;
ret %struct.S %a
}
define void @caller() {
; CHECK-LABEL: define void @caller() {
; CHECK-NEXT: [[R:%.*]] = call alignstack(16) [[STRUCT_S:%.*]] @[[CALLEE:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]]([[STRUCT_S]] alignstack(16) zeroinitializer)
; CHECK-NEXT: ret void
;
%r = call %struct.S @callee(%struct.S zeroinitializer)
ret void
}
; A byval call matching the callee's ABI is promoted and mirrored onto the call.
define internal void @byval_match(ptr byval(%struct.S) %s) {
; CHECK-LABEL: define internal void @byval_match(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 4 alignstack(16) [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
define void @byval_match_caller(ptr %p) {
; CHECK-LABEL: define void @byval_match_caller(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: call void @byval_match(ptr byval([[STRUCT_S:%.*]]) alignstack(16) [[P]])
; CHECK-NEXT: ret void
;
call void @byval_match(ptr byval(%struct.S) %p)
ret void
}
; A byval call whose align differs from the callee is not promoted.
define internal void @byval_abi_mismatch(ptr byval(%struct.S) align 8 %s) {
; CHECK-LABEL: define internal void @byval_abi_mismatch(
; CHECK-SAME: ptr byval([[STRUCT_S:%.*]]) align 8 [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
define void @byval_abi_mismatch_caller(ptr %p) {
; CHECK-LABEL: define void @byval_abi_mismatch_caller(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: call void @byval_abi_mismatch(ptr byval([[STRUCT_S:%.*]]) align 4 [[P]])
; CHECK-NEXT: ret void
;
call void @byval_abi_mismatch(ptr byval(%struct.S) align 4 %p)
ret void
}
; Address-taken functions aren't promoted (an indirect call wouldn't see them).
define internal void @addr_taken(%struct.S %s) {
; CHECK-LABEL: define internal void @addr_taken(
; CHECK-SAME: [[STRUCT_S:%.*]] [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
define void @take_address() {
; CHECK-LABEL: define void @take_address() {
; CHECK-NEXT: store ptr @addr_taken, ptr @gfp, align 8
; CHECK-NEXT: ret void
;
store ptr @addr_taken, ptr @gfp
ret void
}
; A type-mismatched call is lowered as indirect, so the callee isn't promoted.
define internal void @type_mismatch(%struct.S %s) {
; CHECK-LABEL: define internal void @type_mismatch(
; CHECK-SAME: [[STRUCT_S:%.*]] [[S:%.*]]) {
; CHECK-NEXT: ret void
;
ret void
}
define void @mismatch_caller() {
; CHECK-LABEL: define void @mismatch_caller() {
; CHECK-NEXT: call void @type_mismatch(i64 0)
; CHECK-NEXT: ret void
;
call void @type_mismatch(i64 0)
ret void
}