Hi nlewycky,

Improved __builtin_constant_p() implementation to match GCC closer.
If the compiler cannot confirm that the argument is constant, the function
is lowered to a (new) llvm.is.constant intrinsic and the constantness is
evaluated again after optimisations such as inlining.

Depends on D4276

http://reviews.llvm.org/D4492

Files:
  lib/CodeGen/CGBuiltin.cpp
  test/CodeGen/builtin_constant_p.c
  test/Sema/builtin_constant_p.cpp
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -194,15 +194,52 @@
   return CGF.Builder.CreateExtractValue(Tmp, 0);
 }
 
+/// \brief Emit a call to llvm.is.constant.* intrinsic.
+/// If the argument to __builtin_constant_p() is known to be constant,
+/// or is not integral, the function returns the constant that
+/// __builtin_constant_p() folded to.
+/// Otherwise the functions emits llvm.is.constant intrinsic.
+///
+/// \arg CGF The current codegen function.
+/// \arg Result The Result, the constant __builtin_constant_p() folded to.
+/// \arg E The __builtin_constant_p() expression.
+/// \returns The result returned by the intrinsic.
+static RValue EmitIsConstantIntrinsic(CodeGenFunction &CGF,
+                               Expr::EvalResult &Result,
+                               const CallExpr *E) {
+    APSInt val = Result.Val.getInt();
+    Value *RetVal = NULL;
+    // FIXME: Add support for non-integral arguments
+    if ((val == 0) && (E->getArg(0)->getType()->isIntegralOrEnumerationType())) {
+      Value *ArgValue = CGF.EmitScalarExpr(E->getArg(0));
+      llvm::Type *ArgType = ArgValue->getType();
+      Value *F = CGF.CGM.getIntrinsic(Intrinsic::is_constant, ArgType);
+      llvm::Type *ResultType = CGF.ConvertType(E->getType());
+      RetVal = CGF.Builder.CreateCall(F, ArgValue);
+      if (RetVal->getType() != ResultType)
+        RetVal = CGF.Builder.CreateIntCast(RetVal, ResultType, /*isSigned*/false,
+                                           "cast");
+    } else {
+      RetVal = llvm::ConstantInt::get(CGF.getLLVMContext(), val);
+    }
+
+    return RValue::get(RetVal);
+  }
+
+
 RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
                                         unsigned BuiltinID, const CallExpr *E) {
   // See if we can constant fold this builtin.  If so, don't emit it at all.
   Expr::EvalResult Result;
   if (E->EvaluateAsRValue(Result, CGM.getContext()) &&
       !Result.hasSideEffects()) {
-    if (Result.Val.isInt())
-      return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
+    if (Result.Val.isInt()) {
+      if (BuiltinID == Builtin::BI__builtin_constant_p)
+        return EmitIsConstantIntrinsic(*this, Result, E);
+      else
+        return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
                                                 Result.Val.getInt()));
+    }
     if (Result.Val.isFloat())
       return RValue::get(llvm::ConstantFP::get(getLLVMContext(),
                                                Result.Val.getFloat()));
Index: test/CodeGen/builtin_constant_p.c
===================================================================
--- /dev/null
+++ test/CodeGen/builtin_constant_p.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+// Test verifies that __builtin_constant_p() is lowered to
+// llvm.is.constant intrinsic if the argument is not known
+// to be constant.
+// CHECK: @test1
+// CHECK: @llvm.is.constant
+// CHECK: {{ *ret }}
+int test1(int x) {
+  return __builtin_constant_p(x);
+}
+
+// If the argument is known to be constant, __builtin_constant_p()
+// is lowered to a constant (1)
+// CHECK: @test2
+// CHECK-NOT: @llvm.is.constant
+// CHECK: {{ *ret i[0-9]+ 1}}
+int test2() {
+  return __builtin_constant_p(12);
+}
Index: test/Sema/builtin_constant_p.cpp
===================================================================
--- /dev/null
+++ test/Sema/builtin_constant_p.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+// Check if __builtin_constant_p can be used in C++ context.
+
+// expected-no-diagnostics
+
+// Change this to '1' to convert it to an executable program.
+#define PRINT_VALUES 0
+
+#if PRINT_VALUES
+#include <iostream>
+#endif
+
+class test_class {
+public:
+  test_class(int v) : v1(__builtin_constant_p(v)), v2(__builtin_constant_p(1)), v3(v) {
+    v4 = 2 + __builtin_constant_p(v + 1);
+    v5 = 3 + v4;
+    v6 = v1 + __builtin_constant_p(v3);
+  }
+
+  static int s1, s2, s3;
+  const int v1, v2, v3;
+  int v4, v5, v6;
+
+#if PRINT_VALUES
+  bool is_constructed_from_constant() const {
+    if (v1 == 1 && v2 == 1 && v4 == 3 && v5 == 6 && v6 == 2)
+      return true;
+    return false;
+  }
+#endif
+};
+
+int x;
+const int y = 12;
+
+int test_class::s1 = __builtin_constant_p(0);
+int test_class::s2 = __builtin_constant_p(x);
+int test_class::s3 = __builtin_constant_p(y);
+
+const test_class A1(10);
+const test_class A2(y);
+
+int fun(int x) {
+  return x;
+}
+
+int test(int val) {
+  test_class B1(0);
+  test_class B2(x);
+  test_class B3(y);
+  const test_class B4(x);
+  const test_class B5(y);
+  test_class B6(val);
+  test_class B7(__builtin_constant_p(B1));
+  test_class B8(__builtin_constant_p(fun(0)));
+
+#if PRINT_VALUES
+#define xstr(s) str(s)
+#define str(s) #s
+#define P(X) std::cout << xstr(X) << ": " << X.is_constructed_from_constant() << "\n"
+  std::cout << "s1: " << test_class::s1 << "\n";
+  std::cout << "s2: " << test_class::s2 << "\n";
+  std::cout << "s3: " << test_class::s3 << "\n";
+  P(A1);
+  P(A2);
+  P(B1);
+  P(B2);
+  P(B3);
+  P(B4);
+  P(B5);
+  P(B6);
+  P(B7);
+  P(B8);
+#endif
+  return val;
+}
+
+#if PRINT_VALUES
+int main() {
+  return test(0);
+}
+#endif
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to