2017-08-09 21:44:58 +00:00
|
|
|
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -ffake-address-space-map -triple i686-pc-darwin | FileCheck -enable-var-scope -check-prefixes=COM,X86 %s
|
CodeGen: Fix address space of indirect function argument
The indirect function argument is in alloca address space in LLVM IR. However,
during Clang codegen for C++, the address space of indirect function argument
should match its address space in the source code, i.e., default addr space, even
for indirect argument. This is because destructor of the indirect argument may
be called in the caller function, and address of the indirect argument may be
taken, in either case the indirect function argument is expected to be in default
addr space, not the alloca address space.
Therefore, the indirect function argument should be mapped to the temp var
casted to default address space. The caller will cast it to alloca addr space
when passing it to the callee. In the callee, the argument is also casted to the
default address space and used.
CallArg is refactored to facilitate this fix.
Differential Revision: https://reviews.llvm.org/D34367
llvm-svn: 326946
2018-03-07 21:45:40 +00:00
|
|
|
// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN %s
|
|
|
|
// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL2.0 -O0 -finclude-default-header -triple amdgcn | FileCheck -enable-var-scope -check-prefixes=COM,AMDGCN,AMDGCN20 %s
|
2014-10-27 12:37:26 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int cells[9];
|
|
|
|
} Mat3X3;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int cells[16];
|
|
|
|
} Mat4X4;
|
|
|
|
|
2017-08-09 21:44:58 +00:00
|
|
|
typedef struct {
|
|
|
|
int cells[1024];
|
|
|
|
} Mat32X32;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int cells[4096];
|
|
|
|
} Mat64X64;
|
|
|
|
|
2017-06-29 18:47:45 +00:00
|
|
|
struct StructOneMember {
|
|
|
|
int2 x;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct StructTwoMember {
|
|
|
|
int2 x;
|
|
|
|
int2 y;
|
|
|
|
};
|
|
|
|
|
2017-08-09 21:44:58 +00:00
|
|
|
struct LargeStructOneMember {
|
|
|
|
int2 x[100];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct LargeStructTwoMember {
|
|
|
|
int2 x[40];
|
|
|
|
int2 y[20];
|
|
|
|
};
|
|
|
|
|
CodeGen: Fix address space of indirect function argument
The indirect function argument is in alloca address space in LLVM IR. However,
during Clang codegen for C++, the address space of indirect function argument
should match its address space in the source code, i.e., default addr space, even
for indirect argument. This is because destructor of the indirect argument may
be called in the caller function, and address of the indirect argument may be
taken, in either case the indirect function argument is expected to be in default
addr space, not the alloca address space.
Therefore, the indirect function argument should be mapped to the temp var
casted to default address space. The caller will cast it to alloca addr space
when passing it to the callee. In the callee, the argument is also casted to the
default address space and used.
CallArg is refactored to facilitate this fix.
Differential Revision: https://reviews.llvm.org/D34367
llvm-svn: 326946
2018-03-07 21:45:40 +00:00
|
|
|
#if __OPENCL_C_VERSION__ >= 200
|
|
|
|
struct LargeStructOneMember g_s;
|
|
|
|
#endif
|
2017-08-09 21:44:58 +00:00
|
|
|
|
|
|
|
// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret %agg.result, %struct.Mat3X3* byval align 4 %in)
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define %struct.Mat4X4 @foo([9 x i32] %in.coerce)
|
2014-10-27 12:37:26 +00:00
|
|
|
Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
|
|
|
|
Mat4X4 out;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2017-06-29 18:47:45 +00:00
|
|
|
// COM-LABEL: define {{.*}} void @ker
|
|
|
|
// Expect two mem copies: one for the argument "in", and one for
|
|
|
|
// the return value.
|
|
|
|
// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
|
|
|
|
// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
|
2017-08-09 21:44:58 +00:00
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN: load [9 x i32], [9 x i32] addrspace(1)*
|
|
|
|
// AMDGCN: call %struct.Mat4X4 @foo([9 x i32]
|
|
|
|
// AMDGCN: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)*
|
2014-10-27 12:37:26 +00:00
|
|
|
kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
|
|
|
|
out[0] = foo(in[1]);
|
|
|
|
}
|
|
|
|
|
2017-08-09 21:44:58 +00:00
|
|
|
// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret %agg.result, %struct.Mat32X32* byval align 4 %in)
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret %agg.result, %struct.Mat32X32 addrspace(5)* byval align 4 %in)
|
2017-08-09 21:44:58 +00:00
|
|
|
Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) {
|
|
|
|
Mat64X64 out;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// COM-LABEL: define {{.*}} void @ker_large
|
|
|
|
// Expect two mem copies: one for the argument "in", and one for
|
|
|
|
// the return value.
|
|
|
|
// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
|
|
|
|
// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN: call void @llvm.memcpy.p5i8.p1i8.i64(i8 addrspace(5)*
|
|
|
|
// AMDGCN: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)*
|
2017-08-09 21:44:58 +00:00
|
|
|
kernel void ker_large(global Mat32X32 *in, global Mat64X64 *out) {
|
|
|
|
out[0] = foo_large(in[1]);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define void @FuncOneMember(<2 x i32> %u.coerce)
|
2017-06-29 18:47:45 +00:00
|
|
|
void FuncOneMember(struct StructOneMember u) {
|
|
|
|
u.x = (int2)(0, 0);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %u)
|
CodeGen: Fix address space of indirect function argument
The indirect function argument is in alloca address space in LLVM IR. However,
during Clang codegen for C++, the address space of indirect function argument
should match its address space in the source code, i.e., default addr space, even
for indirect argument. This is because destructor of the indirect argument may
be called in the caller function, and address of the indirect argument may be
taken, in either case the indirect function argument is expected to be in default
addr space, not the alloca address space.
Therefore, the indirect function argument should be mapped to the temp var
casted to default address space. The caller will cast it to alloca addr space
when passing it to the callee. In the callee, the argument is also casted to the
default address space and used.
CallArg is refactored to facilitate this fix.
Differential Revision: https://reviews.llvm.org/D34367
llvm-svn: 326946
2018-03-07 21:45:40 +00:00
|
|
|
// AMDGCN-NOT: addrspacecast
|
|
|
|
// AMDGCN: store <2 x i32> %{{.*}}, <2 x i32> addrspace(5)*
|
2017-08-09 21:44:58 +00:00
|
|
|
void FuncOneLargeMember(struct LargeStructOneMember u) {
|
|
|
|
u.x[0] = (int2)(0, 0);
|
|
|
|
}
|
|
|
|
|
CodeGen: Fix address space of indirect function argument
The indirect function argument is in alloca address space in LLVM IR. However,
during Clang codegen for C++, the address space of indirect function argument
should match its address space in the source code, i.e., default addr space, even
for indirect argument. This is because destructor of the indirect argument may
be called in the caller function, and address of the indirect argument may be
taken, in either case the indirect function argument is expected to be in default
addr space, not the alloca address space.
Therefore, the indirect function argument should be mapped to the temp var
casted to default address space. The caller will cast it to alloca addr space
when passing it to the callee. In the callee, the argument is also casted to the
default address space and used.
CallArg is refactored to facilitate this fix.
Differential Revision: https://reviews.llvm.org/D34367
llvm-svn: 326946
2018-03-07 21:45:40 +00:00
|
|
|
// AMDGCN20-LABEL: define void @test_indirect_arg_globl()
|
|
|
|
// AMDGCN20: %[[byval_temp:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN20: %[[r0:.*]] = bitcast %struct.LargeStructOneMember addrspace(5)* %[[byval_temp]] to i8 addrspace(5)*
|
|
|
|
// AMDGCN20: call void @llvm.memcpy.p5i8.p1i8.i64(i8 addrspace(5)* align 8 %[[r0]], i8 addrspace(1)* align 8 bitcast (%struct.LargeStructOneMember addrspace(1)* @g_s to i8 addrspace(1)*), i64 800, i1 false)
|
|
|
|
// AMDGCN20: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[byval_temp]])
|
|
|
|
#if __OPENCL_C_VERSION__ >= 200
|
|
|
|
void test_indirect_arg_globl(void) {
|
|
|
|
FuncOneLargeMember(g_s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// AMDGCN-LABEL: define amdgpu_kernel void @test_indirect_arg_local()
|
|
|
|
// AMDGCN: %[[byval_temp:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN: %[[r0:.*]] = bitcast %struct.LargeStructOneMember addrspace(5)* %[[byval_temp]] to i8 addrspace(5)*
|
|
|
|
// AMDGCN: call void @llvm.memcpy.p5i8.p3i8.i64(i8 addrspace(5)* align 8 %[[r0]], i8 addrspace(3)* align 8 bitcast (%struct.LargeStructOneMember addrspace(3)* @test_indirect_arg_local.l_s to i8 addrspace(3)*), i64 800, i1 false)
|
|
|
|
// AMDGCN: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[byval_temp]])
|
|
|
|
kernel void test_indirect_arg_local(void) {
|
|
|
|
local struct LargeStructOneMember l_s;
|
|
|
|
FuncOneLargeMember(l_s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// AMDGCN-LABEL: define void @test_indirect_arg_private()
|
|
|
|
// AMDGCN: %[[p_s:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN-NOT: @llvm.memcpy
|
|
|
|
// AMDGCN-NEXT: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[p_s]])
|
|
|
|
void test_indirect_arg_private(void) {
|
|
|
|
struct LargeStructOneMember p_s;
|
|
|
|
FuncOneLargeMember(p_s);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define amdgpu_kernel void @KernelOneMember
|
|
|
|
// AMDGCN-SAME: (<2 x i32> %[[u_coerce:.*]])
|
|
|
|
// AMDGCN: %[[u:.*]] = alloca %struct.StructOneMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN: %[[coerce_dive:.*]] = getelementptr inbounds %struct.StructOneMember, %struct.StructOneMember addrspace(5)* %[[u]], i32 0, i32 0
|
|
|
|
// AMDGCN: store <2 x i32> %[[u_coerce]], <2 x i32> addrspace(5)* %[[coerce_dive]]
|
|
|
|
// AMDGCN: call void @FuncOneMember(<2 x i32>
|
2017-06-29 18:47:45 +00:00
|
|
|
kernel void KernelOneMember(struct StructOneMember u) {
|
|
|
|
FuncOneMember(u);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define amdgpu_kernel void @KernelLargeOneMember(
|
|
|
|
// AMDGCN: %[[U:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN: store %struct.LargeStructOneMember %u.coerce, %struct.LargeStructOneMember addrspace(5)* %[[U]], align 8
|
|
|
|
// AMDGCN: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[U]])
|
2017-08-09 21:44:58 +00:00
|
|
|
kernel void KernelLargeOneMember(struct LargeStructOneMember u) {
|
|
|
|
FuncOneLargeMember(u);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define void @FuncTwoMember(<2 x i32> %u.coerce0, <2 x i32> %u.coerce1)
|
2017-06-29 18:47:45 +00:00
|
|
|
void FuncTwoMember(struct StructTwoMember u) {
|
2017-08-09 21:44:58 +00:00
|
|
|
u.y = (int2)(0, 0);
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %u)
|
2017-08-09 21:44:58 +00:00
|
|
|
void FuncLargeTwoMember(struct LargeStructTwoMember u) {
|
|
|
|
u.y[0] = (int2)(0, 0);
|
2017-06-29 18:47:45 +00:00
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define amdgpu_kernel void @KernelTwoMember
|
|
|
|
// AMDGCN-SAME: (%struct.StructTwoMember %[[u_coerce:.*]])
|
|
|
|
// AMDGCN: %[[u:.*]] = alloca %struct.StructTwoMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN: %[[LD0:.*]] = load <2 x i32>, <2 x i32> addrspace(5)*
|
|
|
|
// AMDGCN: %[[LD1:.*]] = load <2 x i32>, <2 x i32> addrspace(5)*
|
|
|
|
// AMDGCN: call void @FuncTwoMember(<2 x i32> %[[LD0]], <2 x i32> %[[LD1]])
|
2017-06-29 18:47:45 +00:00
|
|
|
kernel void KernelTwoMember(struct StructTwoMember u) {
|
|
|
|
FuncTwoMember(u);
|
|
|
|
}
|
2017-08-09 21:44:58 +00:00
|
|
|
|
2018-02-15 19:12:41 +00:00
|
|
|
// AMDGCN-LABEL: define amdgpu_kernel void @KernelLargeTwoMember
|
|
|
|
// AMDGCN-SAME: (%struct.LargeStructTwoMember %[[u_coerce:.*]])
|
|
|
|
// AMDGCN: %[[u:.*]] = alloca %struct.LargeStructTwoMember, align 8, addrspace(5)
|
|
|
|
// AMDGCN: store %struct.LargeStructTwoMember %[[u_coerce]], %struct.LargeStructTwoMember addrspace(5)* %[[u]]
|
|
|
|
// AMDGCN: call void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %[[u]])
|
2017-08-09 21:44:58 +00:00
|
|
|
kernel void KernelLargeTwoMember(struct LargeStructTwoMember u) {
|
|
|
|
FuncLargeTwoMember(u);
|
|
|
|
}
|