[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.

llvm-svn: 184227
This commit is contained in:
Michael Gottesman 2013-06-18 20:40:40 +00:00
parent cc0273d784
commit 1534399059
4 changed files with 46 additions and 0 deletions

View File

@ -1555,10 +1555,12 @@ The complete list of builtins are:
.. 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);

View File

@ -928,10 +928,12 @@ LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
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")

View File

@ -1345,10 +1345,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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:

View File

@ -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 @@ unsigned long long test_addcll(unsigned long long x, unsigned long long y,
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