[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