aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/TargetInfo.h7
-rw-r--r--lib/Basic/Targets.cpp1
-rw-r--r--lib/CodeGen/CGBuiltin.cpp6
-rw-r--r--test/CodeGen/builtin-count-zeros.c8
4 files changed, 18 insertions, 4 deletions
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 5e219262dd..b1e1cbdf66 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -357,6 +357,13 @@ public:
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const = 0;
+ /// isCLZForZeroUndef - The __builtin_clz* and __builtin_ctz* built-in
+ /// functions are specified to have undefined results for zero inputs, but
+ /// on targets that support these operations in a way that provides
+ /// well-defined results for zero without loss of performance, it is a good
+ /// idea to avoid optimizing based on that undef behavior.
+ virtual bool isCLZForZeroUndef() const { return true; }
+
/// getVAListDeclaration - Return the declaration to use for
/// __builtin_va_list, which is target-specific.
virtual const char *getVAListDeclaration() const = 0;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f0e3bc4b74..a557142290 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -2778,6 +2778,7 @@ public:
Records = BuiltinInfo;
NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
+ virtual bool isCLZForZeroUndef() const { return false; }
virtual const char *getVAListDeclaration() const {
return "typedef void* __builtin_va_list;";
}
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index e63eeb3c76..f4a5a82802 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -238,7 +238,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall2(F, ArgValue, Builder.getTrue());
+ Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -253,7 +254,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall2(F, ArgValue, Builder.getTrue());
+ Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
diff --git a/test/CodeGen/builtin-count-zeros.c b/test/CodeGen/builtin-count-zeros.c
index 5a0be2fb86..acd22e69a7 100644
--- a/test/CodeGen/builtin-count-zeros.c
+++ b/test/CodeGen/builtin-count-zeros.c
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep 'cttz' | count 2
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep 'ctlz' | count 2
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-ARM
int a(int a) {return __builtin_ctz(a) + __builtin_clz(a);}
+// CHECK: call i32 @llvm.cttz.i32({{.*}}, i1 true)
+// CHECK: call i32 @llvm.ctlz.i32({{.*}}, i1 true)
+// CHECK-ARM: call i32 @llvm.cttz.i32({{.*}}, i1 false)
+// CHECK-ARM: call i32 @llvm.ctlz.i32({{.*}}, i1 false)