diff options
-rw-r--r-- | include/clang/Basic/TargetInfo.h | 7 | ||||
-rw-r--r-- | lib/Basic/Targets.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 6 | ||||
-rw-r--r-- | test/CodeGen/builtin-count-zeros.c | 8 |
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) |