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