Yaxun (Sam) Liu b008ea304d [CUDA][HIP] Fix device variable linkage
For -fgpu-rdc, shadow variables should not be internalized, otherwise
they cannot be accessed by other TUs. This is necessary because
the shadow variable of external device variables are always
emitted as undefined symbols, which need to resolve to a global
symbols.

Managed variables need to be emitted as undefined symbols
in device compilations.

Reviewed by: Artem Belevich

Differential Revision: https://reviews.llvm.org/D95901
2021-02-05 15:11:12 -05:00

122 lines
4.3 KiB
Plaintext

// REQUIRES: x86-registered-target, amdgpu-registered-target
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \
// RUN: -emit-llvm -o - -x hip %s | FileCheck \
// RUN: -check-prefixes=DEV %s
// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device -std=c++11 \
// RUN: -emit-llvm -fgpu-rdc -o - -x hip %s | FileCheck \
// RUN: -check-prefixes=DEV %s
// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \
// RUN: -emit-llvm -o - -x hip %s | FileCheck \
// RUN: -check-prefixes=HOST,NORDC %s
// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \
// RUN: -emit-llvm -fgpu-rdc -o - -x hip %s | FileCheck \
// RUN: -check-prefixes=HOST,RDC %s
#include "Inputs/cuda.h"
// DEV-DAG: @x = external addrspace(1) externally_initialized global i32
// NORDC-DAG: @x = internal global i32 1
// RDC-DAG: @x = dso_local global i32 1
// NORDC-DAG: @x.managed = internal global i32* null
// RDC-DAG: @x.managed = dso_local global i32* null
// HOST-DAG: @[[DEVNAMEX:[0-9]+]] = {{.*}}c"x\00"
struct vec {
float x,y,z;
};
__managed__ int x = 1;
__managed__ vec v[100];
__managed__ vec v2[100] = {{1, 1, 1}};
// DEV-DAG: @ex = external addrspace(1) global i32
// HOST-DAG: @ex = external global i32
extern __managed__ int ex;
// DEV-DAG: @_ZL2sx = external addrspace(1) externally_initialized global i32
// HOST-DAG: @_ZL2sx = internal global i32 1
// HOST-DAG: @_ZL2sx.managed = internal global i32* null
static __managed__ int sx = 1;
// HOST-NOT: @ex.managed
// Force ex and sx mitted in device compilation.
__global__ void foo(int *z) {
*z = x + ex + sx;
v[1].x = 2;
}
// Force ex and sx emitted in host compilatioin.
int foo2() {
return ex + sx;
}
// HOST-LABEL: define {{.*}}@_Z4loadv()
// HOST: %ld.managed = load i32*, i32** @x.managed, align 4
// HOST: %0 = load i32, i32* %ld.managed, align 4
// HOST: ret i32 %0
int load() {
return x;
}
// HOST-LABEL: define {{.*}}@_Z5storev()
// HOST: %ld.managed = load i32*, i32** @x.managed, align 4
// HOST: store i32 2, i32* %ld.managed, align 4
void store() {
x = 2;
}
// HOST-LABEL: define {{.*}}@_Z10addr_takenv()
// HOST: %ld.managed = load i32*, i32** @x.managed, align 4
// HOST: store i32* %ld.managed, i32** %p, align 8
// HOST: %0 = load i32*, i32** %p, align 8
// HOST: store i32 3, i32* %0, align 4
void addr_taken() {
int *p = &x;
*p = 3;
}
// HOST-LABEL: define {{.*}}@_Z5load2v()
// HOST: %ld.managed = load [100 x %struct.vec]*, [100 x %struct.vec]** @v.managed, align 16
// HOST: %0 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %ld.managed, i64 0, i64 1, i32 0
// HOST: %1 = load float, float* %0, align 4
// HOST: ret float %1
float load2() {
return v[1].x;
}
// HOST-LABEL: define {{.*}}@_Z5load3v()
// HOST: %ld.managed = load <{ %struct.vec, [99 x %struct.vec] }>*, <{ %struct.vec, [99 x %struct.vec] }>** @v2.managed, align 16
// HOST: %0 = bitcast <{ %struct.vec, [99 x %struct.vec] }>* %ld.managed to [100 x %struct.vec]*
// HOST: %1 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %0, i64 0, i64 1, i32 1
// HOST: %2 = load float, float* %1, align 4
// HOST: ret float %2
float load3() {
return v2[1].y;
}
// HOST-LABEL: define {{.*}}@_Z11addr_taken2v()
// HOST: %ld.managed = load [100 x %struct.vec]*, [100 x %struct.vec]** @v.managed, align 16
// HOST: %0 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %ld.managed, i64 0, i64 1, i32 0
// HOST: %1 = ptrtoint float* %0 to i64
// HOST: %ld.managed1 = load <{ %struct.vec, [99 x %struct.vec] }>*, <{ %struct.vec, [99 x %struct.vec] }>** @v2.managed, align 16
// HOST: %2 = bitcast <{ %struct.vec, [99 x %struct.vec] }>* %ld.managed1 to [100 x %struct.vec]*
// HOST: %3 = getelementptr inbounds [100 x %struct.vec], [100 x %struct.vec]* %2, i64 0, i64 1, i32 1
// HOST: %4 = ptrtoint float* %3 to i64
// HOST: %5 = sub i64 %4, %1
// HOST: %6 = sdiv i64 %5, 4
// HOST: %7 = sitofp i64 %6 to float
// HOST: ret float %7
float addr_taken2() {
return (float)reinterpret_cast<long>(&(v2[1].y)-&(v[1].x));
}
// HOST-DAG: __hipRegisterManagedVar({{.*}}@x.managed {{.*}}@x {{.*}}@[[DEVNAMEX]]{{.*}}, i64 4, i32 4)
// HOST-DAG: __hipRegisterManagedVar({{.*}}@_ZL2sx.managed {{.*}}@_ZL2sx
// HOST-NOT: __hipRegisterManagedVar({{.*}}@ex.managed {{.*}}@ex
// HOST-DAG: declare void @__hipRegisterManagedVar(i8**, i8*, i8*, i8*, i64, i32)