Skip to content

Commit 996cf5d

Browse files
authored
[HLSL] Implement dot2add intrinsic (llvm#131237)
Resolves llvm#99221 Key points: For SPIRV backend, it decompose into a `dot` followed a `add`. - [x] Implement dot2add clang builtin, - [x] Link dot2add clang builtin with hlsl_intrinsics.h - [x] Add sema checks for dot2add to CheckHLSLBuiltinFunctionCall in SemaHLSL.cpp - [x] Add codegen for dot2add to EmitHLSLBuiltinExpr in CGBuiltin.cpp - [x] Add codegen tests to clang/test/CodeGenHLSL/builtins/dot2add.hlsl - [x] Add sema tests to clang/test/SemaHLSL/BuiltIns/dot2add-errors.hlsl - [x] Create the int_dx_dot2add intrinsic in IntrinsicsDirectX.td - [x] Create the DXILOpMapping of int_dx_dot2add to 162 in DXIL.td - [x] Create the dot2add.ll and dot2add_errors.ll tests in llvm/test/CodeGen/DirectX/
1 parent 109566a commit 996cf5d

File tree

10 files changed

+228
-4
lines changed

10 files changed

+228
-4
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4891,6 +4891,12 @@ def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
48914891
let Prototype = "void(...)";
48924892
}
48934893

4894+
def HLSLDot2Add : LangBuiltin<"HLSL_LANG"> {
4895+
let Spellings = ["__builtin_hlsl_dot2add"];
4896+
let Attributes = [NoThrow, Const];
4897+
let Prototype = "float(_ExtVector<2, _Float16>, _ExtVector<2, _Float16>, float)";
4898+
}
4899+
48944900
def HLSLDot4AddI8Packed : LangBuiltin<"HLSL_LANG"> {
48954901
let Spellings = ["__builtin_hlsl_dot4add_i8packed"];
48964902
let Attributes = [NoThrow, Const];

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,19 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
380380
getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
381381
ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
382382
}
383+
case Builtin::BI__builtin_hlsl_dot2add: {
384+
llvm::Triple::ArchType Arch = CGM.getTarget().getTriple().getArch();
385+
assert(Arch == llvm::Triple::dxil &&
386+
"Intrinsic dot2add is only allowed for dxil architecture");
387+
Value *A = EmitScalarExpr(E->getArg(0));
388+
Value *B = EmitScalarExpr(E->getArg(1));
389+
Value *C = EmitScalarExpr(E->getArg(2));
390+
391+
Intrinsic::ID ID = llvm ::Intrinsic::dx_dot2add;
392+
return Builder.CreateIntrinsic(
393+
/*ReturnType=*/C->getType(), ID, ArrayRef<Value *>{A, B, C}, nullptr,
394+
"dx.dot2add");
395+
}
383396
case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
384397
Value *A = EmitScalarExpr(E->getArg(0));
385398
Value *B = EmitScalarExpr(E->getArg(1));

clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
4545
return length_vec_impl(X - Y);
4646
}
4747

48+
constexpr float dot2add_impl(half2 a, half2 b, float c) {
49+
#if defined(__DIRECTX__)
50+
return __builtin_hlsl_dot2add(a, b, c);
51+
#else
52+
return dot(a, b) + c;
53+
#endif
54+
}
55+
4856
template <typename T> constexpr T reflect_impl(T I, T N) {
4957
return I - 2 * N * I * N;
5058
}

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,21 @@ const inline float distance(__detail::HLSL_FIXED_VECTOR<float, N> X,
175175
return __detail::distance_vec_impl(X, Y);
176176
}
177177

178+
//===----------------------------------------------------------------------===//
179+
// dot2add builtins
180+
//===----------------------------------------------------------------------===//
181+
182+
/// \fn float dot2add(half2 A, half2 B, float C)
183+
/// \brief Dot product of 2 vector of type half and add a float scalar value.
184+
/// \param A The first input value to dot product.
185+
/// \param B The second input value to dot product.
186+
/// \param C The input value added to the dot product.
187+
188+
_HLSL_AVAILABILITY(shadermodel, 6.4)
189+
const inline float dot2add(half2 A, half2 B, float C) {
190+
return __detail::dot2add_impl(A, B, C);
191+
}
192+
178193
//===----------------------------------------------------------------------===//
179194
// fmod builtins
180195
//===----------------------------------------------------------------------===//
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \
2+
// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -o - | \
3+
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
4+
// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \
5+
// RUN: spirv-pc-vulkan-compute %s -emit-llvm -o - | \
6+
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
7+
8+
// Test basic lowering to runtime function call.
9+
10+
// CHECK-LABEL: define {{.*}}test_default_parameter_type
11+
float test_default_parameter_type(half2 p1, half2 p2, float p3) {
12+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
13+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
14+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
15+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
16+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
17+
// CHECK: ret float %[[RES]]
18+
return dot2add(p1, p2, p3);
19+
}
20+
21+
// CHECK-LABEL: define {{.*}}test_float_arg2_type
22+
float test_float_arg2_type(half2 p1, float2 p2, float p3) {
23+
// CHECK: %conv = fptrunc reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}} to <2 x half>
24+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
25+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
26+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
27+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
28+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
29+
// CHECK: ret float %[[RES]]
30+
return dot2add(p1, p2, p3);
31+
}
32+
33+
// CHECK-LABEL: define {{.*}}test_float_arg1_type
34+
float test_float_arg1_type(float2 p1, half2 p2, float p3) {
35+
// CHECK: %conv = fptrunc reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}} to <2 x half>
36+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
37+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
38+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
39+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
40+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
41+
// CHECK: ret float %[[RES]]
42+
return dot2add(p1, p2, p3);
43+
}
44+
45+
// CHECK-LABEL: define {{.*}}test_double_arg3_type
46+
float test_double_arg3_type(half2 p1, half2 p2, double p3) {
47+
// CHECK: %conv = fptrunc reassoc nnan ninf nsz arcp afn double %{{.*}} to float
48+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
49+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
50+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
51+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
52+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
53+
// CHECK: ret float %[[RES]]
54+
return dot2add(p1, p2, p3);
55+
}
56+
57+
// CHECK-LABEL: define {{.*}}test_float_arg1_arg2_type
58+
float test_float_arg1_arg2_type(float2 p1, float2 p2, float p3) {
59+
// CHECK: %conv = fptrunc reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}} to <2 x half>
60+
// CHECK: %conv1 = fptrunc reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}} to <2 x half>
61+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
62+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
63+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
64+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
65+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
66+
// CHECK: ret float %[[RES]]
67+
return dot2add(p1, p2, p3);
68+
}
69+
70+
// CHECK-LABEL: define {{.*}}test_double_arg1_arg2_type
71+
float test_double_arg1_arg2_type(double2 p1, double2 p2, float p3) {
72+
// CHECK: %conv = fptrunc reassoc nnan ninf nsz arcp afn <2 x double> %{{.*}} to <2 x half>
73+
// CHECK: %conv1 = fptrunc reassoc nnan ninf nsz arcp afn <2 x double> %{{.*}} to <2 x half>
74+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
75+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
76+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
77+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
78+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
79+
// CHECK: ret float %[[RES]]
80+
return dot2add(p1, p2, p3);
81+
}
82+
83+
// CHECK-LABEL: define {{.*}}test_int16_arg1_arg2_type
84+
float test_int16_arg1_arg2_type(int16_t2 p1, int16_t2 p2, float p3) {
85+
// CHECK: %conv = sitofp <2 x i16> %{{.*}} to <2 x half>
86+
// CHECK: %conv1 = sitofp <2 x i16> %{{.*}} to <2 x half>
87+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
88+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
89+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
90+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
91+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
92+
// CHECK: ret float %[[RES]]
93+
return dot2add(p1, p2, p3);
94+
}
95+
96+
// CHECK-LABEL: define {{.*}}test_int32_arg1_arg2_type
97+
float test_int32_arg1_arg2_type(int32_t2 p1, int32_t2 p2, float p3) {
98+
// CHECK: %conv = sitofp <2 x i32> %{{.*}} to <2 x half>
99+
// CHECK: %conv1 = sitofp <2 x i32> %{{.*}} to <2 x half>
100+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
101+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
102+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
103+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
104+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
105+
// CHECK: ret float %[[RES]]
106+
return dot2add(p1, p2, p3);
107+
}
108+
109+
// CHECK-LABEL: define {{.*}}test_int64_arg1_arg2_type
110+
float test_int64_arg1_arg2_type(int64_t2 p1, int64_t2 p2, float p3) {
111+
// CHECK: %conv = sitofp <2 x i64> %{{.*}} to <2 x half>
112+
// CHECK: %conv1 = sitofp <2 x i64> %{{.*}} to <2 x half>
113+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
114+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
115+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
116+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
117+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
118+
// CHECK: ret float %[[RES]]
119+
return dot2add(p1, p2, p3);
120+
}
121+
122+
// CHECK-LABEL: define {{.*}}test_bool_arg1_arg2_type
123+
float test_bool_arg1_arg2_type(bool2 p1, bool2 p2, float p3) {
124+
// CHECK: %loadedv = trunc <2 x i32> %{{.*}} to <2 x i1>
125+
// CHECK: %conv = uitofp <2 x i1> %loadedv to <2 x half>
126+
// CHECK: %loadedv1 = trunc <2 x i32> %{{.*}} to <2 x i1>
127+
// CHECK: %conv2 = uitofp <2 x i1> %loadedv1 to <2 x half>
128+
// CHECK-SPIRV: %[[MUL:.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
129+
// CHECK-SPIRV: %[[CONV:.*]] = fpext reassoc nnan ninf nsz arcp afn half %[[MUL]] to float
130+
// CHECK-SPIRV: %[[C:.*]] = load float, ptr %c.addr.i, align 4
131+
// CHECK-SPIRV: %[[RES:.*]] = fadd reassoc nnan ninf nsz arcp afn float %[[CONV]], %[[C]]
132+
// CHECK-DXIL: %[[RES:.*]] = call {{.*}} float @llvm.dx.dot2add.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, float %{{.*}})
133+
// CHECK: ret float %[[RES]]
134+
return dot2add(p1, p2, p3);
135+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify
2+
3+
float test_too_few_arg() {
4+
return dot2add();
5+
// expected-error@-1 {{no matching function for call to 'dot2add'}}
6+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 0 were provided}}
7+
}
8+
9+
float test_too_many_arg(half2 p1, half2 p2, float p3) {
10+
return dot2add(p1, p2, p3, p1);
11+
// expected-error@-1 {{no matching function for call to 'dot2add'}}
12+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 4 were provided}}
13+
}

llvm/include/llvm/IR/IntrinsicsDirectX.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def int_dx_udot :
100100
DefaultAttrsIntrinsic<[LLVMVectorElementType<0>],
101101
[llvm_anyint_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],
102102
[IntrNoMem, Commutative] >;
103+
def int_dx_dot2add :
104+
DefaultAttrsIntrinsic<[llvm_float_ty],
105+
[llvm_anyfloat_ty, LLVMMatchType<0>, llvm_float_ty],
106+
[IntrNoMem, Commutative]>;
103107
def int_dx_dot4add_i8packed : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
104108
def int_dx_dot4add_u8packed : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>;
105109

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,17 @@ def RawBufferStore : DXILOp<140, rawBufferStore> {
10771077
let stages = [Stages<DXIL1_2, [all_stages]>];
10781078
}
10791079

1080+
def Dot2AddHalf : DXILOp<162, dot2AddHalf> {
1081+
let Doc = "dot product of 2 vectors of half having size = 2, returns "
1082+
"float";
1083+
let intrinsics = [IntrinSelect<int_dx_dot2add>];
1084+
let arguments = [FloatTy, HalfTy, HalfTy, HalfTy, HalfTy];
1085+
let result = FloatTy;
1086+
let overloads = [Overloads<DXIL1_0, []>];
1087+
let stages = [Stages<DXIL1_0, [all_stages]>];
1088+
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
1089+
}
1090+
10801091
def Dot4AddI8Packed : DXILOp<163, dot4AddPacked> {
10811092
let Doc = "signed dot product of 4 x i8 vectors packed into i32, with "
10821093
"accumulate to i32";

llvm/lib/Target/DirectX/DXILOpLowering.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,8 @@ static SmallVector<Value *> populateOperands(Value *Arg, IRBuilder<> &Builder) {
5454
return ExtractedElements;
5555
}
5656

57-
static SmallVector<Value *> argVectorFlatten(CallInst *Orig,
58-
IRBuilder<> &Builder) {
59-
// Note: arg[NumOperands-1] is a pointer and is not needed by our flattening.
60-
unsigned NumOperands = Orig->getNumOperands() - 1;
57+
static SmallVector<Value *>
58+
argVectorFlatten(CallInst *Orig, IRBuilder<> &Builder, unsigned NumOperands) {
6159
assert(NumOperands > 0);
6260
Value *Arg0 = Orig->getOperand(0);
6361
[[maybe_unused]] auto *VecArg0 = dyn_cast<FixedVectorType>(Arg0->getType());
@@ -75,6 +73,12 @@ static SmallVector<Value *> argVectorFlatten(CallInst *Orig,
7573
return NewOperands;
7674
}
7775

76+
static SmallVector<Value *> argVectorFlatten(CallInst *Orig,
77+
IRBuilder<> &Builder) {
78+
// Note: arg[NumOperands-1] is a pointer and is not needed by our flattening.
79+
return argVectorFlatten(Orig, Builder, Orig->getNumOperands() - 1);
80+
}
81+
7882
namespace {
7983
class OpLowerer {
8084
Module &M;
@@ -168,6 +172,13 @@ class OpLowerer {
168172
}
169173
} else if (IsVectorArgExpansion) {
170174
Args = argVectorFlatten(CI, OpBuilder.getIRB());
175+
} else if (F.getIntrinsicID() == Intrinsic::dx_dot2add) {
176+
// arg[NumOperands-1] is a pointer and is not needed by our flattening.
177+
// arg[NumOperands-2] also does not need to be flattened because it is a
178+
// scalar.
179+
unsigned NumOperands = CI->getNumOperands() - 2;
180+
Args.push_back(CI->getArgOperand(NumOperands));
181+
Args.append(argVectorFlatten(CI, OpBuilder.getIRB(), NumOperands));
171182
} else {
172183
Args.append(CI->arg_begin(), CI->arg_end());
173184
}

llvm/test/CodeGen/DirectX/dot2add.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-compute %s | FileCheck %s
2+
3+
define noundef float @dot2add_simple(<2 x half> noundef %a, <2 x half> noundef %b, float %c) {
4+
entry:
5+
; CHECK: call float @dx.op.dot2AddHalf(i32 162, float %c, half %0, half %1, half %2, half %3)
6+
%ret = call float @llvm.dx.dot2add(<2 x half> %a, <2 x half> %b, float %c)
7+
ret float %ret
8+
}

0 commit comments

Comments
 (0)