xref: /llvm-project/clang/test/CodeGenHLSL/inline-functions.hlsl (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
2// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
3// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
4// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
5// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
6// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
7
8// Tests that user functions will always be inlined.
9// This includes exported functions and mangled entry point implementation functions.
10// The unmangled entry functions must not be alwaysinlined.
11
12#define MAX 100
13
14float nums[MAX];
15
16// Verify that all functions have the alwaysinline attribute
17// NOINLINE: Function Attrs: alwaysinline
18// NOINLINE: define void @_Z4swapA100_jjj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %ix1, i32 noundef %ix2) [[IntAttr:\#[0-9]+]]
19// NOINLINE: ret void
20// Swap the values of Buf at indices ix1 and ix2
21void swap(unsigned Buf[MAX], unsigned ix1, unsigned ix2) {
22  float tmp = Buf[ix1];
23  Buf[ix1] = Buf[ix2];
24  Buf[ix2] = tmp;
25}
26
27// NOINLINE: Function Attrs: alwaysinline
28// NOINLINE: define void @_Z10BubbleSortA100_jj(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) [[IntAttr]]
29// NOINLINE: ret void
30// Inefficiently sort Buf in place
31void BubbleSort(unsigned Buf[MAX], unsigned size) {
32  bool swapped = true;
33  while (swapped) {
34    swapped = false;
35    for (unsigned i = 1; i < size; i++) {
36      if (Buf[i] < Buf[i-1]) {
37	swap(Buf, i, i-1);
38	swapped = true;
39      }
40    }
41  }
42}
43
44// Note ExtAttr is the inlined export set of attribs
45// CHECK: Function Attrs: alwaysinline
46// CHECK: define noundef i32 @_Z11RemoveDupesA100_jj(ptr {{[a-z_ ]*}}noundef byval([100 x i32]) align 4 {{.*}}%Buf, i32 noundef %size) {{[a-z_ ]*}}[[ExtAttr:\#[0-9]+]]
47// CHECK: ret i32
48// Sort Buf and remove any duplicate values
49// returns the number of values left
50export
51unsigned RemoveDupes(unsigned Buf[MAX], unsigned size) {
52  BubbleSort(Buf, size);
53  unsigned insertPt = 0;
54  for (unsigned i = 1; i < size; i++) {
55    if (Buf[i] == Buf[i-1])
56      insertPt++;
57    else
58      Buf[insertPt] = Buf[i];
59  }
60  return insertPt;
61}
62
63
64RWBuffer<unsigned> Indices;
65
66// The mangled version of main only remains without inlining
67// because it has internal linkage from the start
68// Note main functions get the norecurse attrib, which IntAttr reflects
69// NOINLINE: Function Attrs: alwaysinline
70// NOINLINE: define internal void @_Z4mainj(i32 noundef %GI) [[IntAttr]]
71// NOINLINE: ret void
72
73// The unmangled version is not inlined, EntryAttr reflects that
74// CHECK: Function Attrs: {{.*}}noinline
75// CHECK: define void @main() {{[a-z_ ]*}}[[EntryAttr:\#[0-9]+]]
76// Make sure function calls are inlined when AlwaysInline is run
77// This only leaves calls to llvm. intrinsics
78// INLINE-NOT:   call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
79// CHECK: ret void
80
81[numthreads(1,1,1)]
82[shader("compute")]
83void main(unsigned int GI : SV_GroupIndex) {
84  unsigned tmpIndices[MAX];
85  if (GI > MAX) return;
86  for (unsigned i = 1; i < GI; i++)
87    tmpIndices[i] = Indices[i];
88  RemoveDupes(tmpIndices, GI);
89  for (unsigned i = 1; i < GI; i++)
90    tmpIndices[i] = Indices[i];
91}
92
93// The mangled version of main only remains without inlining
94// because it has internal linkage from the start
95// Note main functions get the norecurse attrib, which IntAttr reflects
96// NOINLINE: Function Attrs: alwaysinline
97// NOINLINE: define internal void @_Z6main10v() [[IntAttr]]
98// NOINLINE: ret void
99
100// The unmangled version is not inlined, EntryAttr reflects that
101// CHECK: Function Attrs: {{.*}}noinline
102// CHECK: define void @main10() {{[a-z_ ]*}}[[EntryAttr]]
103// Make sure function calls are inlined when AlwaysInline is run
104// This only leaves calls to llvm. intrinsics
105// INLINE-NOT:   call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
106// CHECK: ret void
107
108[numthreads(1,1,1)]
109[shader("compute")]
110void main10() {
111  main(10);
112}
113
114// NOINLINE: attributes [[IntAttr]] = {{.*}} alwaysinline
115// CHECK: attributes [[ExtAttr]] = {{.*}} alwaysinline
116// CHECK: attributes [[EntryAttr]] = {{.*}} noinline
117