Skip to content

Commit 54f631d

Browse files
authored
[DirectX][NFC] Model precise overload type specification of DXIL Ops (#83917)
Implement an abstraction to specify precise overload types supported by DXIL ops. These overload types are typically a subset of LLVM intrinsics. Implement the corresponding changes in DXILEmitter backend. Add tests to verify expected errors for unsupported overload types at code generation time. Add tests to check for correct overload error output.
1 parent 2377beb commit 54f631d

File tree

9 files changed

+203
-75
lines changed

9 files changed

+203
-75
lines changed

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,28 +205,71 @@ defset list<DXILOpClass> OpClasses = {
205205
def writeSamplerFeedbackBias : DXILOpClass;
206206
def writeSamplerFeedbackGrad : DXILOpClass;
207207
def writeSamplerFeedbackLevel: DXILOpClass;
208+
209+
// This is a sentinel definition. Hence placed at the end of the list
210+
// and not as part of the above alphabetically sorted valid definitions.
211+
// Additionally it is capitalized unlike all the others.
212+
def UnknownOpClass: DXILOpClass;
213+
}
214+
215+
// Several of the overloaded DXIL Operations support for data types
216+
// that are a subset of the overloaded LLVM intrinsics that they map to.
217+
// For e.g., llvm.sin.* intrinsic operates on any floating-point type and
218+
// maps for lowering to DXIL Op Sin. However, valid overloads of DXIL Sin
219+
// operation overloads are half (f16) and float (f32) only.
220+
//
221+
// The following abstracts overload types specific to DXIL operations.
222+
223+
class DXILType : LLVMType<OtherVT> {
224+
let isAny = 1;
225+
int isI16OrI32 = 0;
226+
int isHalfOrFloat = 0;
208227
}
209228

229+
// Concrete records for various overload types supported specifically by
230+
// DXIL Operations.
231+
let isI16OrI32 = 1 in
232+
def llvm_i16ori32_ty : DXILType;
233+
234+
let isHalfOrFloat = 1 in
235+
def llvm_halforfloat_ty : DXILType;
236+
210237
// Abstraction DXIL Operation to LLVM intrinsic
211-
class DXILOpMapping<int opCode, DXILOpClass opClass, Intrinsic intrinsic, string doc> {
238+
class DXILOpMappingBase {
239+
int OpCode = 0; // Opcode of DXIL Operation
240+
DXILOpClass OpClass = UnknownOpClass;// Class of DXIL Operation.
241+
Intrinsic LLVMIntrinsic = ?; // LLVM Intrinsic DXIL Operation maps to
242+
string Doc = ""; // A short description of the operation
243+
list<LLVMType> OpTypes = ?; // Valid types of DXIL Operation in the
244+
// format [returnTy, param1ty, ...]
245+
}
246+
247+
class DXILOpMapping<int opCode, DXILOpClass opClass,
248+
Intrinsic intrinsic, string doc,
249+
list<LLVMType> opTys = []> : DXILOpMappingBase {
212250
int OpCode = opCode; // Opcode corresponding to DXIL Operation
213-
DXILOpClass OpClass = opClass; // Class of DXIL Operation.
251+
DXILOpClass OpClass = opClass; // Class of DXIL Operation.
214252
Intrinsic LLVMIntrinsic = intrinsic; // LLVM Intrinsic the DXIL Operation maps
215253
string Doc = doc; // to a short description of the operation
254+
list<LLVMType> OpTypes = !if(!eq(!size(opTys), 0), LLVMIntrinsic.Types, opTys);
216255
}
217256

218257
// Concrete definition of DXIL Operation mapping to corresponding LLVM intrinsic
219258
def Sin : DXILOpMapping<13, unary, int_sin,
220-
"Returns sine(theta) for theta in radians.">;
259+
"Returns sine(theta) for theta in radians.",
260+
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
221261
def Exp2 : DXILOpMapping<21, unary, int_exp2,
222262
"Returns the base 2 exponential, or 2**x, of the specified value."
223-
"exp2(x) = 2**x.">;
263+
"exp2(x) = 2**x.",
264+
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
224265
def Frac : DXILOpMapping<22, unary, int_dx_frac,
225266
"Returns a fraction from 0 to 1 that represents the "
226-
"decimal part of the input.">;
267+
"decimal part of the input.",
268+
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
227269
def Round : DXILOpMapping<26, unary, int_round,
228270
"Returns the input rounded to the nearest integer"
229-
"within a floating-point type.">;
271+
"within a floating-point type.",
272+
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
230273
def UMax : DXILOpMapping<39, binary, int_umax,
231274
"Unsigned integer maximum. UMax(a,b) = a > b ? a : b">;
232275
def FMad : DXILOpMapping<46, tertiary, int_fmuladd,

llvm/lib/Target/DirectX/DXILOpBuilder.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,8 @@ static FunctionCallee getOrCreateDXILOpFunction(dxil::OpCode DXILOp,
254254
const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
255255

256256
OverloadKind Kind = getOverloadKind(OverloadTy);
257-
// FIXME: find the issue and report error in clang instead of check it in
258-
// backend.
259257
if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
260-
llvm_unreachable("invalid overload");
258+
report_fatal_error("Invalid Overload Type", /* gen_crash_diag=*/false);
261259
}
262260

263261
std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
2+
3+
; DXIL operation exp2 does not support double overload type
4+
; CHECK: LLVM ERROR: Invalid Overload
5+
6+
define noundef double @exp2_double(double noundef %a) #0 {
7+
entry:
8+
%a.addr = alloca double, align 8
9+
store double %a, ptr %a.addr, align 8
10+
%0 = load double, ptr %a.addr, align 8
11+
%elt.exp2 = call double @llvm.exp2.f64(double %0)
12+
ret double %elt.exp2
13+
}

llvm/test/CodeGen/DirectX/frac.ll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,3 @@ entry:
2929
%dx.frac = call half @llvm.dx.frac.f16(half %0)
3030
ret half %dx.frac
3131
}
32-
33-
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
34-
declare half @llvm.dx.frac.f16(half) #1
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
2+
3+
; DXIL operation frac does not support double overload type
4+
; CHECK: LLVM ERROR: Invalid Overload Type
5+
6+
; Function Attrs: noinline nounwind optnone
7+
define noundef double @frac_double(double noundef %a) #0 {
8+
entry:
9+
%a.addr = alloca double, align 8
10+
store double %a, ptr %a.addr, align 8
11+
%0 = load double, ptr %a.addr, align 8
12+
%dx.frac = call double @llvm.dx.frac.f64(double %0)
13+
ret double %dx.frac
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
2+
3+
; This test is expected to fail with the following error
4+
; CHECK: LLVM ERROR: Invalid Overload Type
5+
6+
define noundef double @round_double(double noundef %a) #0 {
7+
entry:
8+
%a.addr = alloca double, align 8
9+
store double %a, ptr %a.addr, align 8
10+
%0 = load double, ptr %a.addr, align 8
11+
%elt.round = call double @llvm.round.f64(double %0)
12+
ret double %elt.round
13+
}

llvm/test/CodeGen/DirectX/sin.ll

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
; CHECK:call float @dx.op.unary.f32(i32 13, float %{{.*}})
55
; CHECK:call half @dx.op.unary.f16(i32 13, half %{{.*}})
66

7-
target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
8-
target triple = "dxil-pc-shadermodel6.7-library"
9-
107
; Function Attrs: noinline nounwind optnone
11-
define noundef float @_Z3foof(float noundef %a) #0 {
8+
define noundef float @sin_float(float noundef %a) #0 {
129
entry:
1310
%a.addr = alloca float, align 4
1411
store float %a, ptr %a.addr, align 4
@@ -17,27 +14,12 @@ entry:
1714
ret float %1
1815
}
1916

20-
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
21-
declare float @llvm.sin.f32(float) #1
22-
2317
; Function Attrs: noinline nounwind optnone
24-
define noundef half @_Z3barDh(half noundef %a) #0 {
18+
define noundef half @sin_half(half noundef %a) #0 {
2519
entry:
2620
%a.addr = alloca half, align 2
2721
store half %a, ptr %a.addr, align 2
2822
%0 = load half, ptr %a.addr, align 2
2923
%1 = call half @llvm.sin.f16(half %0)
3024
ret half %1
3125
}
32-
33-
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
34-
declare half @llvm.sin.f16(half) #1
35-
36-
attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
37-
attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
38-
39-
!llvm.module.flags = !{!0}
40-
!llvm.ident = !{!1}
41-
42-
!0 = !{i32 1, !"wchar_size", i32 4}
43-
!1 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 73417c517644db5c419c85c0b3cb6750172fcab5)"}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
2+
3+
; DXIL operation sin does not support double overload type
4+
; CHECK: LLVM ERROR: Invalid Overload
5+
6+
define noundef double @sin_double(double noundef %a) #0 {
7+
entry:
8+
%a.addr = alloca double, align 8
9+
store double %a, ptr %a.addr, align 8
10+
%0 = load double, ptr %a.addr, align 8
11+
%1 = call double @llvm.sin.f64(double %0)
12+
ret double %1
13+
}
14+

0 commit comments

Comments
 (0)