[clang] [llvm] [HLSL] [DXIL] Implement the AddUint64 HLSL function and the UAddc DXIL op (PR #127137)
Justin Bogner via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 19 12:01:01 PST 2025
================
@@ -19445,6 +19445,70 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;
switch (BuiltinID) {
+ case Builtin::BI__builtin_hlsl_adduint64: {
+ Value *OpA = EmitScalarExpr(E->getArg(0));
+ Value *OpB = EmitScalarExpr(E->getArg(1));
+ assert(E->getArg(0)->getType()->hasIntegerRepresentation() &&
+ E->getArg(1)->getType()->hasIntegerRepresentation() &&
+ "AddUint64 operands must have an integer representation");
+ assert(((E->getArg(0)->getType()->castAs<VectorType>()->getNumElements() ==
+ 2 &&
+ E->getArg(1)->getType()->castAs<VectorType>()->getNumElements() ==
+ 2) ||
+ (E->getArg(0)->getType()->castAs<VectorType>()->getNumElements() ==
+ 4 &&
+ E->getArg(1)->getType()->castAs<VectorType>()->getNumElements() ==
+ 4)) &&
+ "input vectors must have 2 or 4 elements each");
+
+ uint64_t NumElements =
+ E->getArg(0)->getType()->castAs<VectorType>()->getNumElements();
+
+ llvm::Value *Result = PoisonValue::get(OpA->getType());
+ llvm::Value *LowA;
+ llvm::Value *HighA;
+ llvm::Value *LowB;
+ llvm::Value *HighB;
+
+ // Obtain low and high words of inputs A and B
+ if (NumElements == 2) {
+ LowA = Builder.CreateExtractElement(OpA, (uint64_t)0, "LowA");
+ HighA = Builder.CreateExtractElement(OpA, (uint64_t)1, "HighA");
+ LowB = Builder.CreateExtractElement(OpB, (uint64_t)0, "LowB");
+ HighB = Builder.CreateExtractElement(OpB, (uint64_t)1, "HighB");
+ } else {
+ LowA = Builder.CreateShuffleVector(OpA, ArrayRef<int>{0, 2}, "LowA");
+ HighA = Builder.CreateShuffleVector(OpA, ArrayRef<int>{1, 3}, "HighA");
+ LowB = Builder.CreateShuffleVector(OpB, ArrayRef<int>{0, 2}, "LowB");
+ HighB = Builder.CreateShuffleVector(OpB, ArrayRef<int>{1, 3}, "HighB");
+ }
+
+ // Use an uadd_with_overflow to compute the sum of low words and obtain a
+ // carry value
+ llvm::Value *Carry;
+ llvm::Value *LowSum = EmitOverflowIntrinsic(
+ *this, llvm::Intrinsic::uadd_with_overflow, LowA, LowB, Carry);
+ llvm::Value *ZExtCarry =
+ Builder.CreateZExt(Carry, HighA->getType(), "CarryZExt");
+
+ // Sum the high words and the carry
+ llvm::Value *HighSum = Builder.CreateAdd(HighA, HighB, "HighSum");
+ llvm::Value *HighSumPlusCarry =
+ Builder.CreateAdd(HighSum, ZExtCarry, "HighSumPlusCarry");
+
+ // Insert the low and high word sums into the result vector
+ if (NumElements == 2) {
+ Result = Builder.CreateInsertElement(Result, LowSum, (uint64_t)0,
+ "hlsl.AddUint64.upto0");
+ Result = Builder.CreateInsertElement(Result, HighSumPlusCarry,
+ (uint64_t)1, "hlsl.AddUint64");
+ } else { /* NumElements == 4 */
+ Result = Builder.CreateShuffleVector(LowSum, HighSumPlusCarry,
+ ArrayRef<int>{0, 2, 1, 3},
+ "hlsl.AddUint64");
+ }
+ return Result;
----------------
bogner wrote:
Better to return early in one of these cases. This also makes it clearer that the initial `poison` value for `Result` is only used in one branch.
```c++
if (NumElements == 4)
return Builder.CreateShuffleVector(...)
llvm::Value *Result = PoisonValue::get(OpA->getType());
// ...
return Result;
```
https://github.com/llvm/llvm-project/pull/127137
More information about the cfe-commits
mailing list