[multiprecision-builtins] Added missing builtin __builtin_{add,sub}cb for {add,sub} with carry for bytes.
I have had several people ask me about why this builtin was not available in
clang (since it seems like a logical conclusion). This patch implements said
builtins.
Relevant tests are included as well. I also updated the Clang language extension reference.
rdar://14192664.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184227 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index d7e88df..af9b61a 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -1555,10 +1555,12 @@
.. code-block:: c
+ unsigned char __builtin_addcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
+ unsigned char __builtin_subcb (unsigned char x, unsigned char y, unsigned char carryin, unsigned char *carryout);
unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 3dd25b4..0da551f 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -928,10 +928,12 @@
BUILTIN(__builtin_annotation, "v.", "tn")
// Multiprecision Arithmetic Builtins.
+BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n")
BUILTIN(__builtin_addc, "UiUiCUiCUiCUi*", "n")
BUILTIN(__builtin_addcl, "ULiULiCULiCULiCULi*", "n")
BUILTIN(__builtin_addcll, "ULLiULLiCULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_subcb, "UcUcCUcCUcCUc*", "n")
BUILTIN(__builtin_subcs, "UsUsCUsCUsCUs*", "n")
BUILTIN(__builtin_subc, "UiUiCUiCUiCUi*", "n")
BUILTIN(__builtin_subcl, "ULiULiCULiCULiCULi*", "n")
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index bd5afb6d..90b8ebc 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -1345,10 +1345,12 @@
StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
+ case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
@@ -1382,12 +1384,14 @@
llvm::Intrinsic::ID IntrinsicId;
switch (BuiltinID) {
default: llvm_unreachable("Unknown multiprecision builtin id.");
+ case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
case Builtin::BI__builtin_addc:
case Builtin::BI__builtin_addcl:
case Builtin::BI__builtin_addcll:
IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
break;
+ case Builtin::BI__builtin_subcb:
case Builtin::BI__builtin_subcs:
case Builtin::BI__builtin_subc:
case Builtin::BI__builtin_subcl:
diff --git a/test/CodeGen/builtins-multiprecision.c b/test/CodeGen/builtins-multiprecision.c
index 172f683..4d19608 100644
--- a/test/CodeGen/builtins-multiprecision.c
+++ b/test/CodeGen/builtins-multiprecision.c
@@ -2,6 +2,25 @@
// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - -O3 | FileCheck %s
// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - -O3 | FileCheck %s
+unsigned char test_addcb(unsigned char x, unsigned char y,
+ unsigned char carryin, unsigned char *z) {
+ // CHECK: @test_addcb
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %x, i8 %y)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %{{.+}}, i8 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i8
+ // CHECK: store i8 %{{.+}}, i8* %z, align 1
+
+ unsigned char carryout;
+ *z = __builtin_addcb(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
unsigned short test_addcs(unsigned short x, unsigned short y,
unsigned short carryin, unsigned short *z) {
// CHECK: @test_addcs
@@ -76,6 +95,25 @@
return carryout;
}
+unsigned char test_subcb(unsigned char x, unsigned char y,
+ unsigned char carryin, unsigned char *z) {
+ // CHECK: @test_subcb
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %{{.+}}, i8 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i8, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i8
+ // CHECK: store i8 %{{.+}}, i8* %z, align 1
+
+ unsigned char carryout;
+ *z = __builtin_subcb(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
unsigned short test_subcs(unsigned short x, unsigned short y,
unsigned short carryin, unsigned short *z) {
// CHECK: @test_subcs