Skip to content

Commit 2bc239b

Browse files
committed
Implement the UAddc DXIL op to lower AddUint64 to DXIL
1 parent 1e194fd commit 2bc239b

File tree

6 files changed

+86
-5
lines changed

6 files changed

+86
-5
lines changed

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def HandleTy : DXILOpParamType;
5050
def ResBindTy : DXILOpParamType;
5151
def ResPropsTy : DXILOpParamType;
5252
def SplitDoubleTy : DXILOpParamType;
53+
def BinaryWithCarryTy : DXILOpParamType;
5354

5455
class DXILOpClass;
5556

@@ -738,6 +739,18 @@ def UMin : DXILOp<40, binary> {
738739
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
739740
}
740741

742+
def UAddc : DXILOp<44, binaryWithCarryOrBorrow > {
743+
let Doc = "Unsigned 32-bit integer arithmetic add with carry. uaddc(a,b) = (a+b, a+b overflowed ? 1 : 0)";
744+
// TODO: This `let intrinsics = ...` line may be uncommented when
745+
// https://github.com/llvm/llvm-project/issues/113192 is fixed
746+
// let intrinsics = [IntrinSelect<int_uadd_with_overflow>];
747+
let arguments = [OverloadTy, OverloadTy];
748+
let result = BinaryWithCarryTy;
749+
let overloads = [Overloads<DXIL1_0, [Int32Ty]>];
750+
let stages = [Stages<DXIL1_0, [all_stages]>];
751+
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
752+
}
753+
741754
def FMad : DXILOp<46, tertiary> {
742755
let Doc = "Floating point arithmetic multiply/add operation. fmad(m,a,b) = m "
743756
"* a + b.";

llvm/lib/Target/DirectX/DXILOpBuilder.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,14 @@ static StructType *getSplitDoubleType(LLVMContext &Context) {
230230
return StructType::create({Int32Ty, Int32Ty}, "dx.types.splitdouble");
231231
}
232232

233+
static StructType *getBinaryWithCarryType(LLVMContext &Context) {
234+
if (auto *ST = StructType::getTypeByName(Context, "dx.types.i32c"))
235+
return ST;
236+
Type *Int32Ty = Type::getInt32Ty(Context);
237+
Type *Int1Ty= Type::getInt1Ty(Context);
238+
return StructType::create({Int32Ty, Int1Ty}, "dx.types.i32c");
239+
}
240+
233241
static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
234242
Type *OverloadTy) {
235243
switch (Kind) {
@@ -273,6 +281,8 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
273281
return getResPropsType(Ctx);
274282
case OpParamType::SplitDoubleTy:
275283
return getSplitDoubleType(Ctx);
284+
case OpParamType::BinaryWithCarryTy:
285+
return getBinaryWithCarryType(Ctx);
276286
}
277287
llvm_unreachable("Invalid parameter kind");
278288
return nullptr;
@@ -539,6 +549,10 @@ StructType *DXILOpBuilder::getSplitDoubleType(LLVMContext &Context) {
539549
return ::getSplitDoubleType(Context);
540550
}
541551

552+
StructType *DXILOpBuilder::getBinaryWithCarryType(LLVMContext &Context) {
553+
return ::getBinaryWithCarryType(Context);
554+
}
555+
542556
StructType *DXILOpBuilder::getHandleType() {
543557
return ::getHandleType(IRB.getContext());
544558
}

llvm/lib/Target/DirectX/DXILOpBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class DXILOpBuilder {
5353
/// Get the `%dx.types.splitdouble` type.
5454
StructType *getSplitDoubleType(LLVMContext &Context);
5555

56+
/// Get the `%dx.types.i32c` type.
57+
StructType *getBinaryWithCarryType(LLVMContext &Context);
58+
5659
/// Get the `%dx.types.Handle` type.
5760
StructType *getHandleType();
5861

llvm/lib/Target/DirectX/DXILOpLowering.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,17 +359,16 @@ class OpLowerer {
359359
return lowerToBindAndAnnotateHandle(F);
360360
}
361361

362-
Error replaceSplitDoubleCallUsages(CallInst *Intrin, CallInst *Op) {
362+
Error replaceExtractElementTypeOfCallUsages(CallInst *Intrin, CallInst *Op) {
363363
for (Use &U : make_early_inc_range(Intrin->uses())) {
364364
if (auto *EVI = dyn_cast<ExtractValueInst>(U.getUser())) {
365365

366366
if (EVI->getNumIndices() != 1)
367-
return createStringError(std::errc::invalid_argument,
368-
"Splitdouble has only 2 elements");
367+
return createStringError(std::errc::invalid_argument, (std::string(Intrin->getOpcodeName()) + " has only 2 elements").c_str());
369368
EVI->setOperand(0, Op);
370369
} else {
371370
return make_error<StringError>(
372-
"Splitdouble use is not ExtractValueInst",
371+
(std::string(Intrin->getOpcodeName()) + " use is not ExtractValueInst").c_str(),
373372
inconvertibleErrorCode());
374373
}
375374
}
@@ -821,7 +820,17 @@ class OpLowerer {
821820
F, OpCode::SplitDouble,
822821
OpBuilder.getSplitDoubleType(M.getContext()),
823822
[&](CallInst *CI, CallInst *Op) {
824-
return replaceSplitDoubleCallUsages(CI, Op);
823+
return replaceExtractElementTypeOfCallUsages(CI, Op);
824+
});
825+
break;
826+
// TODO: this can be removed when
827+
// https://github.com/llvm/llvm-project/issues/113192 is fixed
828+
case Intrinsic::uadd_with_overflow:
829+
HasErrors |= replaceFunctionWithNamedStructOp(
830+
F, OpCode::UAddc,
831+
OpBuilder.getBinaryWithCarryType(M.getContext()),
832+
[&](CallInst *CI, CallInst *Op) {
833+
return replaceExtractElementTypeOfCallUsages(CI, Op);
825834
});
826835
break;
827836
case Intrinsic::ctpop:

llvm/test/CodeGen/DirectX/UAddc.ll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
2+
3+
; CHECK: %dx.types.i32c = type { i32, i1 }
4+
5+
define noundef i32 @test_UAddc(i32 noundef %a, i32 noundef %b) {
6+
; CHECK-LABEL: define noundef i32 @test_UAddc(
7+
; CHECK-SAME: i32 noundef [[A:%.*]], i32 noundef [[B:%.*]]) {
8+
; CHECK-NEXT: [[UAddc:%.*]] = call %dx.types.i32c @dx.op.binaryWithCarryOrBorrow.i32(i32 44, i32 [[A]], i32 [[B]])
9+
; CHECK-NEXT: [[Carry:%.*]] = extractvalue %dx.types.i32c [[UAddc]], 1
10+
; CHECK-NEXT: [[Sum:%.*]] = extractvalue %dx.types.i32c [[UAddc]], 0
11+
; CHECK-NEXT: [[CarryZExt:%.*]] = zext i1 [[Carry]] to i32
12+
; CHECK-NEXT: [[Result:%.*]] = add i32 [[Sum]], [[CarryZExt]]
13+
; CHECK-NEXT: ret i32 [[Result]]
14+
;
15+
%uaddc = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)
16+
%carry = extractvalue { i32, i1 } %uaddc, 1
17+
%sum = extractvalue { i32, i1 } %uaddc, 0
18+
%carry_zext = zext i1 %carry to i32
19+
%result = add i32 %sum, %carry_zext
20+
ret i32 %result
21+
}
22+
23+
declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32)
24+
; CHECK: declare %dx.types.i32c @dx.op.binaryWithCarryOrBorrow.i32(i32, i32, i32)
25+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
2+
3+
; DXIL operation UAddc only supports i32. Other integer types are unsupported.
4+
; CHECK: in function uaddc_i16
5+
; CHECK-SAME: Cannot create UAddc operation: Invalid overload type
6+
7+
define noundef i16 @uaddc_i16(i16 noundef %a, i16 noundef %b) {
8+
%uaddc = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
9+
%carry = extractvalue { i16, i1 } %uaddc, 1
10+
%sum = extractvalue { i16, i1 } %uaddc, 0
11+
%carry_zext = zext i1 %carry to i16
12+
%result = add i16 %sum, %carry_zext
13+
ret i16 %result
14+
}
15+
16+
declare { i16, i1 } @llvm.uadd.with.overflow.i16(i16, i16)
17+

0 commit comments

Comments
 (0)