1*700637cbSDimitry Andric //===------- CGHLSLBuiltins.cpp - Emit LLVM Code for HLSL builtins --------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This contains code to emit HLSL Builtin calls as LLVM code.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric
13*700637cbSDimitry Andric #include "CGBuiltin.h"
14*700637cbSDimitry Andric #include "CGHLSLRuntime.h"
15*700637cbSDimitry Andric #include "CodeGenFunction.h"
16*700637cbSDimitry Andric
17*700637cbSDimitry Andric using namespace clang;
18*700637cbSDimitry Andric using namespace CodeGen;
19*700637cbSDimitry Andric using namespace llvm;
20*700637cbSDimitry Andric
handleAsDoubleBuiltin(CodeGenFunction & CGF,const CallExpr * E)21*700637cbSDimitry Andric static Value *handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E) {
22*700637cbSDimitry Andric assert((E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
23*700637cbSDimitry Andric E->getArg(1)->getType()->hasUnsignedIntegerRepresentation()) &&
24*700637cbSDimitry Andric "asdouble operands types mismatch");
25*700637cbSDimitry Andric Value *OpLowBits = CGF.EmitScalarExpr(E->getArg(0));
26*700637cbSDimitry Andric Value *OpHighBits = CGF.EmitScalarExpr(E->getArg(1));
27*700637cbSDimitry Andric
28*700637cbSDimitry Andric llvm::Type *ResultType = CGF.DoubleTy;
29*700637cbSDimitry Andric int N = 1;
30*700637cbSDimitry Andric if (auto *VTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
31*700637cbSDimitry Andric N = VTy->getNumElements();
32*700637cbSDimitry Andric ResultType = llvm::FixedVectorType::get(CGF.DoubleTy, N);
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric
35*700637cbSDimitry Andric if (CGF.CGM.getTarget().getTriple().isDXIL())
36*700637cbSDimitry Andric return CGF.Builder.CreateIntrinsic(
37*700637cbSDimitry Andric /*ReturnType=*/ResultType, Intrinsic::dx_asdouble,
38*700637cbSDimitry Andric {OpLowBits, OpHighBits}, nullptr, "hlsl.asdouble");
39*700637cbSDimitry Andric
40*700637cbSDimitry Andric if (!E->getArg(0)->getType()->isVectorType()) {
41*700637cbSDimitry Andric OpLowBits = CGF.Builder.CreateVectorSplat(1, OpLowBits);
42*700637cbSDimitry Andric OpHighBits = CGF.Builder.CreateVectorSplat(1, OpHighBits);
43*700637cbSDimitry Andric }
44*700637cbSDimitry Andric
45*700637cbSDimitry Andric llvm::SmallVector<int> Mask;
46*700637cbSDimitry Andric for (int i = 0; i < N; i++) {
47*700637cbSDimitry Andric Mask.push_back(i);
48*700637cbSDimitry Andric Mask.push_back(i + N);
49*700637cbSDimitry Andric }
50*700637cbSDimitry Andric
51*700637cbSDimitry Andric Value *BitVec = CGF.Builder.CreateShuffleVector(OpLowBits, OpHighBits, Mask);
52*700637cbSDimitry Andric
53*700637cbSDimitry Andric return CGF.Builder.CreateBitCast(BitVec, ResultType);
54*700637cbSDimitry Andric }
55*700637cbSDimitry Andric
handleHlslClip(const CallExpr * E,CodeGenFunction * CGF)56*700637cbSDimitry Andric static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
57*700637cbSDimitry Andric Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
58*700637cbSDimitry Andric
59*700637cbSDimitry Andric Constant *FZeroConst = ConstantFP::getZero(CGF->FloatTy);
60*700637cbSDimitry Andric Value *CMP;
61*700637cbSDimitry Andric Value *LastInstr;
62*700637cbSDimitry Andric
63*700637cbSDimitry Andric if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
64*700637cbSDimitry Andric FZeroConst = ConstantVector::getSplat(
65*700637cbSDimitry Andric ElementCount::getFixed(VecTy->getNumElements()), FZeroConst);
66*700637cbSDimitry Andric auto *FCompInst = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
67*700637cbSDimitry Andric CMP = CGF->Builder.CreateIntrinsic(
68*700637cbSDimitry Andric CGF->Builder.getInt1Ty(), CGF->CGM.getHLSLRuntime().getAnyIntrinsic(),
69*700637cbSDimitry Andric {FCompInst});
70*700637cbSDimitry Andric } else {
71*700637cbSDimitry Andric CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
72*700637cbSDimitry Andric }
73*700637cbSDimitry Andric
74*700637cbSDimitry Andric if (CGF->CGM.getTarget().getTriple().isDXIL()) {
75*700637cbSDimitry Andric LastInstr = CGF->Builder.CreateIntrinsic(Intrinsic::dx_discard, {CMP});
76*700637cbSDimitry Andric } else if (CGF->CGM.getTarget().getTriple().isSPIRV()) {
77*700637cbSDimitry Andric BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
78*700637cbSDimitry Andric BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
79*700637cbSDimitry Andric
80*700637cbSDimitry Andric CGF->Builder.CreateCondBr(CMP, LT0, End);
81*700637cbSDimitry Andric
82*700637cbSDimitry Andric CGF->Builder.SetInsertPoint(LT0);
83*700637cbSDimitry Andric
84*700637cbSDimitry Andric CGF->Builder.CreateIntrinsic(Intrinsic::spv_discard, {});
85*700637cbSDimitry Andric
86*700637cbSDimitry Andric LastInstr = CGF->Builder.CreateBr(End);
87*700637cbSDimitry Andric CGF->Builder.SetInsertPoint(End);
88*700637cbSDimitry Andric } else {
89*700637cbSDimitry Andric llvm_unreachable("Backend Codegen not supported.");
90*700637cbSDimitry Andric }
91*700637cbSDimitry Andric
92*700637cbSDimitry Andric return LastInstr;
93*700637cbSDimitry Andric }
94*700637cbSDimitry Andric
handleHlslSplitdouble(const CallExpr * E,CodeGenFunction * CGF)95*700637cbSDimitry Andric static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
96*700637cbSDimitry Andric Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
97*700637cbSDimitry Andric const auto *OutArg1 = dyn_cast<HLSLOutArgExpr>(E->getArg(1));
98*700637cbSDimitry Andric const auto *OutArg2 = dyn_cast<HLSLOutArgExpr>(E->getArg(2));
99*700637cbSDimitry Andric
100*700637cbSDimitry Andric CallArgList Args;
101*700637cbSDimitry Andric LValue Op1TmpLValue =
102*700637cbSDimitry Andric CGF->EmitHLSLOutArgExpr(OutArg1, Args, OutArg1->getType());
103*700637cbSDimitry Andric LValue Op2TmpLValue =
104*700637cbSDimitry Andric CGF->EmitHLSLOutArgExpr(OutArg2, Args, OutArg2->getType());
105*700637cbSDimitry Andric
106*700637cbSDimitry Andric if (CGF->getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee())
107*700637cbSDimitry Andric Args.reverseWritebacks();
108*700637cbSDimitry Andric
109*700637cbSDimitry Andric Value *LowBits = nullptr;
110*700637cbSDimitry Andric Value *HighBits = nullptr;
111*700637cbSDimitry Andric
112*700637cbSDimitry Andric if (CGF->CGM.getTarget().getTriple().isDXIL()) {
113*700637cbSDimitry Andric llvm::Type *RetElementTy = CGF->Int32Ty;
114*700637cbSDimitry Andric if (auto *Op0VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>())
115*700637cbSDimitry Andric RetElementTy = llvm::VectorType::get(
116*700637cbSDimitry Andric CGF->Int32Ty, ElementCount::getFixed(Op0VecTy->getNumElements()));
117*700637cbSDimitry Andric auto *RetTy = llvm::StructType::get(RetElementTy, RetElementTy);
118*700637cbSDimitry Andric
119*700637cbSDimitry Andric CallInst *CI = CGF->Builder.CreateIntrinsic(
120*700637cbSDimitry Andric RetTy, Intrinsic::dx_splitdouble, {Op0}, nullptr, "hlsl.splitdouble");
121*700637cbSDimitry Andric
122*700637cbSDimitry Andric LowBits = CGF->Builder.CreateExtractValue(CI, 0);
123*700637cbSDimitry Andric HighBits = CGF->Builder.CreateExtractValue(CI, 1);
124*700637cbSDimitry Andric } else {
125*700637cbSDimitry Andric // For Non DXIL targets we generate the instructions.
126*700637cbSDimitry Andric
127*700637cbSDimitry Andric if (!Op0->getType()->isVectorTy()) {
128*700637cbSDimitry Andric FixedVectorType *DestTy = FixedVectorType::get(CGF->Int32Ty, 2);
129*700637cbSDimitry Andric Value *Bitcast = CGF->Builder.CreateBitCast(Op0, DestTy);
130*700637cbSDimitry Andric
131*700637cbSDimitry Andric LowBits = CGF->Builder.CreateExtractElement(Bitcast, (uint64_t)0);
132*700637cbSDimitry Andric HighBits = CGF->Builder.CreateExtractElement(Bitcast, 1);
133*700637cbSDimitry Andric } else {
134*700637cbSDimitry Andric int NumElements = 1;
135*700637cbSDimitry Andric if (const auto *VecTy =
136*700637cbSDimitry Andric E->getArg(0)->getType()->getAs<clang::VectorType>())
137*700637cbSDimitry Andric NumElements = VecTy->getNumElements();
138*700637cbSDimitry Andric
139*700637cbSDimitry Andric FixedVectorType *Uint32VecTy =
140*700637cbSDimitry Andric FixedVectorType::get(CGF->Int32Ty, NumElements * 2);
141*700637cbSDimitry Andric Value *Uint32Vec = CGF->Builder.CreateBitCast(Op0, Uint32VecTy);
142*700637cbSDimitry Andric if (NumElements == 1) {
143*700637cbSDimitry Andric LowBits = CGF->Builder.CreateExtractElement(Uint32Vec, (uint64_t)0);
144*700637cbSDimitry Andric HighBits = CGF->Builder.CreateExtractElement(Uint32Vec, 1);
145*700637cbSDimitry Andric } else {
146*700637cbSDimitry Andric SmallVector<int> EvenMask, OddMask;
147*700637cbSDimitry Andric for (int I = 0, E = NumElements; I != E; ++I) {
148*700637cbSDimitry Andric EvenMask.push_back(I * 2);
149*700637cbSDimitry Andric OddMask.push_back(I * 2 + 1);
150*700637cbSDimitry Andric }
151*700637cbSDimitry Andric LowBits = CGF->Builder.CreateShuffleVector(Uint32Vec, EvenMask);
152*700637cbSDimitry Andric HighBits = CGF->Builder.CreateShuffleVector(Uint32Vec, OddMask);
153*700637cbSDimitry Andric }
154*700637cbSDimitry Andric }
155*700637cbSDimitry Andric }
156*700637cbSDimitry Andric CGF->Builder.CreateStore(LowBits, Op1TmpLValue.getAddress());
157*700637cbSDimitry Andric auto *LastInst =
158*700637cbSDimitry Andric CGF->Builder.CreateStore(HighBits, Op2TmpLValue.getAddress());
159*700637cbSDimitry Andric CGF->EmitWritebacks(Args);
160*700637cbSDimitry Andric return LastInst;
161*700637cbSDimitry Andric }
162*700637cbSDimitry Andric
163*700637cbSDimitry Andric // Return dot product intrinsic that corresponds to the QT scalar type
getDotProductIntrinsic(CGHLSLRuntime & RT,QualType QT)164*700637cbSDimitry Andric static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
165*700637cbSDimitry Andric if (QT->isFloatingType())
166*700637cbSDimitry Andric return RT.getFDotIntrinsic();
167*700637cbSDimitry Andric if (QT->isSignedIntegerType())
168*700637cbSDimitry Andric return RT.getSDotIntrinsic();
169*700637cbSDimitry Andric assert(QT->isUnsignedIntegerType());
170*700637cbSDimitry Andric return RT.getUDotIntrinsic();
171*700637cbSDimitry Andric }
172*700637cbSDimitry Andric
getFirstBitHighIntrinsic(CGHLSLRuntime & RT,QualType QT)173*700637cbSDimitry Andric static Intrinsic::ID getFirstBitHighIntrinsic(CGHLSLRuntime &RT, QualType QT) {
174*700637cbSDimitry Andric if (QT->hasSignedIntegerRepresentation()) {
175*700637cbSDimitry Andric return RT.getFirstBitSHighIntrinsic();
176*700637cbSDimitry Andric }
177*700637cbSDimitry Andric
178*700637cbSDimitry Andric assert(QT->hasUnsignedIntegerRepresentation());
179*700637cbSDimitry Andric return RT.getFirstBitUHighIntrinsic();
180*700637cbSDimitry Andric }
181*700637cbSDimitry Andric
182*700637cbSDimitry Andric // Return wave active sum that corresponds to the QT scalar type
getWaveActiveSumIntrinsic(llvm::Triple::ArchType Arch,CGHLSLRuntime & RT,QualType QT)183*700637cbSDimitry Andric static Intrinsic::ID getWaveActiveSumIntrinsic(llvm::Triple::ArchType Arch,
184*700637cbSDimitry Andric CGHLSLRuntime &RT, QualType QT) {
185*700637cbSDimitry Andric switch (Arch) {
186*700637cbSDimitry Andric case llvm::Triple::spirv:
187*700637cbSDimitry Andric return Intrinsic::spv_wave_reduce_sum;
188*700637cbSDimitry Andric case llvm::Triple::dxil: {
189*700637cbSDimitry Andric if (QT->isUnsignedIntegerType())
190*700637cbSDimitry Andric return Intrinsic::dx_wave_reduce_usum;
191*700637cbSDimitry Andric return Intrinsic::dx_wave_reduce_sum;
192*700637cbSDimitry Andric }
193*700637cbSDimitry Andric default:
194*700637cbSDimitry Andric llvm_unreachable("Intrinsic WaveActiveSum"
195*700637cbSDimitry Andric " not supported by target architecture");
196*700637cbSDimitry Andric }
197*700637cbSDimitry Andric }
198*700637cbSDimitry Andric
199*700637cbSDimitry Andric // Return wave active sum that corresponds to the QT scalar type
getWaveActiveMaxIntrinsic(llvm::Triple::ArchType Arch,CGHLSLRuntime & RT,QualType QT)200*700637cbSDimitry Andric static Intrinsic::ID getWaveActiveMaxIntrinsic(llvm::Triple::ArchType Arch,
201*700637cbSDimitry Andric CGHLSLRuntime &RT, QualType QT) {
202*700637cbSDimitry Andric switch (Arch) {
203*700637cbSDimitry Andric case llvm::Triple::spirv:
204*700637cbSDimitry Andric if (QT->isUnsignedIntegerType())
205*700637cbSDimitry Andric return Intrinsic::spv_wave_reduce_umax;
206*700637cbSDimitry Andric return Intrinsic::spv_wave_reduce_max;
207*700637cbSDimitry Andric case llvm::Triple::dxil: {
208*700637cbSDimitry Andric if (QT->isUnsignedIntegerType())
209*700637cbSDimitry Andric return Intrinsic::dx_wave_reduce_umax;
210*700637cbSDimitry Andric return Intrinsic::dx_wave_reduce_max;
211*700637cbSDimitry Andric }
212*700637cbSDimitry Andric default:
213*700637cbSDimitry Andric llvm_unreachable("Intrinsic WaveActiveMax"
214*700637cbSDimitry Andric " not supported by target architecture");
215*700637cbSDimitry Andric }
216*700637cbSDimitry Andric }
217*700637cbSDimitry Andric
218*700637cbSDimitry Andric // Returns the mangled name for a builtin function that the SPIR-V backend
219*700637cbSDimitry Andric // will expand into a spec Constant.
getSpecConstantFunctionName(clang::QualType SpecConstantType,ASTContext & Context)220*700637cbSDimitry Andric static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType,
221*700637cbSDimitry Andric ASTContext &Context) {
222*700637cbSDimitry Andric // The parameter types for our conceptual intrinsic function.
223*700637cbSDimitry Andric QualType ClangParamTypes[] = {Context.IntTy, SpecConstantType};
224*700637cbSDimitry Andric
225*700637cbSDimitry Andric // Create a temporary FunctionDecl for the builtin fuction. It won't be
226*700637cbSDimitry Andric // added to the AST.
227*700637cbSDimitry Andric FunctionProtoType::ExtProtoInfo EPI;
228*700637cbSDimitry Andric QualType FnType =
229*700637cbSDimitry Andric Context.getFunctionType(SpecConstantType, ClangParamTypes, EPI);
230*700637cbSDimitry Andric DeclarationName FuncName = &Context.Idents.get("__spirv_SpecConstant");
231*700637cbSDimitry Andric FunctionDecl *FnDeclForMangling = FunctionDecl::Create(
232*700637cbSDimitry Andric Context, Context.getTranslationUnitDecl(), SourceLocation(),
233*700637cbSDimitry Andric SourceLocation(), FuncName, FnType, /*TSI=*/nullptr, SC_Extern);
234*700637cbSDimitry Andric
235*700637cbSDimitry Andric // Attach the created parameter declarations to the function declaration.
236*700637cbSDimitry Andric SmallVector<ParmVarDecl *, 2> ParamDecls;
237*700637cbSDimitry Andric for (QualType ParamType : ClangParamTypes) {
238*700637cbSDimitry Andric ParmVarDecl *PD = ParmVarDecl::Create(
239*700637cbSDimitry Andric Context, FnDeclForMangling, SourceLocation(), SourceLocation(),
240*700637cbSDimitry Andric /*IdentifierInfo*/ nullptr, ParamType, /*TSI*/ nullptr, SC_None,
241*700637cbSDimitry Andric /*DefaultArg*/ nullptr);
242*700637cbSDimitry Andric ParamDecls.push_back(PD);
243*700637cbSDimitry Andric }
244*700637cbSDimitry Andric FnDeclForMangling->setParams(ParamDecls);
245*700637cbSDimitry Andric
246*700637cbSDimitry Andric // Get the mangled name.
247*700637cbSDimitry Andric std::string Name;
248*700637cbSDimitry Andric llvm::raw_string_ostream MangledNameStream(Name);
249*700637cbSDimitry Andric std::unique_ptr<MangleContext> Mangler(Context.createMangleContext());
250*700637cbSDimitry Andric Mangler->mangleName(FnDeclForMangling, MangledNameStream);
251*700637cbSDimitry Andric MangledNameStream.flush();
252*700637cbSDimitry Andric
253*700637cbSDimitry Andric return Name;
254*700637cbSDimitry Andric }
255*700637cbSDimitry Andric
EmitHLSLBuiltinExpr(unsigned BuiltinID,const CallExpr * E,ReturnValueSlot ReturnValue)256*700637cbSDimitry Andric Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
257*700637cbSDimitry Andric const CallExpr *E,
258*700637cbSDimitry Andric ReturnValueSlot ReturnValue) {
259*700637cbSDimitry Andric if (!getLangOpts().HLSL)
260*700637cbSDimitry Andric return nullptr;
261*700637cbSDimitry Andric
262*700637cbSDimitry Andric switch (BuiltinID) {
263*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_adduint64: {
264*700637cbSDimitry Andric Value *OpA = EmitScalarExpr(E->getArg(0));
265*700637cbSDimitry Andric Value *OpB = EmitScalarExpr(E->getArg(1));
266*700637cbSDimitry Andric QualType Arg0Ty = E->getArg(0)->getType();
267*700637cbSDimitry Andric uint64_t NumElements = Arg0Ty->castAs<VectorType>()->getNumElements();
268*700637cbSDimitry Andric assert(Arg0Ty == E->getArg(1)->getType() &&
269*700637cbSDimitry Andric "AddUint64 operand types must match");
270*700637cbSDimitry Andric assert(Arg0Ty->hasIntegerRepresentation() &&
271*700637cbSDimitry Andric "AddUint64 operands must have an integer representation");
272*700637cbSDimitry Andric assert((NumElements == 2 || NumElements == 4) &&
273*700637cbSDimitry Andric "AddUint64 operands must have 2 or 4 elements");
274*700637cbSDimitry Andric
275*700637cbSDimitry Andric llvm::Value *LowA;
276*700637cbSDimitry Andric llvm::Value *HighA;
277*700637cbSDimitry Andric llvm::Value *LowB;
278*700637cbSDimitry Andric llvm::Value *HighB;
279*700637cbSDimitry Andric
280*700637cbSDimitry Andric // Obtain low and high words of inputs A and B
281*700637cbSDimitry Andric if (NumElements == 2) {
282*700637cbSDimitry Andric LowA = Builder.CreateExtractElement(OpA, (uint64_t)0, "LowA");
283*700637cbSDimitry Andric HighA = Builder.CreateExtractElement(OpA, (uint64_t)1, "HighA");
284*700637cbSDimitry Andric LowB = Builder.CreateExtractElement(OpB, (uint64_t)0, "LowB");
285*700637cbSDimitry Andric HighB = Builder.CreateExtractElement(OpB, (uint64_t)1, "HighB");
286*700637cbSDimitry Andric } else {
287*700637cbSDimitry Andric LowA = Builder.CreateShuffleVector(OpA, {0, 2}, "LowA");
288*700637cbSDimitry Andric HighA = Builder.CreateShuffleVector(OpA, {1, 3}, "HighA");
289*700637cbSDimitry Andric LowB = Builder.CreateShuffleVector(OpB, {0, 2}, "LowB");
290*700637cbSDimitry Andric HighB = Builder.CreateShuffleVector(OpB, {1, 3}, "HighB");
291*700637cbSDimitry Andric }
292*700637cbSDimitry Andric
293*700637cbSDimitry Andric // Use an uadd_with_overflow to compute the sum of low words and obtain a
294*700637cbSDimitry Andric // carry value
295*700637cbSDimitry Andric llvm::Value *Carry;
296*700637cbSDimitry Andric llvm::Value *LowSum = EmitOverflowIntrinsic(
297*700637cbSDimitry Andric *this, Intrinsic::uadd_with_overflow, LowA, LowB, Carry);
298*700637cbSDimitry Andric llvm::Value *ZExtCarry =
299*700637cbSDimitry Andric Builder.CreateZExt(Carry, HighA->getType(), "CarryZExt");
300*700637cbSDimitry Andric
301*700637cbSDimitry Andric // Sum the high words and the carry
302*700637cbSDimitry Andric llvm::Value *HighSum = Builder.CreateAdd(HighA, HighB, "HighSum");
303*700637cbSDimitry Andric llvm::Value *HighSumPlusCarry =
304*700637cbSDimitry Andric Builder.CreateAdd(HighSum, ZExtCarry, "HighSumPlusCarry");
305*700637cbSDimitry Andric
306*700637cbSDimitry Andric if (NumElements == 4) {
307*700637cbSDimitry Andric return Builder.CreateShuffleVector(LowSum, HighSumPlusCarry, {0, 2, 1, 3},
308*700637cbSDimitry Andric "hlsl.AddUint64");
309*700637cbSDimitry Andric }
310*700637cbSDimitry Andric
311*700637cbSDimitry Andric llvm::Value *Result = PoisonValue::get(OpA->getType());
312*700637cbSDimitry Andric Result = Builder.CreateInsertElement(Result, LowSum, (uint64_t)0,
313*700637cbSDimitry Andric "hlsl.AddUint64.upto0");
314*700637cbSDimitry Andric Result = Builder.CreateInsertElement(Result, HighSumPlusCarry, (uint64_t)1,
315*700637cbSDimitry Andric "hlsl.AddUint64");
316*700637cbSDimitry Andric return Result;
317*700637cbSDimitry Andric }
318*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_resource_getpointer: {
319*700637cbSDimitry Andric Value *HandleOp = EmitScalarExpr(E->getArg(0));
320*700637cbSDimitry Andric Value *IndexOp = EmitScalarExpr(E->getArg(1));
321*700637cbSDimitry Andric
322*700637cbSDimitry Andric llvm::Type *RetTy = ConvertType(E->getType());
323*700637cbSDimitry Andric return Builder.CreateIntrinsic(
324*700637cbSDimitry Andric RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
325*700637cbSDimitry Andric ArrayRef<Value *>{HandleOp, IndexOp});
326*700637cbSDimitry Andric }
327*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
328*700637cbSDimitry Andric llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
329*700637cbSDimitry Andric return llvm::PoisonValue::get(HandleTy);
330*700637cbSDimitry Andric }
331*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
332*700637cbSDimitry Andric llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
333*700637cbSDimitry Andric Value *RegisterOp = EmitScalarExpr(E->getArg(1));
334*700637cbSDimitry Andric Value *SpaceOp = EmitScalarExpr(E->getArg(2));
335*700637cbSDimitry Andric Value *RangeOp = EmitScalarExpr(E->getArg(3));
336*700637cbSDimitry Andric Value *IndexOp = EmitScalarExpr(E->getArg(4));
337*700637cbSDimitry Andric Value *Name = EmitScalarExpr(E->getArg(5));
338*700637cbSDimitry Andric // FIXME: NonUniformResourceIndex bit is not yet implemented
339*700637cbSDimitry Andric // (llvm/llvm-project#135452)
340*700637cbSDimitry Andric Value *NonUniform =
341*700637cbSDimitry Andric llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
342*700637cbSDimitry Andric
343*700637cbSDimitry Andric llvm::Intrinsic::ID IntrinsicID =
344*700637cbSDimitry Andric CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
345*700637cbSDimitry Andric SmallVector<Value *> Args{SpaceOp, RegisterOp, RangeOp,
346*700637cbSDimitry Andric IndexOp, NonUniform, Name};
347*700637cbSDimitry Andric return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
348*700637cbSDimitry Andric }
349*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
350*700637cbSDimitry Andric llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
351*700637cbSDimitry Andric Value *SpaceOp = EmitScalarExpr(E->getArg(1));
352*700637cbSDimitry Andric Value *RangeOp = EmitScalarExpr(E->getArg(2));
353*700637cbSDimitry Andric Value *IndexOp = EmitScalarExpr(E->getArg(3));
354*700637cbSDimitry Andric Value *OrderID = EmitScalarExpr(E->getArg(4));
355*700637cbSDimitry Andric Value *Name = EmitScalarExpr(E->getArg(5));
356*700637cbSDimitry Andric // FIXME: NonUniformResourceIndex bit is not yet implemented
357*700637cbSDimitry Andric // (llvm/llvm-project#135452)
358*700637cbSDimitry Andric Value *NonUniform =
359*700637cbSDimitry Andric llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
360*700637cbSDimitry Andric
361*700637cbSDimitry Andric llvm::Intrinsic::ID IntrinsicID =
362*700637cbSDimitry Andric CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
363*700637cbSDimitry Andric SmallVector<Value *> Args{OrderID, SpaceOp, RangeOp,
364*700637cbSDimitry Andric IndexOp, NonUniform, Name};
365*700637cbSDimitry Andric return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
366*700637cbSDimitry Andric }
367*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_all: {
368*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
369*700637cbSDimitry Andric return Builder.CreateIntrinsic(
370*700637cbSDimitry Andric /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
371*700637cbSDimitry Andric CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
372*700637cbSDimitry Andric "hlsl.all");
373*700637cbSDimitry Andric }
374*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_and: {
375*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
376*700637cbSDimitry Andric Value *Op1 = EmitScalarExpr(E->getArg(1));
377*700637cbSDimitry Andric return Builder.CreateAnd(Op0, Op1, "hlsl.and");
378*700637cbSDimitry Andric }
379*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_or: {
380*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
381*700637cbSDimitry Andric Value *Op1 = EmitScalarExpr(E->getArg(1));
382*700637cbSDimitry Andric return Builder.CreateOr(Op0, Op1, "hlsl.or");
383*700637cbSDimitry Andric }
384*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_any: {
385*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
386*700637cbSDimitry Andric return Builder.CreateIntrinsic(
387*700637cbSDimitry Andric /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
388*700637cbSDimitry Andric CGM.getHLSLRuntime().getAnyIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
389*700637cbSDimitry Andric "hlsl.any");
390*700637cbSDimitry Andric }
391*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_asdouble:
392*700637cbSDimitry Andric return handleAsDoubleBuiltin(*this, E);
393*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_clamp: {
394*700637cbSDimitry Andric Value *OpX = EmitScalarExpr(E->getArg(0));
395*700637cbSDimitry Andric Value *OpMin = EmitScalarExpr(E->getArg(1));
396*700637cbSDimitry Andric Value *OpMax = EmitScalarExpr(E->getArg(2));
397*700637cbSDimitry Andric
398*700637cbSDimitry Andric QualType Ty = E->getArg(0)->getType();
399*700637cbSDimitry Andric if (auto *VecTy = Ty->getAs<VectorType>())
400*700637cbSDimitry Andric Ty = VecTy->getElementType();
401*700637cbSDimitry Andric
402*700637cbSDimitry Andric Intrinsic::ID Intr;
403*700637cbSDimitry Andric if (Ty->isFloatingType()) {
404*700637cbSDimitry Andric Intr = CGM.getHLSLRuntime().getNClampIntrinsic();
405*700637cbSDimitry Andric } else if (Ty->isUnsignedIntegerType()) {
406*700637cbSDimitry Andric Intr = CGM.getHLSLRuntime().getUClampIntrinsic();
407*700637cbSDimitry Andric } else {
408*700637cbSDimitry Andric assert(Ty->isSignedIntegerType());
409*700637cbSDimitry Andric Intr = CGM.getHLSLRuntime().getSClampIntrinsic();
410*700637cbSDimitry Andric }
411*700637cbSDimitry Andric return Builder.CreateIntrinsic(
412*700637cbSDimitry Andric /*ReturnType=*/OpX->getType(), Intr,
413*700637cbSDimitry Andric ArrayRef<Value *>{OpX, OpMin, OpMax}, nullptr, "hlsl.clamp");
414*700637cbSDimitry Andric }
415*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_crossf16:
416*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_crossf32: {
417*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
418*700637cbSDimitry Andric Value *Op1 = EmitScalarExpr(E->getArg(1));
419*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
420*700637cbSDimitry Andric E->getArg(1)->getType()->hasFloatingRepresentation() &&
421*700637cbSDimitry Andric "cross operands must have a float representation");
422*700637cbSDimitry Andric // make sure each vector has exactly 3 elements
423*700637cbSDimitry Andric assert(
424*700637cbSDimitry Andric E->getArg(0)->getType()->castAs<VectorType>()->getNumElements() == 3 &&
425*700637cbSDimitry Andric E->getArg(1)->getType()->castAs<VectorType>()->getNumElements() == 3 &&
426*700637cbSDimitry Andric "input vectors must have 3 elements each");
427*700637cbSDimitry Andric return Builder.CreateIntrinsic(
428*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getCrossIntrinsic(),
429*700637cbSDimitry Andric ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.cross");
430*700637cbSDimitry Andric }
431*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_dot: {
432*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
433*700637cbSDimitry Andric Value *Op1 = EmitScalarExpr(E->getArg(1));
434*700637cbSDimitry Andric llvm::Type *T0 = Op0->getType();
435*700637cbSDimitry Andric llvm::Type *T1 = Op1->getType();
436*700637cbSDimitry Andric
437*700637cbSDimitry Andric // If the arguments are scalars, just emit a multiply
438*700637cbSDimitry Andric if (!T0->isVectorTy() && !T1->isVectorTy()) {
439*700637cbSDimitry Andric if (T0->isFloatingPointTy())
440*700637cbSDimitry Andric return Builder.CreateFMul(Op0, Op1, "hlsl.dot");
441*700637cbSDimitry Andric
442*700637cbSDimitry Andric if (T0->isIntegerTy())
443*700637cbSDimitry Andric return Builder.CreateMul(Op0, Op1, "hlsl.dot");
444*700637cbSDimitry Andric
445*700637cbSDimitry Andric llvm_unreachable(
446*700637cbSDimitry Andric "Scalar dot product is only supported on ints and floats.");
447*700637cbSDimitry Andric }
448*700637cbSDimitry Andric // For vectors, validate types and emit the appropriate intrinsic
449*700637cbSDimitry Andric assert(CGM.getContext().hasSameUnqualifiedType(E->getArg(0)->getType(),
450*700637cbSDimitry Andric E->getArg(1)->getType()) &&
451*700637cbSDimitry Andric "Dot product operands must have the same type.");
452*700637cbSDimitry Andric
453*700637cbSDimitry Andric auto *VecTy0 = E->getArg(0)->getType()->castAs<VectorType>();
454*700637cbSDimitry Andric assert(VecTy0 && "Dot product argument must be a vector.");
455*700637cbSDimitry Andric
456*700637cbSDimitry Andric return Builder.CreateIntrinsic(
457*700637cbSDimitry Andric /*ReturnType=*/T0->getScalarType(),
458*700637cbSDimitry Andric getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
459*700637cbSDimitry Andric ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
460*700637cbSDimitry Andric }
461*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
462*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
463*700637cbSDimitry Andric Value *Y = EmitScalarExpr(E->getArg(1));
464*700637cbSDimitry Andric Value *Acc = EmitScalarExpr(E->getArg(2));
465*700637cbSDimitry Andric
466*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddI8PackedIntrinsic();
467*700637cbSDimitry Andric // Note that the argument order disagrees between the builtin and the
468*700637cbSDimitry Andric // intrinsic here.
469*700637cbSDimitry Andric return Builder.CreateIntrinsic(
470*700637cbSDimitry Andric /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
471*700637cbSDimitry Andric nullptr, "hlsl.dot4add.i8packed");
472*700637cbSDimitry Andric }
473*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_dot4add_u8packed: {
474*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
475*700637cbSDimitry Andric Value *Y = EmitScalarExpr(E->getArg(1));
476*700637cbSDimitry Andric Value *Acc = EmitScalarExpr(E->getArg(2));
477*700637cbSDimitry Andric
478*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddU8PackedIntrinsic();
479*700637cbSDimitry Andric // Note that the argument order disagrees between the builtin and the
480*700637cbSDimitry Andric // intrinsic here.
481*700637cbSDimitry Andric return Builder.CreateIntrinsic(
482*700637cbSDimitry Andric /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
483*700637cbSDimitry Andric nullptr, "hlsl.dot4add.u8packed");
484*700637cbSDimitry Andric }
485*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: {
486*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
487*700637cbSDimitry Andric
488*700637cbSDimitry Andric return Builder.CreateIntrinsic(
489*700637cbSDimitry Andric /*ReturnType=*/ConvertType(E->getType()),
490*700637cbSDimitry Andric getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()),
491*700637cbSDimitry Andric ArrayRef<Value *>{X}, nullptr, "hlsl.firstbithigh");
492*700637cbSDimitry Andric }
493*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
494*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
495*700637cbSDimitry Andric
496*700637cbSDimitry Andric return Builder.CreateIntrinsic(
497*700637cbSDimitry Andric /*ReturnType=*/ConvertType(E->getType()),
498*700637cbSDimitry Andric CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef<Value *>{X},
499*700637cbSDimitry Andric nullptr, "hlsl.firstbitlow");
500*700637cbSDimitry Andric }
501*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_lerp: {
502*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
503*700637cbSDimitry Andric Value *Y = EmitScalarExpr(E->getArg(1));
504*700637cbSDimitry Andric Value *S = EmitScalarExpr(E->getArg(2));
505*700637cbSDimitry Andric if (!E->getArg(0)->getType()->hasFloatingRepresentation())
506*700637cbSDimitry Andric llvm_unreachable("lerp operand must have a float representation");
507*700637cbSDimitry Andric return Builder.CreateIntrinsic(
508*700637cbSDimitry Andric /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getLerpIntrinsic(),
509*700637cbSDimitry Andric ArrayRef<Value *>{X, Y, S}, nullptr, "hlsl.lerp");
510*700637cbSDimitry Andric }
511*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_normalize: {
512*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
513*700637cbSDimitry Andric
514*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
515*700637cbSDimitry Andric "normalize operand must have a float representation");
516*700637cbSDimitry Andric
517*700637cbSDimitry Andric return Builder.CreateIntrinsic(
518*700637cbSDimitry Andric /*ReturnType=*/X->getType(),
519*700637cbSDimitry Andric CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef<Value *>{X},
520*700637cbSDimitry Andric nullptr, "hlsl.normalize");
521*700637cbSDimitry Andric }
522*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_degrees: {
523*700637cbSDimitry Andric Value *X = EmitScalarExpr(E->getArg(0));
524*700637cbSDimitry Andric
525*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
526*700637cbSDimitry Andric "degree operand must have a float representation");
527*700637cbSDimitry Andric
528*700637cbSDimitry Andric return Builder.CreateIntrinsic(
529*700637cbSDimitry Andric /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(),
530*700637cbSDimitry Andric ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
531*700637cbSDimitry Andric }
532*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_frac: {
533*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
534*700637cbSDimitry Andric if (!E->getArg(0)->getType()->hasFloatingRepresentation())
535*700637cbSDimitry Andric llvm_unreachable("frac operand must have a float representation");
536*700637cbSDimitry Andric return Builder.CreateIntrinsic(
537*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(),
538*700637cbSDimitry Andric ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac");
539*700637cbSDimitry Andric }
540*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_isinf: {
541*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
542*700637cbSDimitry Andric llvm::Type *Xty = Op0->getType();
543*700637cbSDimitry Andric llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
544*700637cbSDimitry Andric if (Xty->isVectorTy()) {
545*700637cbSDimitry Andric auto *XVecTy = E->getArg(0)->getType()->castAs<VectorType>();
546*700637cbSDimitry Andric retType = llvm::VectorType::get(
547*700637cbSDimitry Andric retType, ElementCount::getFixed(XVecTy->getNumElements()));
548*700637cbSDimitry Andric }
549*700637cbSDimitry Andric if (!E->getArg(0)->getType()->hasFloatingRepresentation())
550*700637cbSDimitry Andric llvm_unreachable("isinf operand must have a float representation");
551*700637cbSDimitry Andric return Builder.CreateIntrinsic(retType, Intrinsic::dx_isinf,
552*700637cbSDimitry Andric ArrayRef<Value *>{Op0}, nullptr, "dx.isinf");
553*700637cbSDimitry Andric }
554*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_mad: {
555*700637cbSDimitry Andric Value *M = EmitScalarExpr(E->getArg(0));
556*700637cbSDimitry Andric Value *A = EmitScalarExpr(E->getArg(1));
557*700637cbSDimitry Andric Value *B = EmitScalarExpr(E->getArg(2));
558*700637cbSDimitry Andric if (E->getArg(0)->getType()->hasFloatingRepresentation())
559*700637cbSDimitry Andric return Builder.CreateIntrinsic(
560*700637cbSDimitry Andric /*ReturnType*/ M->getType(), Intrinsic::fmuladd,
561*700637cbSDimitry Andric ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");
562*700637cbSDimitry Andric
563*700637cbSDimitry Andric if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
564*700637cbSDimitry Andric if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
565*700637cbSDimitry Andric return Builder.CreateIntrinsic(
566*700637cbSDimitry Andric /*ReturnType*/ M->getType(), Intrinsic::dx_imad,
567*700637cbSDimitry Andric ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
568*700637cbSDimitry Andric
569*700637cbSDimitry Andric Value *Mul = Builder.CreateNSWMul(M, A);
570*700637cbSDimitry Andric return Builder.CreateNSWAdd(Mul, B);
571*700637cbSDimitry Andric }
572*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
573*700637cbSDimitry Andric if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
574*700637cbSDimitry Andric return Builder.CreateIntrinsic(
575*700637cbSDimitry Andric /*ReturnType=*/M->getType(), Intrinsic::dx_umad,
576*700637cbSDimitry Andric ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
577*700637cbSDimitry Andric
578*700637cbSDimitry Andric Value *Mul = Builder.CreateNUWMul(M, A);
579*700637cbSDimitry Andric return Builder.CreateNUWAdd(Mul, B);
580*700637cbSDimitry Andric }
581*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_rcp: {
582*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
583*700637cbSDimitry Andric if (!E->getArg(0)->getType()->hasFloatingRepresentation())
584*700637cbSDimitry Andric llvm_unreachable("rcp operand must have a float representation");
585*700637cbSDimitry Andric llvm::Type *Ty = Op0->getType();
586*700637cbSDimitry Andric llvm::Type *EltTy = Ty->getScalarType();
587*700637cbSDimitry Andric Constant *One = Ty->isVectorTy()
588*700637cbSDimitry Andric ? ConstantVector::getSplat(
589*700637cbSDimitry Andric ElementCount::getFixed(
590*700637cbSDimitry Andric cast<FixedVectorType>(Ty)->getNumElements()),
591*700637cbSDimitry Andric ConstantFP::get(EltTy, 1.0))
592*700637cbSDimitry Andric : ConstantFP::get(EltTy, 1.0);
593*700637cbSDimitry Andric return Builder.CreateFDiv(One, Op0, "hlsl.rcp");
594*700637cbSDimitry Andric }
595*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
596*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
597*700637cbSDimitry Andric if (!E->getArg(0)->getType()->hasFloatingRepresentation())
598*700637cbSDimitry Andric llvm_unreachable("rsqrt operand must have a float representation");
599*700637cbSDimitry Andric return Builder.CreateIntrinsic(
600*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getRsqrtIntrinsic(),
601*700637cbSDimitry Andric ArrayRef<Value *>{Op0}, nullptr, "hlsl.rsqrt");
602*700637cbSDimitry Andric }
603*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_saturate: {
604*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
605*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
606*700637cbSDimitry Andric "saturate operand must have a float representation");
607*700637cbSDimitry Andric return Builder.CreateIntrinsic(
608*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(),
609*700637cbSDimitry Andric CGM.getHLSLRuntime().getSaturateIntrinsic(), ArrayRef<Value *>{Op0},
610*700637cbSDimitry Andric nullptr, "hlsl.saturate");
611*700637cbSDimitry Andric }
612*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_select: {
613*700637cbSDimitry Andric Value *OpCond = EmitScalarExpr(E->getArg(0));
614*700637cbSDimitry Andric RValue RValTrue = EmitAnyExpr(E->getArg(1));
615*700637cbSDimitry Andric Value *OpTrue =
616*700637cbSDimitry Andric RValTrue.isScalar()
617*700637cbSDimitry Andric ? RValTrue.getScalarVal()
618*700637cbSDimitry Andric : RValTrue.getAggregatePointer(E->getArg(1)->getType(), *this);
619*700637cbSDimitry Andric RValue RValFalse = EmitAnyExpr(E->getArg(2));
620*700637cbSDimitry Andric Value *OpFalse =
621*700637cbSDimitry Andric RValFalse.isScalar()
622*700637cbSDimitry Andric ? RValFalse.getScalarVal()
623*700637cbSDimitry Andric : RValFalse.getAggregatePointer(E->getArg(2)->getType(), *this);
624*700637cbSDimitry Andric if (auto *VTy = E->getType()->getAs<VectorType>()) {
625*700637cbSDimitry Andric if (!OpTrue->getType()->isVectorTy())
626*700637cbSDimitry Andric OpTrue =
627*700637cbSDimitry Andric Builder.CreateVectorSplat(VTy->getNumElements(), OpTrue, "splat");
628*700637cbSDimitry Andric if (!OpFalse->getType()->isVectorTy())
629*700637cbSDimitry Andric OpFalse =
630*700637cbSDimitry Andric Builder.CreateVectorSplat(VTy->getNumElements(), OpFalse, "splat");
631*700637cbSDimitry Andric }
632*700637cbSDimitry Andric
633*700637cbSDimitry Andric Value *SelectVal =
634*700637cbSDimitry Andric Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select");
635*700637cbSDimitry Andric if (!RValTrue.isScalar())
636*700637cbSDimitry Andric Builder.CreateStore(SelectVal, ReturnValue.getAddress(),
637*700637cbSDimitry Andric ReturnValue.isVolatile());
638*700637cbSDimitry Andric
639*700637cbSDimitry Andric return SelectVal;
640*700637cbSDimitry Andric }
641*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_step: {
642*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
643*700637cbSDimitry Andric Value *Op1 = EmitScalarExpr(E->getArg(1));
644*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
645*700637cbSDimitry Andric E->getArg(1)->getType()->hasFloatingRepresentation() &&
646*700637cbSDimitry Andric "step operands must have a float representation");
647*700637cbSDimitry Andric return Builder.CreateIntrinsic(
648*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(),
649*700637cbSDimitry Andric ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.step");
650*700637cbSDimitry Andric }
651*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_active_all_true: {
652*700637cbSDimitry Andric Value *Op = EmitScalarExpr(E->getArg(0));
653*700637cbSDimitry Andric assert(Op->getType()->isIntegerTy(1) &&
654*700637cbSDimitry Andric "Intrinsic WaveActiveAllTrue operand must be a bool");
655*700637cbSDimitry Andric
656*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic();
657*700637cbSDimitry Andric return EmitRuntimeCall(
658*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op});
659*700637cbSDimitry Andric }
660*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_active_any_true: {
661*700637cbSDimitry Andric Value *Op = EmitScalarExpr(E->getArg(0));
662*700637cbSDimitry Andric assert(Op->getType()->isIntegerTy(1) &&
663*700637cbSDimitry Andric "Intrinsic WaveActiveAnyTrue operand must be a bool");
664*700637cbSDimitry Andric
665*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic();
666*700637cbSDimitry Andric return EmitRuntimeCall(
667*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op});
668*700637cbSDimitry Andric }
669*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_active_count_bits: {
670*700637cbSDimitry Andric Value *OpExpr = EmitScalarExpr(E->getArg(0));
671*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveCountBitsIntrinsic();
672*700637cbSDimitry Andric return EmitRuntimeCall(
673*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID),
674*700637cbSDimitry Andric ArrayRef{OpExpr});
675*700637cbSDimitry Andric }
676*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_active_sum: {
677*700637cbSDimitry Andric // Due to the use of variadic arguments, explicitly retreive argument
678*700637cbSDimitry Andric Value *OpExpr = EmitScalarExpr(E->getArg(0));
679*700637cbSDimitry Andric Intrinsic::ID IID = getWaveActiveSumIntrinsic(
680*700637cbSDimitry Andric getTarget().getTriple().getArch(), CGM.getHLSLRuntime(),
681*700637cbSDimitry Andric E->getArg(0)->getType());
682*700637cbSDimitry Andric
683*700637cbSDimitry Andric return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration(
684*700637cbSDimitry Andric &CGM.getModule(), IID, {OpExpr->getType()}),
685*700637cbSDimitry Andric ArrayRef{OpExpr}, "hlsl.wave.active.sum");
686*700637cbSDimitry Andric }
687*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_active_max: {
688*700637cbSDimitry Andric // Due to the use of variadic arguments, explicitly retreive argument
689*700637cbSDimitry Andric Value *OpExpr = EmitScalarExpr(E->getArg(0));
690*700637cbSDimitry Andric Intrinsic::ID IID = getWaveActiveMaxIntrinsic(
691*700637cbSDimitry Andric getTarget().getTriple().getArch(), CGM.getHLSLRuntime(),
692*700637cbSDimitry Andric E->getArg(0)->getType());
693*700637cbSDimitry Andric
694*700637cbSDimitry Andric return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration(
695*700637cbSDimitry Andric &CGM.getModule(), IID, {OpExpr->getType()}),
696*700637cbSDimitry Andric ArrayRef{OpExpr}, "hlsl.wave.active.max");
697*700637cbSDimitry Andric }
698*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
699*700637cbSDimitry Andric // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in
700*700637cbSDimitry Andric // defined in SPIRVBuiltins.td. So instead we manually get the matching name
701*700637cbSDimitry Andric // for the DirectX intrinsic and the demangled builtin name
702*700637cbSDimitry Andric switch (CGM.getTarget().getTriple().getArch()) {
703*700637cbSDimitry Andric case llvm::Triple::dxil:
704*700637cbSDimitry Andric return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration(
705*700637cbSDimitry Andric &CGM.getModule(), Intrinsic::dx_wave_getlaneindex));
706*700637cbSDimitry Andric case llvm::Triple::spirv:
707*700637cbSDimitry Andric return EmitRuntimeCall(CGM.CreateRuntimeFunction(
708*700637cbSDimitry Andric llvm::FunctionType::get(IntTy, {}, false),
709*700637cbSDimitry Andric "__hlsl_wave_get_lane_index", {}, false, true));
710*700637cbSDimitry Andric default:
711*700637cbSDimitry Andric llvm_unreachable(
712*700637cbSDimitry Andric "Intrinsic WaveGetLaneIndex not supported by target architecture");
713*700637cbSDimitry Andric }
714*700637cbSDimitry Andric }
715*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_is_first_lane: {
716*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
717*700637cbSDimitry Andric return EmitRuntimeCall(
718*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
719*700637cbSDimitry Andric }
720*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_get_lane_count: {
721*700637cbSDimitry Andric Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveGetLaneCountIntrinsic();
722*700637cbSDimitry Andric return EmitRuntimeCall(
723*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
724*700637cbSDimitry Andric }
725*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
726*700637cbSDimitry Andric // Due to the use of variadic arguments we must explicitly retreive them and
727*700637cbSDimitry Andric // create our function type.
728*700637cbSDimitry Andric Value *OpExpr = EmitScalarExpr(E->getArg(0));
729*700637cbSDimitry Andric Value *OpIndex = EmitScalarExpr(E->getArg(1));
730*700637cbSDimitry Andric return EmitRuntimeCall(
731*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(
732*700637cbSDimitry Andric &CGM.getModule(), CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(),
733*700637cbSDimitry Andric {OpExpr->getType()}),
734*700637cbSDimitry Andric ArrayRef{OpExpr, OpIndex}, "hlsl.wave.readlane");
735*700637cbSDimitry Andric }
736*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_sign: {
737*700637cbSDimitry Andric auto *Arg0 = E->getArg(0);
738*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(Arg0);
739*700637cbSDimitry Andric llvm::Type *Xty = Op0->getType();
740*700637cbSDimitry Andric llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext());
741*700637cbSDimitry Andric if (Xty->isVectorTy()) {
742*700637cbSDimitry Andric auto *XVecTy = Arg0->getType()->castAs<VectorType>();
743*700637cbSDimitry Andric retType = llvm::VectorType::get(
744*700637cbSDimitry Andric retType, ElementCount::getFixed(XVecTy->getNumElements()));
745*700637cbSDimitry Andric }
746*700637cbSDimitry Andric assert((Arg0->getType()->hasFloatingRepresentation() ||
747*700637cbSDimitry Andric Arg0->getType()->hasIntegerRepresentation()) &&
748*700637cbSDimitry Andric "sign operand must have a float or int representation");
749*700637cbSDimitry Andric
750*700637cbSDimitry Andric if (Arg0->getType()->hasUnsignedIntegerRepresentation()) {
751*700637cbSDimitry Andric Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::get(Xty, 0));
752*700637cbSDimitry Andric return Builder.CreateSelect(Cmp, ConstantInt::get(retType, 0),
753*700637cbSDimitry Andric ConstantInt::get(retType, 1), "hlsl.sign");
754*700637cbSDimitry Andric }
755*700637cbSDimitry Andric
756*700637cbSDimitry Andric return Builder.CreateIntrinsic(
757*700637cbSDimitry Andric retType, CGM.getHLSLRuntime().getSignIntrinsic(),
758*700637cbSDimitry Andric ArrayRef<Value *>{Op0}, nullptr, "hlsl.sign");
759*700637cbSDimitry Andric }
760*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_radians: {
761*700637cbSDimitry Andric Value *Op0 = EmitScalarExpr(E->getArg(0));
762*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
763*700637cbSDimitry Andric "radians operand must have a float representation");
764*700637cbSDimitry Andric return Builder.CreateIntrinsic(
765*700637cbSDimitry Andric /*ReturnType=*/Op0->getType(),
766*700637cbSDimitry Andric CGM.getHLSLRuntime().getRadiansIntrinsic(), ArrayRef<Value *>{Op0},
767*700637cbSDimitry Andric nullptr, "hlsl.radians");
768*700637cbSDimitry Andric }
769*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_buffer_update_counter: {
770*700637cbSDimitry Andric Value *ResHandle = EmitScalarExpr(E->getArg(0));
771*700637cbSDimitry Andric Value *Offset = EmitScalarExpr(E->getArg(1));
772*700637cbSDimitry Andric Value *OffsetI8 = Builder.CreateIntCast(Offset, Int8Ty, true);
773*700637cbSDimitry Andric return Builder.CreateIntrinsic(
774*700637cbSDimitry Andric /*ReturnType=*/Offset->getType(),
775*700637cbSDimitry Andric CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(),
776*700637cbSDimitry Andric ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr);
777*700637cbSDimitry Andric }
778*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
779*700637cbSDimitry Andric
780*700637cbSDimitry Andric assert((E->getArg(0)->getType()->hasFloatingRepresentation() &&
781*700637cbSDimitry Andric E->getArg(1)->getType()->hasUnsignedIntegerRepresentation() &&
782*700637cbSDimitry Andric E->getArg(2)->getType()->hasUnsignedIntegerRepresentation()) &&
783*700637cbSDimitry Andric "asuint operands types mismatch");
784*700637cbSDimitry Andric return handleHlslSplitdouble(E, this);
785*700637cbSDimitry Andric }
786*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_elementwise_clip:
787*700637cbSDimitry Andric assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
788*700637cbSDimitry Andric "clip operands types mismatch");
789*700637cbSDimitry Andric return handleHlslClip(E, this);
790*700637cbSDimitry Andric case Builtin::BI__builtin_hlsl_group_memory_barrier_with_group_sync: {
791*700637cbSDimitry Andric Intrinsic::ID ID =
792*700637cbSDimitry Andric CGM.getHLSLRuntime().getGroupMemoryBarrierWithGroupSyncIntrinsic();
793*700637cbSDimitry Andric return EmitRuntimeCall(
794*700637cbSDimitry Andric Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
795*700637cbSDimitry Andric }
796*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_bool:
797*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_short:
798*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_ushort:
799*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_int:
800*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_uint:
801*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_longlong:
802*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_ulonglong:
803*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_half:
804*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_float:
805*700637cbSDimitry Andric case Builtin::BI__builtin_get_spirv_spec_constant_double: {
806*700637cbSDimitry Andric llvm::Function *SpecConstantFn = getSpecConstantFunction(E->getType());
807*700637cbSDimitry Andric llvm::Value *SpecId = EmitScalarExpr(E->getArg(0));
808*700637cbSDimitry Andric llvm::Value *DefaultVal = EmitScalarExpr(E->getArg(1));
809*700637cbSDimitry Andric llvm::Value *Args[] = {SpecId, DefaultVal};
810*700637cbSDimitry Andric return Builder.CreateCall(SpecConstantFn, Args);
811*700637cbSDimitry Andric }
812*700637cbSDimitry Andric }
813*700637cbSDimitry Andric return nullptr;
814*700637cbSDimitry Andric }
815*700637cbSDimitry Andric
getSpecConstantFunction(const clang::QualType & SpecConstantType)816*700637cbSDimitry Andric llvm::Function *clang::CodeGen::CodeGenFunction::getSpecConstantFunction(
817*700637cbSDimitry Andric const clang::QualType &SpecConstantType) {
818*700637cbSDimitry Andric
819*700637cbSDimitry Andric // Find or create the declaration for the function.
820*700637cbSDimitry Andric llvm::Module *M = &CGM.getModule();
821*700637cbSDimitry Andric std::string MangledName =
822*700637cbSDimitry Andric getSpecConstantFunctionName(SpecConstantType, getContext());
823*700637cbSDimitry Andric llvm::Function *SpecConstantFn = M->getFunction(MangledName);
824*700637cbSDimitry Andric
825*700637cbSDimitry Andric if (!SpecConstantFn) {
826*700637cbSDimitry Andric llvm::Type *IntType = ConvertType(getContext().IntTy);
827*700637cbSDimitry Andric llvm::Type *RetTy = ConvertType(SpecConstantType);
828*700637cbSDimitry Andric llvm::Type *ArgTypes[] = {IntType, RetTy};
829*700637cbSDimitry Andric llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, ArgTypes, false);
830*700637cbSDimitry Andric SpecConstantFn = llvm::Function::Create(
831*700637cbSDimitry Andric FnTy, llvm::GlobalValue::ExternalLinkage, MangledName, M);
832*700637cbSDimitry Andric }
833*700637cbSDimitry Andric return SpecConstantFn;
834*700637cbSDimitry Andric }
835