
Implements https://github.com/llvm/wg-hlsl/blob/main/proposals/0026-symbol-visibility.md. The change is to stop using the `hlsl.export` attribute. Instead, symbols with "program linkage" in HLSL will have export linkage with default visibility, and symbols with "external linkage" in HLSL will have export linkage with hidden visibility.
112 lines
4.9 KiB
HLSL
112 lines
4.9 KiB
HLSL
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
|
|
|
|
// CHECK: %struct.S = type <{ <2 x i32>, float }>
|
|
// CHECK: [[ConstS:@.*]] = private unnamed_addr constant %struct.S <{ <2 x i32> splat (i32 1), float 1.000000e+00 }>, align 1
|
|
// CHECK: [[ConstArr:.*]] = private unnamed_addr constant [2 x <2 x i32>] [<2 x i32> splat (i32 1), <2 x i32> zeroinitializer], align 8
|
|
|
|
struct S {
|
|
bool2 bv;
|
|
float f;
|
|
};
|
|
|
|
// CHECK-LABEL: define hidden noundef i1 {{.*}}fn1{{.*}}
|
|
// CHECK: [[B:%.*]] = alloca <2 x i32>, align 8
|
|
// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[B]], align 8
|
|
// CHECK-NEXT: [[BoolVec:%.*]] = load <2 x i32>, ptr [[B]], align 8
|
|
// CHECK-NEXT: [[L:%.*]] = trunc <2 x i32> [[BoolVec:%.*]] to <2 x i1>
|
|
// CHECK-NEXT: [[VecExt:%.*]] = extractelement <2 x i1> [[L]], i32 0
|
|
// CHECK-NEXT: ret i1 [[VecExt]]
|
|
bool fn1() {
|
|
bool2 B = {true,true};
|
|
return B[0];
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden noundef <2 x i1> {{.*}}fn2{{.*}}
|
|
// CHECK: [[VAddr:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[A:%.*]] = alloca <2 x i32>, align 8
|
|
// CHECK-NEXT: [[StoreV:%.*]] = zext i1 {{.*}} to i32
|
|
// CHECK-NEXT: store i32 [[StoreV]], ptr [[VAddr]], align 4
|
|
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[VAddr]], align 4
|
|
// CHECK-NEXT: [[LoadV:%.*]] = trunc i32 [[L]] to i1
|
|
// CHECK-NEXT: [[Vec:%.*]] = insertelement <2 x i1> poison, i1 [[LoadV]], i32 0
|
|
// CHECK-NEXT: [[Vec1:%.*]] = insertelement <2 x i1> [[Vec]], i1 true, i32 1
|
|
// CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[Vec1]] to <2 x i32>
|
|
// CHECK-NEXT: store <2 x i32> [[Z]], ptr [[A]], align 8
|
|
// CHECK-NEXT: [[LoadBV:%.*]] = load <2 x i32>, ptr [[A]], align 8
|
|
// CHECK-NEXT: [[LoadV2:%.*]] = trunc <2 x i32> [[LoadBV]] to <2 x i1>
|
|
// CHECK-NEXT: ret <2 x i1> [[LoadV2]]
|
|
bool2 fn2(bool V) {
|
|
bool2 A = {V,true};
|
|
return A;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden noundef i1 {{.*}}fn3{{.*}}
|
|
// CHECK: [[s:%.*]] = alloca %struct.S, align 1
|
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[s]], ptr align 1 [[ConstS]], i32 12, i1 false)
|
|
// CHECK-NEXT: [[BV:%.*]] = getelementptr inbounds nuw %struct.S, ptr [[s]], i32 0, i32 0
|
|
// CHECK-NEXT: [[LBV:%.*]] = load <2 x i32>, ptr [[BV]], align 1
|
|
// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[LBV]] to <2 x i1>
|
|
// CHECK-NEXT: [[VX:%.*]] = extractelement <2 x i1> [[LV]], i32 0
|
|
// CHECK-NEXT: ret i1 [[VX]]
|
|
bool fn3() {
|
|
S s = {{true,true}, 1.0};
|
|
return s.bv[0];
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden noundef i1 {{.*}}fn4{{.*}}
|
|
// CHECK: [[Arr:%.*]] = alloca [2 x <2 x i32>], align 8
|
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[Arr]], ptr align 8 [[ConstArr]], i32 16, i1 false)
|
|
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x <2 x i32>], ptr [[Arr]], i32 0, i32 0
|
|
// CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[Idx]], align 8
|
|
// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[L]] to <2 x i1>
|
|
// CHECK-NEXT: [[VX:%.*]] = extractelement <2 x i1> [[LV]], i32 1
|
|
// CHECK-NEXT: ret i1 [[VX]]
|
|
bool fn4() {
|
|
bool2 Arr[2] = {{true,true}, {false,false}};
|
|
return Arr[0][1];
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void {{.*}}fn5{{.*}}
|
|
// CHECK: [[Arr:%.*]] = alloca <2 x i32>, align 8
|
|
// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[Arr]], align 8
|
|
// CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[Arr]], align 8
|
|
// CHECK-NEXT: [[V:%.*]] = insertelement <2 x i32> [[L]], i32 0, i32 1
|
|
// CHECK-NEXT: store <2 x i32> [[V]], ptr [[Arr]], align 8
|
|
// CHECK-NEXT: ret void
|
|
void fn5() {
|
|
bool2 Arr = {true,true};
|
|
Arr[1] = false;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void {{.*}}fn6{{.*}}
|
|
// CHECK: [[V:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[S:%.*]] = alloca %struct.S, align 1
|
|
// CHECK-NEXT: store i32 0, ptr [[V]], align 4
|
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[S]], ptr align 1 {{.*}}, i32 12, i1 false)
|
|
// CHECK-NEXT: [[Y:%.*]] = load i32, ptr [[V]], align 4
|
|
// CHECK-NEXT: [[LV:%.*]] = trunc i32 [[Y]] to i1
|
|
// CHECK-NEXT: [[BV:%.*]] = getelementptr inbounds nuw %struct.S, ptr [[S]], i32 0, i32 0
|
|
// CHECK-NEXT: [[X:%.*]] = load <2 x i32>, ptr [[BV]], align 1
|
|
// CHECK-NEXT: [[Z:%.*]] = zext i1 [[LV]] to i32
|
|
// CHECK-NEXT: [[VI:%.*]] = insertelement <2 x i32> [[X]], i32 [[Z]], i32 1
|
|
// CHECK-NEXT: store <2 x i32> [[VI]], ptr [[BV]], align 1
|
|
// CHECK-NEXT: ret void
|
|
void fn6() {
|
|
bool V = false;
|
|
S s = {{true,true}, 1.0};
|
|
s.bv[1] = V;
|
|
}
|
|
|
|
// CHECK-LABEL: define hidden void {{.*}}fn7{{.*}}
|
|
// CHECK: [[Arr:%.*]] = alloca [2 x <2 x i32>], align 8
|
|
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[Arr]], ptr align 8 {{.*}}, i32 16, i1 false)
|
|
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x <2 x i32>], ptr [[Arr]], i32 0, i32 0
|
|
// CHECK-NEXT: [[X:%.*]] = load <2 x i32>, ptr [[Idx]], align 8
|
|
// CHECK-NEXT: [[VI:%.*]] = insertelement <2 x i32> [[X]], i32 0, i32 1
|
|
// CHECK-NEXT: store <2 x i32> [[VI]], ptr [[Idx]], align 8
|
|
// CHECK-NEXT: ret void
|
|
void fn7() {
|
|
bool2 Arr[2] = {{true,true}, {false,false}};
|
|
Arr[0][1] = false;
|
|
}
|