[clang] [llvm] [HLSL] [DXIL] Implement the `AddUint64` HLSL function and the `UAddc` DXIL op (PR #125319)

Deric Cheung via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 4 16:56:34 PST 2025


================
@@ -359,18 +359,21 @@ class OpLowerer {
     return lowerToBindAndAnnotateHandle(F);
   }
 
-  Error replaceSplitDoubleCallUsages(CallInst *Intrin, CallInst *Op) {
+  Error replaceExtractElementTypeOfCallUsages(CallInst *Intrin, CallInst *Op) {
     for (Use &U : make_early_inc_range(Intrin->uses())) {
       if (auto *EVI = dyn_cast<ExtractValueInst>(U.getUser())) {
 
         if (EVI->getNumIndices() != 1)
-          return createStringError(std::errc::invalid_argument,
-                                   "Splitdouble has only 2 elements");
+          return createStringError(
----------------
Icohedron wrote:

The new `replaceFunctionWithNamedStructOp` would look like this

```c++
  [[nodiscard]] bool replaceFunctionWithNamedStructOp(Function &F,
                                                      dxil::OpCode DXILOp,
                                                      Type *NewRetTy) {
    bool IsVectorArgExpansion = isVectorArgExpansion(F);
    return replaceFunction(F, [&](CallInst *CI) -> Error {
      SmallVector<Value *> Args;
      OpBuilder.getIRB().SetInsertPoint(CI);
      if (IsVectorArgExpansion) {
        SmallVector<Value *> NewArgs = argVectorFlatten(CI, OpBuilder.getIRB());
        Args.append(NewArgs.begin(), NewArgs.end());
      } else
        Args.append(CI->arg_begin(), CI->arg_end());

      Expected<CallInst *> OpCall =
          OpBuilder.tryCreateOp(DXILOp, Args, CI->getName(), NewRetTy);
      if (Error E = OpCall.takeError())
        return E;

      for (Use &U : make_early_inc_range(CI->uses())) {
        U.set(*OpCall);
      }
      CI->eraseFromParent();

      return Error::success();
    });
  }
```

It works. All aggregate operations (`extractvalue`, `insertvalue`) get replaced correctly.
The only issue is if a function returns the result directly:
```c++
define noundef { i32, i1 } @test_UAddc2(i32 noundef %a, i32 noundef %b) {
; CHECK-LABEL: define noundef %dx.types.i32c @test_UAddc2(
; CHECK-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) {
; CHECK-NEXT:    [[UAddc:%.*]] = call %dx.types.i32c @dx.op.binaryWithCarryOrBorrow.i32(i32 44, i32 [[A]], i32 [[B]])
; CHECK-NEXT:    ret %dx.types.i32c [[Result]]
; 
  %uaddc = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
  ret { i32, i1 } %uaddc
}
```
It results in an error that reads:
```
opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library /home/icohedron/workspace/feature-uaddc/llvm/test/CodeGen/DirectX/UAddc.ll
Function return type does not match operand type of return inst!
  ret %dx.types.i32c %uaddc1
 { i32, i1 }in function test_UAddc2
LLVM ERROR: Broken function found, compilation aborted!
...
```


https://github.com/llvm/llvm-project/pull/125319


More information about the cfe-commits mailing list