
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.
118 lines
4.5 KiB
HLSL
118 lines
4.5 KiB
HLSL
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE,OPT_ATTR
|
|
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE,OPT_ATTR
|
|
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE,NOOPT_ATTR
|
|
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
|
|
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE,OPT_ATTR
|
|
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE,NOOPT_ATTR
|
|
|
|
// Tests that user functions will always be inlined.
|
|
// This includes exported functions and mangled entry point implementation functions.
|
|
// The unmangled entry functions must not be alwaysinlined.
|
|
|
|
#define MAX 100
|
|
|
|
float nums[MAX];
|
|
|
|
// Verify that all functions have the alwaysinline attribute
|
|
// NOINLINE: Function Attrs: alwaysinline
|
|
// NOINLINE: define hidden void @_Z4swapA100_jjj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %ix1, i32 noundef %ix2) [[Attr:\#[0-9]+]]
|
|
// NOINLINE: ret void
|
|
// Swap the values of Buf at indices ix1 and ix2
|
|
void swap(unsigned Buf[MAX], unsigned ix1, unsigned ix2) {
|
|
float tmp = Buf[ix1];
|
|
Buf[ix1] = Buf[ix2];
|
|
Buf[ix2] = tmp;
|
|
}
|
|
|
|
// NOINLINE: Function Attrs: alwaysinline
|
|
// NOINLINE: define hidden void @_Z10BubbleSortA100_jj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) [[Attr]]
|
|
// NOINLINE: ret void
|
|
// Inefficiently sort Buf in place
|
|
void BubbleSort(unsigned Buf[MAX], unsigned size) {
|
|
bool swapped = true;
|
|
while (swapped) {
|
|
swapped = false;
|
|
for (unsigned i = 1; i < size; i++) {
|
|
if (Buf[i] < Buf[i-1]) {
|
|
swap(Buf, i, i-1);
|
|
swapped = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note ExtAttr is the inlined export set of attribs
|
|
// CHECK: Function Attrs: alwaysinline
|
|
// CHECK: define noundef i32 @_Z11RemoveDupesA100_jj(ptr {{[a-z_ ]*}}noundef byval([100 x i32]) align 4 {{.*}}%Buf, i32 noundef %size) {{[a-z_ ]*}}[[Attr:\#[0-9]+]]
|
|
// CHECK: ret i32
|
|
// Sort Buf and remove any duplicate values
|
|
// returns the number of values left
|
|
export
|
|
unsigned RemoveDupes(unsigned Buf[MAX], unsigned size) {
|
|
BubbleSort(Buf, size);
|
|
unsigned insertPt = 0;
|
|
for (unsigned i = 1; i < size; i++) {
|
|
if (Buf[i] == Buf[i-1])
|
|
insertPt++;
|
|
else
|
|
Buf[insertPt] = Buf[i];
|
|
}
|
|
return insertPt;
|
|
}
|
|
|
|
|
|
RWBuffer<unsigned> Indices;
|
|
|
|
// The mangled version of main only remains without inlining
|
|
// because it has internal linkage from the start
|
|
// Note main functions get the alwaysinline attrib, which Attr reflects
|
|
// NOINLINE: Function Attrs: alwaysinline
|
|
// NOINLINE: define internal void @_Z4mainj(i32 noundef %GI) [[Attr]]
|
|
// NOINLINE: ret void
|
|
|
|
// The unmangled version is not inlined, EntryAttr reflects that
|
|
// OPT_ATTR: Function Attrs: {{.*}}optnone
|
|
// NOOPT_ATTR-NOT: Function Attrs: {{.*}}optnone
|
|
// CHECK: define void @main() {{[a-z_ ]*}}[[EntryAttr:\#[0-9]+]]
|
|
// Make sure function calls are inlined when AlwaysInline is run
|
|
// This only leaves calls to llvm. intrinsics
|
|
// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
|
|
// CHECK: ret void
|
|
|
|
[numthreads(1,1,1)]
|
|
[shader("compute")]
|
|
void main(unsigned int GI : SV_GroupIndex) {
|
|
unsigned tmpIndices[MAX];
|
|
if (GI > MAX) return;
|
|
for (unsigned i = 1; i < GI; i++)
|
|
tmpIndices[i] = Indices[i];
|
|
RemoveDupes(tmpIndices, GI);
|
|
for (unsigned i = 1; i < GI; i++)
|
|
tmpIndices[i] = Indices[i];
|
|
}
|
|
|
|
// The mangled version of main only remains without inlining
|
|
// because it has internal linkage from the start
|
|
// Note main functions get the alwaysinline attrib, which Attr reflects
|
|
// NOINLINE: Function Attrs: alwaysinline
|
|
// NOINLINE: define internal void @_Z6main10v() [[Attr]]
|
|
// NOINLINE: ret void
|
|
|
|
// The unmangled version is not inlined, EntryAttr reflects that
|
|
// OPT_ATTR: Function Attrs: {{.*}}optnone
|
|
// NOOPT_ATTR-NOT: Function Attrs: {{.*}}optnone
|
|
// CHECK: define void @main10() {{[a-z_ ]*}}[[EntryAttr]]
|
|
// Make sure function calls are inlined when AlwaysInline is run
|
|
// This only leaves calls to llvm. intrinsics
|
|
// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
|
|
// CHECK: ret void
|
|
|
|
[numthreads(1,1,1)]
|
|
[shader("compute")]
|
|
void main10() {
|
|
main(10);
|
|
}
|
|
|
|
// CHECK: attributes [[Attr]] = {{.*}} alwaysinline
|
|
// CHECK: attributes [[EntryAttr]] = {{.*}} noinline
|