[llvm] r346322 - Add support for llvm.is.constant intrinsic (PR4898)

James Y Knight via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 7 07:24:13 PST 2018


Author: jyknight
Date: Wed Nov  7 07:24:12 2018
New Revision: 346322

URL: http://llvm.org/viewvc/llvm-project?rev=346322&view=rev
Log:
Add support for llvm.is.constant intrinsic (PR4898)

This adds the llvm-side support for post-inlining evaluation of the
__builtin_constant_p GCC intrinsic.

Also fixed SCCPSolver::visitCallSite to not blow up when seeing a call
to a function where canConstantFoldTo returns true, and one of the
arguments is a struct.

Updated from patch initially by Janusz Sobczak.

Differential Revision: https://reviews.llvm.org/D4276

Added:
    llvm/trunk/test/CodeGen/Generic/is-constant.ll
    llvm/trunk/test/CodeGen/X86/is-constant.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h
    llvm/trunk/include/llvm/IR/Intrinsics.td
    llvm/trunk/lib/Analysis/ConstantFolding.cpp
    llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
    llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
    llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Wed Nov  7 07:24:12 2018
@@ -15417,6 +15417,51 @@ Semantics:
 This intrinsic actually does nothing, but optimizers must assume that it
 has externally observable side effects.
 
+'``llvm.is.constant.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use llvm.is.constant with any argument type.
+
+::
+
+      declare i1 @llvm.is.constant.i32(i32 %operand) nounwind readnone
+      declare i1 @llvm.is.constant.f32(float %operand) nounwind readnone
+      declare i1 @llvm.is.constant.TYPENAME(TYPE %operand) nounwind readnone
+
+Overview:
+"""""""""
+
+The '``llvm.is.constant``' intrinsic will return true if the argument
+is known to be a manifest compile-time constant. It is guaranteed to
+fold to either true or false before generating machine code.
+
+Semantics:
+""""""""""
+
+This intrinsic generates no code. If its argument is known to be a
+manifest compile-time constant value, then the intrinsic will be
+converted to a constant true value. Otherwise, it will be converted to
+a constant false value.
+
+In particular, note that if the argument is a constant expression
+which refers to a global (the address of which _is_ a constant, but
+not manifest during the compile), then the intrinsic evaluates to
+false.
+
+The result also intentionally depends on the result of optimization
+passes -- e.g., the result can change depending on whether a
+function gets inlined or not. A function's parameters are
+obviously not constant. However, a call like
+``llvm.is.constant.i32(i32 %param)`` *can* return true after the
+function is inlined, if the value passed to the function parameter was
+a constant.
+
+On the other hand, if constant folding is not run, it will never
+evaluate to true, even in simple cases.
+
 Stack Map Intrinsics
 --------------------
 

Modified: llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h (original)
+++ llvm/trunk/include/llvm/Analysis/TargetTransformInfoImpl.h Wed Nov  7 07:24:12 2018
@@ -160,6 +160,7 @@ public:
     case Intrinsic::invariant_end:
     case Intrinsic::launder_invariant_group:
     case Intrinsic::strip_invariant_group:
+    case Intrinsic::is_constant:
     case Intrinsic::lifetime_start:
     case Intrinsic::lifetime_end:
     case Intrinsic::objectsize:

Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.td Wed Nov  7 07:24:12 2018
@@ -900,6 +900,10 @@ def int_convert_from_fp16 : Intrinsic<[l
 def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty],
                                 [], "llvm.clear_cache">;
 
+// Intrinsic to detect whether its argument is a constant.
+def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">;
+
+
 //===-------------------------- Masked Intrinsics -------------------------===//
 //
 def int_masked_store : Intrinsic<[], [llvm_anyvector_ty,

Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
+++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Wed Nov  7 07:24:12 2018
@@ -1426,6 +1426,7 @@ bool llvm::canConstantFoldCallTo(Immutab
   case Intrinsic::x86_avx512_vcvtsd2usi64:
   case Intrinsic::x86_avx512_cvttsd2usi:
   case Intrinsic::x86_avx512_cvttsd2usi64:
+  case Intrinsic::is_constant:
     return true;
   default:
     return false;
@@ -1600,11 +1601,32 @@ double getValueAsDouble(ConstantFP *Op)
   return APF.convertToDouble();
 }
 
+static bool isManifestConstant(const Constant *c) {
+  if (isa<ConstantData>(c)) {
+    return true;
+  } else if (isa<ConstantAggregate>(c) || isa<ConstantExpr>(c)) {
+    for (const Value *subc : c->operand_values()) {
+      if (!isManifestConstant(cast<Constant>(subc)))
+        return false;
+    }
+    return true;
+  }
+  return false;
+}
+
 Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
                                  ArrayRef<Constant *> Operands,
                                  const TargetLibraryInfo *TLI,
                                  ImmutableCallSite CS) {
   if (Operands.size() == 1) {
+    if (IntrinsicID == Intrinsic::is_constant) {
+      // We know we have a "Constant" argument. But we want to only
+      // return true for manifest constants, not those that depend on
+      // constants with unknowable values, e.g. GlobalValue or BlockAddress.
+      if (isManifestConstant(Operands[0]))
+        return ConstantInt::getTrue(Ty->getContext());
+      return nullptr;
+    }
     if (isa<UndefValue>(Operands[0])) {
       // cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN
       if (IntrinsicID == Intrinsic::cos)

Modified: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp Wed Nov  7 07:24:12 2018
@@ -321,6 +321,24 @@ class TypePromotionTransaction;
     }
 
   private:
+    template <typename F>
+    void resetIteratorIfInvalidatedWhileCalling(BasicBlock *BB, F f) {
+      // Substituting can cause recursive simplifications, which can invalidate
+      // our iterator.  Use a WeakTrackingVH to hold onto it in case this
+      // happens.
+      Value *CurValue = &*CurInstIterator;
+      WeakTrackingVH IterHandle(CurValue);
+
+      f();
+
+      // If the iterator instruction was recursively deleted, start over at the
+      // start of the block.
+      if (IterHandle != CurValue) {
+        CurInstIterator = BB->begin();
+        SunkAddrs.clear();
+      }
+    }
+
     bool eliminateFallThrough(Function &F);
     bool eliminateMostlyEmptyBlocks(Function &F);
     BasicBlock *findDestBlockOfMergeableEmptyBlock(BasicBlock *BB);
@@ -1690,21 +1708,18 @@ bool CodeGenPrepare::optimizeCallInst(Ca
       // Lower all uses of llvm.objectsize.*
       ConstantInt *RetVal =
           lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true);
-      // Substituting this can cause recursive simplifications, which can
-      // invalidate our iterator.  Use a WeakTrackingVH to hold onto it in case
-      // this
-      // happens.
-      Value *CurValue = &*CurInstIterator;
-      WeakTrackingVH IterHandle(CurValue);
 
-      replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
-
-      // If the iterator instruction was recursively deleted, start over at the
-      // start of the block.
-      if (IterHandle != CurValue) {
-        CurInstIterator = BB->begin();
-        SunkAddrs.clear();
-      }
+      resetIteratorIfInvalidatedWhileCalling(BB, [&]() {
+        replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
+      });
+      return true;
+    }
+    case Intrinsic::is_constant: {
+      // If is_constant hasn't folded away yet, lower it to false now.
+      Constant *RetVal = ConstantInt::get(II->getType(), 0);
+      resetIteratorIfInvalidatedWhileCalling(BB, [&]() {
+        replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr);
+      });
       return true;
     }
     case Intrinsic::aarch64_stlxr:

Modified: llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/IRTranslator.cpp Wed Nov  7 07:24:12 2018
@@ -947,6 +947,11 @@ bool IRTranslator::translateKnownIntrins
     MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0);
     return true;
   }
+  case Intrinsic::is_constant:
+    // If this wasn't constant-folded away by now, then it's not a
+    // constant.
+    MIRBuilder.buildConstant(getOrCreateVReg(CI), 0);
+    return true;
   case Intrinsic::stackguard:
     getStackGuard(getOrCreateVReg(CI), MIRBuilder);
     return true;

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/FastISel.cpp Wed Nov  7 07:24:12 2018
@@ -1450,6 +1450,14 @@ bool FastISel::selectIntrinsicCall(const
     updateValueMap(II, ResultReg);
     return true;
   }
+  case Intrinsic::is_constant: {
+    Constant *ResCI = ConstantInt::get(II->getType(), 0);
+    unsigned ResultReg = getRegForValue(ResCI);
+    if (!ResultReg)
+      return false;
+    updateValueMap(II, ResultReg);
+    return true;
+  }
   case Intrinsic::launder_invariant_group:
   case Intrinsic::strip_invariant_group:
   case Intrinsic::expect: {

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Nov  7 07:24:12 2018
@@ -5897,6 +5897,13 @@ SelectionDAGBuilder::visitIntrinsicCall(
     setValue(&I, Res);
     return nullptr;
   }
+
+  case Intrinsic::is_constant:
+    // If this wasn't constant-folded away by now, then it's not a
+    // constant.
+    setValue(&I, DAG.getConstant(0, sdl, MVT::i1));
+    return nullptr;
+
   case Intrinsic::annotation:
   case Intrinsic::ptr_annotation:
   case Intrinsic::launder_invariant_group:

Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Wed Nov  7 07:24:12 2018
@@ -1230,6 +1230,8 @@ CallOverdefined:
       SmallVector<Constant*, 8> Operands;
       for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
            AI != E; ++AI) {
+        if (AI->get()->getType()->isStructTy())
+          return markOverdefined(I); // Can't handle struct args.
         LatticeVal State = getValueState(*AI);
 
         if (State.isUnknown())

Added: llvm/trunk/test/CodeGen/Generic/is-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/is-constant.ll?rev=346322&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Generic/is-constant.ll (added)
+++ llvm/trunk/test/CodeGen/Generic/is-constant.ll Wed Nov  7 07:24:12 2018
@@ -0,0 +1,114 @@
+; RUN: opt -O2 -S < %s  | FileCheck %s
+; RUN: llc -o /dev/null 2>&1 < %s
+; RUN: llc -O0 -o /dev/null 2>&1 < %s
+
+;; The llc runs above are just to ensure it doesn't blow up upon
+;; seeing an is_constant intrinsic.
+
+declare i1 @llvm.is.constant.i32(i32 %a)
+declare i1 @llvm.is.constant.i64(i64 %a)
+declare i1 @llvm.is.constant.i256(i256 %a)
+declare i1 @llvm.is.constant.v2i64(<2 x i64> %a)
+declare i1 @llvm.is.constant.f32(float %a)
+declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a)
+declare i1 @llvm.is.constant.a2i32([2 x i32] %a)
+declare i1 @llvm.is.constant.p0i64(i64* %a)
+
+;; Basic test that optimization folds away the is.constant when given
+;; a constant.
+define i1 @test_constant() #0 {
+; CHECK-LABEL: @test_constant(
+; CHECK-NOT: llvm.is.constant
+; CHECK: ret i1 true
+%y = call i1 @llvm.is.constant.i32(i32 44)
+  ret i1 %y
+}
+
+;; And test that the intrinsic sticks around when given a
+;; non-constant.
+define i1 @test_nonconstant(i32 %x) #0 {
+; CHECK-LABEL: @test_nonconstant(
+; CHECK: @llvm.is.constant
+  %y = call i1 @llvm.is.constant.i32(i32 %x)
+  ret i1 %y
+}
+
+;; Ensure that nested is.constants fold.
+define i32 @test_nested() #0 {
+; CHECK-LABEL: @test_nested(
+; CHECK-NOT: llvm.is.constant
+; CHECK: ret i32 13
+  %val1 = call i1 @llvm.is.constant.i32(i32 27)
+  %val2 = zext i1 %val1 to i32
+  %val3 = add i32 %val2, 12
+  %1 = call i1 @llvm.is.constant.i32(i32 %val3)
+  %2 = zext i1 %1 to i32
+  %3 = add i32 %2, 12
+  ret i32 %3
+}
+
+ at G = global [2 x i64] zeroinitializer
+define i1 @test_global() #0 {
+; CHECK-LABEL: @test_global(
+; CHECK: llvm.is.constant
+  %ret = call i1 @llvm.is.constant.p0i64(i64* getelementptr ([2 x i64], [2 x i64]* @G, i32 0, i32 0))
+  ret i1 %ret
+}
+
+define i1 @test_diff() #0 {
+; CHECK-LABEL: @test_diff(
+  %ret = call i1 @llvm.is.constant.i64(i64 sub (
+      i64 ptrtoint (i64* getelementptr inbounds ([2 x i64], [2 x i64]* @G, i64 0, i64 1) to i64),
+      i64 ptrtoint ([2 x i64]* @G to i64)))
+  ret i1 %ret
+}
+
+define i1 @test_various_types(i256 %int, float %float, <2 x i64> %vec, {i32, i32} %struct, [2 x i32] %arr, i64* %ptr) #0 {
+; CHECK-LABEL: @test_various_types(
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK: llvm.is.constant
+; CHECK-NOT: llvm.is.constant
+  %v1 = call i1 @llvm.is.constant.i256(i256 %int)
+  %v2 = call i1 @llvm.is.constant.f32(float %float)
+  %v3 = call i1 @llvm.is.constant.v2i64(<2 x i64> %vec)
+  %v4 = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} %struct)
+  %v5 = call i1 @llvm.is.constant.a2i32([2 x i32] %arr)
+  %v6 = call i1 @llvm.is.constant.p0i64(i64* %ptr)
+
+  %c1 = call i1 @llvm.is.constant.i256(i256 -1)
+  %c2 = call i1 @llvm.is.constant.f32(float 17.0)
+  %c3 = call i1 @llvm.is.constant.v2i64(<2 x i64> <i64 -1, i64 44>)
+  %c4 = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} {i32 -1, i32 32})
+  %c5 = call i1 @llvm.is.constant.a2i32([2 x i32] [i32 -1, i32 32])
+  %c6 = call i1 @llvm.is.constant.p0i64(i64* inttoptr (i32 42 to i64*))
+
+  %x1 = add i1 %v1, %c1
+  %x2 = add i1 %v2, %c2
+  %x3 = add i1 %v3, %c3
+  %x4 = add i1 %v4, %c4
+  %x5 = add i1 %v5, %c5
+  %x6 = add i1 %v6, %c6
+
+  %res2 = add i1 %x1, %x2
+  %res3 = add i1 %res2, %x3
+  %res4 = add i1 %res3, %x4
+  %res5 = add i1 %res4, %x5
+  %res6 = add i1 %res5, %x6
+
+  ret i1 %res6
+}
+
+define i1 @test_various_types2() #0 {
+; CHECK-LABEL: @test_various_types2(
+; CHECK: ret i1 false
+  %r = call i1 @test_various_types(i256 -1, float 22.0, <2 x i64> <i64 -1, i64 44>,
+                     {i32, i32} {i32 -1, i32 55}, [2 x i32] [i32 -1, i32 55],
+		     i64* inttoptr (i64 42 to i64*))
+  ret i1 %r
+}
+
+attributes #0 = { nounwind uwtable }

Added: llvm/trunk/test/CodeGen/X86/is-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/is-constant.ll?rev=346322&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/is-constant.ll (added)
+++ llvm/trunk/test/CodeGen/X86/is-constant.ll Wed Nov  7 07:24:12 2018
@@ -0,0 +1,50 @@
+; RUN: llc -O2 < %s | FileCheck %s --check-prefix=CHECK-O2 --check-prefix=CHECK
+; RUN: llc -O0 -fast-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+; RUN: llc -O0 -fast-isel=0 < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+; RUN: llc -O0 -global-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
+
+;; Ensure that an unfoldable is.constant gets lowered reasonably in
+;; optimized codegen, in particular, that the "true" branch is
+;; eliminated.
+;;
+;; This isn't asserting any specific output from non-optimized runs,
+;; (e.g., currently the not-taken branch does not get eliminated). But
+;; it does ensure that lowering succeeds in all 3 codegen paths.
+
+target triple = "x86_64-unknown-linux-gnu"
+
+declare i1 @llvm.is.constant.i32(i32 %a) nounwind readnone
+declare i1 @llvm.is.constant.i64(i64 %a) nounwind readnone
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1) nounwind readnone
+
+declare i32 @subfun_1()
+declare i32 @subfun_2()
+
+define i32 @test_branch(i32 %in) nounwind {
+; CHECK-LABEL:    test_branch:
+; CHECK-O2:       %bb.0:
+; CHECK-O2-NEXT:  jmp subfun_2
+  %v = call i1 @llvm.is.constant.i32(i32 %in)
+  br i1 %v, label %True, label %False
+
+True:
+  %call1 = tail call i32 @subfun_1()
+  ret i32 %call1
+
+False:
+  %call2 = tail call i32 @subfun_2()
+  ret i32 %call2
+}
+
+;; llvm.objectsize is another tricky case which gets folded to -1 very
+;; late in the game. We'd like to ensure that llvm.is.constant of
+;; llvm.objectsize is true.
+define i1 @test_objectsize(i8* %obj) nounwind {
+; CHECK-LABEL:    test_objectsize:
+; CHECK-O2:       %bb.0:
+; CHECK-O2:       movb $1, %al
+; CHECK-O2-NEXT:  retq
+  %os = call i64 @llvm.objectsize.i64.p0i8(i8* %obj, i1 false, i1 false)
+  %v = call i1 @llvm.is.constant.i64(i64 %os)
+  ret i1 %v
+}

Modified: llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll?rev=346322&r1=346321&r2=346322&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll (original)
+++ llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll Wed Nov  7 07:24:12 2018
@@ -258,3 +258,16 @@ define i64 @test11b() {
 }
 
 declare i64 @llvm.ctpop.i64(i64)
+
+;;======================== test12
+;; Ensure that a struct as an arg to a potentially constant-foldable
+;; function does not crash SCCP (for now it'll just ignores it)
+
+define i1 @test12() {
+  %c = call i1 @llvm.is.constant.sl_i32i32s({i32, i32} {i32 -1, i32 32})
+  ret i1 %c
+; CHECK-LABEL: define i1 @test12
+; CHECK: ret i1 %c
+}
+
+declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a)




More information about the llvm-commits mailing list