]> granicus.if.org Git - llvm/commitdiff
Reapply r374743 with a fix for the ocaml binding
authorJoerg Sonnenberger <joerg@bec.de>
Mon, 14 Oct 2019 16:15:14 +0000 (16:15 +0000)
committerJoerg Sonnenberger <joerg@bec.de>
Mon, 14 Oct 2019 16:15:14 +0000 (16:15 +0000)
Add a pass to lower is.constant and objectsize intrinsics

This pass lowers is.constant and objectsize intrinsics not simplified by
earlier constant folding, i.e. if the object given is not constant or if
not using the optimized pass chain. The result is recursively simplified
and constant conditionals are pruned, so that dead blocks are removed
even for -O0. This allows inline asm blocks with operand constraints to
work all the time.

The new pass replaces the existing lowering in the codegen-prepare pass
and fallbacks in SDAG/GlobalISEL and FastISel. The latter now assert
on the intrinsics.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374784 91177308-0d34-0410-b5e6-96231b3b80d8

39 files changed:
bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.ml
bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli
bindings/ocaml/transforms/scalar_opts/scalar_opts_ocaml.c
include/llvm-c/Transforms/Scalar.h
include/llvm/InitializePasses.h
include/llvm/LinkAllPasses.h
include/llvm/Transforms/Scalar.h
include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h [new file with mode: 0644]
lib/CodeGen/CodeGenPrepare.cpp
lib/CodeGen/GlobalISel/IRTranslator.cpp
lib/CodeGen/SelectionDAG/FastISel.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/TargetPassConfig.cpp
lib/Passes/PassBuilder.cpp
lib/Passes/PassRegistry.def
lib/Transforms/IPO/PassManagerBuilder.cpp
lib/Transforms/Scalar/CMakeLists.txt
lib/Transforms/Scalar/LowerConstantIntrinsics.cpp [new file with mode: 0644]
lib/Transforms/Scalar/Scalar.cpp
test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll
test/CodeGen/AArch64/O0-pipeline.ll
test/CodeGen/AArch64/O3-pipeline.ll
test/CodeGen/ARM/O3-pipeline.ll
test/CodeGen/Generic/is-constant.ll [deleted file]
test/CodeGen/X86/O0-pipeline.ll
test/CodeGen/X86/O3-pipeline.ll
test/CodeGen/X86/is-constant.ll [deleted file]
test/CodeGen/X86/object-size.ll [deleted file]
test/Other/new-pm-defaults.ll
test/Other/new-pm-thinlto-defaults.ll
test/Other/opt-O2-pipeline.ll
test/Other/opt-O3-pipeline.ll
test/Other/opt-Os-pipeline.ll
test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll
test/Transforms/CodeGenPrepare/builtin-condition.ll [deleted file]
test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll [new file with mode: 0644]
test/Transforms/LowerConstantIntrinsics/crash-on-large-allocas.ll [moved from test/Transforms/CodeGenPrepare/crash-on-large-allocas.ll with 87% similarity]
test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll [moved from test/Transforms/CodeGenPrepare/basic.ll with 94% similarity]
utils/gn/secondary/llvm/lib/Transforms/Scalar/BUILD.gn

index 6864076053b67a173c095595efc10aa00255a585..4d905533936a6524e4bda132c3d8362ab77a08a4 100644 (file)
@@ -114,6 +114,9 @@ external add_early_cse
 external add_lower_expect_intrinsic
   : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
   = "llvm_add_lower_expect_intrinsic"
+external add_lower_constant_intrinsics
+  : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
+  = "llvm_add_lower_constant_intrinsics"
 external add_type_based_alias_analysis
   : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
   = "llvm_add_type_based_alias_analysis"
index 8970431aeab27a1bbbc9ad76d7f53b89791072ea..117218f06608e2d9e1ea63ad756df831449de667 100644 (file)
@@ -191,6 +191,11 @@ external add_lower_expect_intrinsic
   : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
   = "llvm_add_lower_expect_intrinsic"
 
+(** See the [llvm::createLowerConstantIntrinsicsPass] function. *)
+external add_lower_constant_intrinsics
+  : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
+  = "llvm_add_lower_constant_intrinsics"
+
 (** See the [llvm::createTypeBasedAliasAnalysisPass] function. *)
 external add_type_based_alias_analysis
   : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit
index 56ebbf3c43c76c2944a1132ce071edcdf3ea5125..8d10989bd667163b1194a76b09f43638569d0871 100644 (file)
@@ -236,6 +236,12 @@ CAMLprim value llvm_add_lower_expect_intrinsic(LLVMPassManagerRef PM) {
   return Val_unit;
 }
 
+/* [<Llvm.PassManager.any] Llvm.PassManager.t -> unit */
+CAMLprim value llvm_add_lower_constant_intrinsics(LLVMPassManagerRef PM) {
+  LLVMAddLowerConstantIntrinsicsPass(PM);
+  return Val_unit;
+}
+
 /* [<Llvm.PassManager.any] Llvm.PassManager.t -> unit */
 CAMLprim value llvm_add_type_based_alias_analysis(LLVMPassManagerRef PM) {
   LLVMAddTypeBasedAliasAnalysisPass(PM);
index 484ac90ab5d594818cd965920285f046e4d7ee3f..6f3a3d8b3750f663aacfa6bfa9bd933ebc56a41e 100644 (file)
@@ -147,6 +147,9 @@ void LLVMAddEarlyCSEMemSSAPass(LLVMPassManagerRef PM);
 /** See llvm::createLowerExpectIntrinsicPass function */
 void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM);
 
+/** See llvm::createLowerConstantIntrinsicsPass function */
+void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM);
+
 /** See llvm::createTypeBasedAliasAnalysisPass function */
 void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM);
 
index f7888b4fb5764b0ea4f83893572dd91b6354cfbd..49f69340c8282afe3afe042d5663bf44e4681754 100644 (file)
@@ -243,6 +243,7 @@ void initializeLoopVectorizePass(PassRegistry&);
 void initializeLoopVersioningLICMPass(PassRegistry&);
 void initializeLoopVersioningPassPass(PassRegistry&);
 void initializeLowerAtomicLegacyPassPass(PassRegistry&);
+void initializeLowerConstantIntrinsicsPass(PassRegistry&);
 void initializeLowerEmuTLSPass(PassRegistry&);
 void initializeLowerExpectIntrinsicPass(PassRegistry&);
 void initializeLowerGuardIntrinsicLegacyPassPass(PassRegistry&);
index a285d172a5c1306e6708c4ce133d96ff2578270c..ac88165845d3c5f73ad5c645b361b37bc57db5ca 100644 (file)
@@ -140,6 +140,7 @@ namespace {
       (void) llvm::createLoopVersioningLICMPass();
       (void) llvm::createLoopIdiomPass();
       (void) llvm::createLoopRotatePass();
+      (void) llvm::createLowerConstantIntrinsicsPass();
       (void) llvm::createLowerExpectIntrinsicPass();
       (void) llvm::createLowerInvokePass();
       (void) llvm::createLowerSwitchPass();
index 7418dcfc1ed570240a5d4512c6dcab49b831bcd8..f06230b6f366b0ddb2391083f25ae0c5788351ac 100644 (file)
@@ -395,6 +395,13 @@ extern char &InferAddressSpacesID;
 // "block_weights" metadata.
 FunctionPass *createLowerExpectIntrinsicPass();
 
+//===----------------------------------------------------------------------===//
+//
+// LowerConstantIntrinsicss - Expand any remaining llvm.objectsize and
+// llvm.is.constant intrinsic calls, even for the unknown cases.
+//
+FunctionPass *createLowerConstantIntrinsicsPass();
+
 //===----------------------------------------------------------------------===//
 //
 // PartiallyInlineLibCalls - Tries to inline the fast path of library
diff --git a/include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h b/include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h
new file mode 100644 (file)
index 0000000..a5ad4a2
--- /dev/null
@@ -0,0 +1,41 @@
+//===- LowerConstantIntrinsics.h - Lower constant int. pass -*- C++ -*-========//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// The header file for the LowerConstantIntrinsics pass as used by the new pass
+/// manager.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_LOWERCONSTANTINTRINSICS_H
+#define LLVM_TRANSFORMS_SCALAR_LOWERCONSTANTINTRINSICS_H
+
+#include "llvm/IR/Function.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+struct LowerConstantIntrinsicsPass :
+    PassInfoMixin<LowerConstantIntrinsicsPass> {
+public:
+  explicit LowerConstantIntrinsicsPass() {}
+
+  /// Run the pass over the function.
+  ///
+  /// This will lower all remaining 'objectsize' and 'is.constant'`
+  /// intrinsic calls in this function, even when the argument has no known
+  /// size or is not a constant respectively. The resulting constant is
+  /// propagated and conditional branches are resolved where possible.
+  /// This complements the Instruction Simplification and
+  /// Instruction Combination passes of the optimized pass chain.
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &);
+};
+
+}
+
+#endif
index 0594d5fe1b1b583cfb908ed15420192ea54f78c9..061c8e51a99718580b4bfe381409cdd6bd1e4c10 100644 (file)
@@ -1868,24 +1868,10 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool &ModifiedDT) {
       });
       return true;
     }
-    case Intrinsic::objectsize: {
-      // Lower all uses of llvm.objectsize.*
-      Value *RetVal =
-          lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true);
-
-      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::objectsize:
+      llvm_unreachable("llvm.objectsize.* should have been lowered already");
+    case Intrinsic::is_constant:
+      llvm_unreachable("llvm.is.constant.* should have been lowered already");
     case Intrinsic::aarch64_stlxr:
     case Intrinsic::aarch64_stxr: {
       ZExtInst *ExtVal = dyn_cast<ZExtInst>(CI->getArgOperand(0));
index 08f3e4f5bd34ef60625ce521d778b540a2bef471..1d1eea4d23d703393a6acee7e250c1f39e9c6f74 100644 (file)
@@ -1437,18 +1437,12 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
     MIRBuilder.buildConstant(Reg, TypeID);
     return true;
   }
-  case Intrinsic::objectsize: {
-    // If we don't know by now, we're never going to know.
-    const ConstantInt *Min = cast<ConstantInt>(CI.getArgOperand(1));
+  case Intrinsic::objectsize:
+    llvm_unreachable("llvm.objectsize.* should have been lowered already");
 
-    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;
+    llvm_unreachable("llvm.is.constant.* should have been lowered already");
+
   case Intrinsic::stackguard:
     getStackGuard(getOrCreateVReg(CI), MIRBuilder);
     return true;
index 0fd2bd7815ba14243dbf0e82881a68de0816e4ce..347776b2367b04eca9865a86360ba548058b48d8 100644 (file)
@@ -1454,24 +1454,12 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
             TII.get(TargetOpcode::DBG_LABEL)).addMetadata(DI->getLabel());
     return true;
   }
-  case Intrinsic::objectsize: {
-    ConstantInt *CI = cast<ConstantInt>(II->getArgOperand(1));
-    unsigned long long Res = CI->isZero() ? -1ULL : 0;
-    Constant *ResCI = ConstantInt::get(II->getType(), Res);
-    unsigned ResultReg = getRegForValue(ResCI);
-    if (!ResultReg)
-      return false;
-    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::objectsize:
+    llvm_unreachable("llvm.objectsize.* should have been lowered already");
+
+  case Intrinsic::is_constant:
+    llvm_unreachable("llvm.is.constant.* should have been lowered already");
+
   case Intrinsic::launder_invariant_group:
   case Intrinsic::strip_invariant_group:
   case Intrinsic::expect: {
index 3c36cc6f6599cdac6dfa9300ca074831c62118b5..9a29a010c14e15d6f80fc16ef3fe0066ff71736b 100644 (file)
@@ -6388,29 +6388,11 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
     DAG.setRoot(Res);
     return;
   }
-  case Intrinsic::objectsize: {
-    // If we don't know by now, we're never going to know.
-    ConstantInt *CI = dyn_cast<ConstantInt>(I.getArgOperand(1));
-
-    assert(CI && "Non-constant type in __builtin_object_size?");
-
-    SDValue Arg = getValue(I.getCalledValue());
-    EVT Ty = Arg.getValueType();
-
-    if (CI->isZero())
-      Res = DAG.getConstant(-1ULL, sdl, Ty);
-    else
-      Res = DAG.getConstant(0, sdl, Ty);
-
-    setValue(&I, Res);
-    return;
-  }
+  case Intrinsic::objectsize:
+    llvm_unreachable("llvm.objectsize.* should have been lowered already");
 
   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;
+    llvm_unreachable("llvm.is.constant.* should have been lowered already");
 
   case Intrinsic::annotation:
   case Intrinsic::ptr_annotation:
index ba780e718bbe96bb1b2ccec36a885c0a637470f7..f1f4f65adf7c2a48d69947586bb416a99b7a6c33 100644 (file)
@@ -657,6 +657,7 @@ void TargetPassConfig::addIRPasses() {
   // TODO: add a pass insertion point here
   addPass(createGCLoweringPass());
   addPass(createShadowStackGCLoweringPass());
+  addPass(createLowerConstantIntrinsicsPass());
 
   // Make sure that no unreachable blocks are instruction selected.
   addPass(createUnreachableBlockEliminationPass());
index bfa3ecfb2806024eacbccc4e420effd635a37c59..25558e1b5146b71dba5d39ab795f2b7cb6ef818f 100644 (file)
 #include "llvm/Transforms/Scalar/LoopUnrollAndJamPass.h"
 #include "llvm/Transforms/Scalar/LoopUnrollPass.h"
 #include "llvm/Transforms/Scalar/LowerAtomic.h"
+#include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h"
 #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
 #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h"
 #include "llvm/Transforms/Scalar/LowerWidenableCondition.h"
@@ -891,6 +892,8 @@ ModulePassManager PassBuilder::buildModuleOptimizationPipeline(
 
   FunctionPassManager OptimizePM(DebugLogging);
   OptimizePM.addPass(Float2IntPass());
+  OptimizePM.addPass(LowerConstantIntrinsicsPass());
+
   // FIXME: We need to run some loop optimizations to re-rotate loops after
   // simplify-cfg and others undo their rotation.
 
index eb350cb665f5d16bfc56ce0691fcc1fbb46bcb6b..1fa274d172b19aeea1aa6ded1db9ec1f266c1514 100644 (file)
@@ -187,6 +187,7 @@ FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass())
 FUNCTION_PASS("loweratomic", LowerAtomicPass())
 FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass())
 FUNCTION_PASS("lower-guard-intrinsic", LowerGuardIntrinsicPass())
+FUNCTION_PASS("lower-constant-intrinsics", LowerConstantIntrinsicsPass())
 FUNCTION_PASS("lower-widenable-condition", LowerWidenableConditionPass())
 FUNCTION_PASS("guard-widening", GuardWideningPass())
 FUNCTION_PASS("gvn", GVN())
index 3ea77f08fd3c39b1eb63b6cf2bc8d4e027cf8c54..5314a8219b1eafb90b56db753c02228362a000f1 100644 (file)
@@ -654,6 +654,7 @@ void PassManagerBuilder::populateModulePassManager(
   MPM.add(createGlobalsAAWrapperPass());
 
   MPM.add(createFloat2IntPass());
+  MPM.add(createLowerConstantIntrinsicsPass());
 
   addExtensionsToPM(EP_VectorizerStart, MPM);
 
index e6f8901ec81d1cd706f99899a887034be089d757..89c2faebfbc07f72802325f9cf4d0d041741a8b9 100644 (file)
@@ -44,6 +44,7 @@ add_llvm_library(LLVMScalarOpts
   LoopUnswitch.cpp
   LoopVersioningLICM.cpp
   LowerAtomic.cpp
+  LowerConstantIntrinsics.cpp
   LowerExpectIntrinsic.cpp
   LowerGuardIntrinsic.cpp
   LowerWidenableCondition.cpp
diff --git a/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp b/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp
new file mode 100644 (file)
index 0000000..d0fcf38
--- /dev/null
@@ -0,0 +1,170 @@
+//===- LowerConstantIntrinsics.cpp - Lower constant intrinsic calls -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass lowers all remaining 'objectsize' 'is.constant' intrinsic calls
+// and provides constant propagation and basic CFG cleanup on the result.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/MemoryBuiltins.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+#define DEBUG_TYPE "lower-is-constant-intrinsic"
+
+STATISTIC(IsConstantIntrinsicsHandled,
+          "Number of 'is.constant' intrinsic calls handled");
+STATISTIC(ObjectSizeIntrinsicsHandled,
+          "Number of 'objectsize' intrinsic calls handled");
+
+static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {
+  Value *Op = II->getOperand(0);
+
+  return isa<Constant>(Op) ? ConstantInt::getTrue(II->getType())
+                           : ConstantInt::getFalse(II->getType());
+}
+
+static bool replaceConditionalBranchesOnConstant(Instruction *II,
+                                                 Value *NewValue) {
+  bool HasDeadBlocks = false;
+  SmallSetVector<Instruction *, 8> Worklist;
+  replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,
+                                &Worklist);
+  for (auto I : Worklist) {
+    BranchInst *BI = dyn_cast<BranchInst>(I);
+    if (!BI)
+      continue;
+    if (BI->isUnconditional())
+      continue;
+
+    BasicBlock *Target, *Other;
+    if (match(BI->getOperand(0), m_Zero())) {
+      Target = BI->getSuccessor(1);
+      Other = BI->getSuccessor(0);
+    } else if (match(BI->getOperand(0), m_One())) {
+      Target = BI->getSuccessor(0);
+      Other = BI->getSuccessor(1);
+    } else {
+      Target = nullptr;
+      Other = nullptr;
+    }
+    if (Target && Target != Other) {
+      BasicBlock *Source = BI->getParent();
+      Other->removePredecessor(Source);
+      BI->eraseFromParent();
+      BranchInst::Create(Target, Source);
+      if (pred_begin(Other) == pred_end(Other))
+        HasDeadBlocks = true;
+    }
+  }
+  return HasDeadBlocks;
+}
+
+static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI) {
+  bool HasDeadBlocks = false;
+  const auto &DL = F.getParent()->getDataLayout();
+  SmallVector<WeakTrackingVH, 8> Worklist;
+
+  ReversePostOrderTraversal<Function *> RPOT(&F);
+  for (BasicBlock *BB : RPOT) {
+    for (Instruction &I: *BB) {
+      IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
+      if (!II)
+        continue;
+      switch (II->getIntrinsicID()) {
+      default:
+        break;
+      case Intrinsic::is_constant:
+      case Intrinsic::objectsize:
+        Worklist.push_back(WeakTrackingVH(&I));
+        break;
+      }
+    }
+  }
+  for (WeakTrackingVH &VH: Worklist) {
+    // Items on the worklist can be mutated by earlier recursive replaces.
+    // This can remove the intrinsic as dead (VH == null), but also replace
+    // the intrinsic in place.
+    if (!VH)
+      continue;
+    IntrinsicInst *II = dyn_cast<IntrinsicInst>(&*VH);
+    if (!II)
+      continue;
+    Value *NewValue;
+    switch (II->getIntrinsicID()) {
+    default:
+      continue;
+    case Intrinsic::is_constant:
+      NewValue = lowerIsConstantIntrinsic(II);
+      IsConstantIntrinsicsHandled++;
+      break;
+    case Intrinsic::objectsize:
+      NewValue = lowerObjectSizeCall(II, DL, TLI, true);
+      ObjectSizeIntrinsicsHandled++;
+      break;
+    }
+    HasDeadBlocks |= replaceConditionalBranchesOnConstant(II, NewValue);
+  }
+  if (HasDeadBlocks)
+    removeUnreachableBlocks(F);
+  return !Worklist.empty();
+}
+
+PreservedAnalyses
+LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
+  if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F)))
+    return PreservedAnalyses::none();
+
+  return PreservedAnalyses::all();
+}
+
+namespace {
+/// Legacy pass for lowering is.constant intrinsics out of the IR.
+///
+/// When this pass is run over a function it converts is.constant intrinsics
+/// into 'true' or 'false'. This is completements the normal constand folding
+/// to 'true' as part of Instruction Simplify passes.
+class LowerConstantIntrinsics : public FunctionPass {
+public:
+  static char ID;
+  LowerConstantIntrinsics() : FunctionPass(ID) {
+    initializeLowerConstantIntrinsicsPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override {
+    auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
+    const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr;
+    return lowerConstantIntrinsics(F, TLI);
+  }
+};
+} // namespace
+
+char LowerConstantIntrinsics::ID = 0;
+INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics",
+                "Lower constant intrinsics", false, false)
+
+FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
+  return new LowerConstantIntrinsics();
+}
index 688b8b9079e05a73d343dc9cc95d4e5cc7220e56..1d2e40bf62be71d374c178ea64ea69b49cc3f552 100644 (file)
@@ -79,6 +79,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
   initializeLoopVersioningLICMPass(Registry);
   initializeLoopIdiomRecognizeLegacyPassPass(Registry);
   initializeLowerAtomicLegacyPassPass(Registry);
+  initializeLowerConstantIntrinsicsPass(Registry);
   initializeLowerExpectIntrinsicPass(Registry);
   initializeLowerGuardIntrinsicLegacyPassPass(Registry);
   initializeLowerWidenableConditionLegacyPassPass(Registry);
@@ -284,6 +285,10 @@ void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM) {
   unwrap(PM)->add(createBasicAAWrapperPass());
 }
 
+void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM) {
+  unwrap(PM)->add(createLowerConstantIntrinsicsPass());
+}
+
 void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM) {
   unwrap(PM)->add(createLowerExpectIntrinsicPass());
 }
index 4f9dcd1686afb65b7432c8a06508b2868a400549..598510df98a56ed8c8330354d469d0d98dbe0cfe 100644 (file)
@@ -1183,23 +1183,6 @@ define void @test_memset(i8* %dst, i8 %val, i64 %size) {
   ret void
 }
 
-declare i64 @llvm.objectsize.i64(i8*, i1)
-declare i32 @llvm.objectsize.i32(i8*, i1)
-define void @test_objectsize(i8* %addr0, i8* %addr1) {
-; CHECK-LABEL: name: test_objectsize
-; CHECK: [[ADDR0:%[0-9]+]]:_(p0) = COPY $x0
-; CHECK: [[ADDR1:%[0-9]+]]:_(p0) = COPY $x1
-; CHECK: {{%[0-9]+}}:_(s64) = G_CONSTANT i64 -1
-; CHECK: {{%[0-9]+}}:_(s64) = G_CONSTANT i64 0
-; CHECK: {{%[0-9]+}}:_(s32) = G_CONSTANT i32 -1
-; CHECK: {{%[0-9]+}}:_(s32) = G_CONSTANT i32 0
-  %size64.0 = call i64 @llvm.objectsize.i64(i8* %addr0, i1 0)
-  %size64.intmin = call i64 @llvm.objectsize.i64(i8* %addr0, i1 1)
-  %size32.0 = call i32 @llvm.objectsize.i32(i8* %addr0, i1 0)
-  %size32.intmin = call i32 @llvm.objectsize.i32(i8* %addr0, i1 1)
-  ret void
-}
-
 define void @test_large_const(i128* %addr) {
 ; CHECK-LABEL: name: test_large_const
 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
index 9611946f7103418441806361864e9262b55f9f6b..20214fb83f4e15141c4f635608286b2190060812 100644 (file)
@@ -21,6 +21,7 @@
 ; CHECK-NEXT:       Module Verifier
 ; CHECK-NEXT:       Lower Garbage Collection Instructions
 ; CHECK-NEXT:       Shadow Stack GC Lowering
+; CHECK-NEXT:       Lower constant intrinsics
 ; CHECK-NEXT:       Remove unreachable blocks from the CFG
 ; CHECK-NEXT:       Instrument function entry/exit with calls to e.g. mcount() (post inlining)
 ; CHECK-NEXT:       Scalarize Masked Memory Intrinsics
index 35417deec1acd1c8bf3de5afec7bd2ddf55e6a0b..f483d631167c08b54f4de5a7188d489e485774ad 100644 (file)
@@ -38,6 +38,7 @@
 ; CHECK-NEXT:       Expand memcmp() to load/stores
 ; CHECK-NEXT:       Lower Garbage Collection Instructions
 ; CHECK-NEXT:       Shadow Stack GC Lowering
+; CHECK-NEXT:       Lower constant intrinsics
 ; CHECK-NEXT:       Remove unreachable blocks from the CFG
 ; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Natural Loop Information
index cbfc1e86a362e426c9b9a3abd5909d44b9b4037e..6cc7e53aeffb7bbdf65a1290b6e44ec05af48e8a 100644 (file)
@@ -22,6 +22,7 @@
 ; CHECK-NEXT:      Expand memcmp() to load/stores
 ; CHECK-NEXT:      Lower Garbage Collection Instructions
 ; CHECK-NEXT:      Shadow Stack GC Lowering
+; CHECK-NEXT:      Lower constant intrinsics
 ; CHECK-NEXT:      Remove unreachable blocks from the CFG
 ; CHECK-NEXT:      Dominator Tree Construction
 ; CHECK-NEXT:      Natural Loop Information
diff --git a/test/CodeGen/Generic/is-constant.ll b/test/CodeGen/Generic/is-constant.ll
deleted file mode 100644 (file)
index 2e1f426..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-; 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.a2i64([2 x i64] %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
-}
-
-@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 i64] %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.a2i64([2 x i64] %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.a2i64([2 x i64] [i64 -1, i64 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 i64] [i64 -1, i64 55],
-                    i64* inttoptr (i64 42 to i64*))
-  ret i1 %r
-}
-
-attributes #0 = { nounwind uwtable }
index 271aec5fa0560e39ce229f48acce78daa43bb7ab..b6e1e459c2d3ec7257370ae51a695daefe7c91af 100644 (file)
@@ -24,6 +24,7 @@
 ; CHECK-NEXT:       Module Verifier
 ; CHECK-NEXT:       Lower Garbage Collection Instructions
 ; CHECK-NEXT:       Shadow Stack GC Lowering
+; CHECK-NEXT:       Lower constant intrinsics
 ; CHECK-NEXT:       Remove unreachable blocks from the CFG
 ; CHECK-NEXT:       Instrument function entry/exit with calls to e.g. mcount() (post inlining)
 ; CHECK-NEXT:       Scalarize Masked Memory Intrinsics
index d7569ccb2da24c6d1865b328c179f8be87658d7b..389c21f0a8f1dfb86bac57a5122437d7c49dec19 100644 (file)
@@ -35,6 +35,7 @@
 ; CHECK-NEXT:       Expand memcmp() to load/stores
 ; CHECK-NEXT:       Lower Garbage Collection Instructions
 ; CHECK-NEXT:       Shadow Stack GC Lowering
+; CHECK-NEXT:       Lower constant intrinsics
 ; CHECK-NEXT:       Remove unreachable blocks from the CFG
 ; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Natural Loop Information
diff --git a/test/CodeGen/X86/is-constant.ll b/test/CodeGen/X86/is-constant.ll
deleted file mode 100644 (file)
index b4c1f35..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-; 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, 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, i1 false)
-  %v = call i1 @llvm.is.constant.i64(i64 %os)
-  ret i1 %v
-}
diff --git a/test/CodeGen/X86/object-size.ll b/test/CodeGen/X86/object-size.ll
deleted file mode 100644 (file)
index b795e0f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-; RUN: llc -O0 < %s | FileCheck %s
-
-; ModuleID = 'ts.c'
-target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
-target triple = "x86_64-apple-darwin10.0"
-
-@p = common global i8* null, align 8              ; <i8**> [#uses=4]
-@.str = private constant [3 x i8] c"Hi\00"        ; <[3 x i8]*> [#uses=1]
-
-define void @bar() nounwind ssp {
-entry:
-  %tmp = load i8*, i8** @p                             ; <i8*> [#uses=1]
-  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp, i1 0) ; <i64> [#uses=1]
-  %cmp = icmp ne i64 %0, -1                       ; <i1> [#uses=1]
-; CHECK: movq $-1, [[RAX:%r..]]
-; CHECK: cmpq $-1, [[RAX]]
-  br i1 %cmp, label %cond.true, label %cond.false
-
-cond.true:                                        ; preds = %entry
-  %tmp1 = load i8*, i8** @p                            ; <i8*> [#uses=1]
-  %tmp2 = load i8*, i8** @p                            ; <i8*> [#uses=1]
-  %1 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp2, i1 1) ; <i64> [#uses=1]
-  %call = call i8* @__strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i64 %1) ssp ; <i8*> [#uses=1]
-  br label %cond.end
-
-cond.false:                                       ; preds = %entry
-  %tmp3 = load i8*, i8** @p                            ; <i8*> [#uses=1]
-  %call4 = call i8* @__inline_strcpy_chk(i8* %tmp3, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) ssp ; <i8*> [#uses=1]
-  br label %cond.end
-
-cond.end:                                         ; preds = %cond.false, %cond.true
-  %cond = phi i8* [ %call, %cond.true ], [ %call4, %cond.false ] ; <i8*> [#uses=0]
-  ret void
-}
-
-declare i64 @llvm.objectsize.i64.p0i8(i8*, i1) nounwind readonly
-
-declare i8* @__strcpy_chk(i8*, i8*, i64) ssp
-
-define internal i8* @__inline_strcpy_chk(i8* %__dest, i8* %__src) nounwind ssp {
-entry:
-  %retval = alloca i8*                            ; <i8**> [#uses=2]
-  %__dest.addr = alloca i8*                       ; <i8**> [#uses=3]
-  %__src.addr = alloca i8*                        ; <i8**> [#uses=2]
-  store i8* %__dest, i8** %__dest.addr
-  store i8* %__src, i8** %__src.addr
-  %tmp = load i8*, i8** %__dest.addr                   ; <i8*> [#uses=1]
-  %tmp1 = load i8*, i8** %__src.addr                   ; <i8*> [#uses=1]
-  %tmp2 = load i8*, i8** %__dest.addr                  ; <i8*> [#uses=1]
-  %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp2, i1 1) ; <i64> [#uses=1]
-  %call = call i8* @__strcpy_chk(i8* %tmp, i8* %tmp1, i64 %0) ssp ; <i8*> [#uses=1]
-  store i8* %call, i8** %retval
-  %1 = load i8*, i8** %retval                          ; <i8*> [#uses=1]
-  ret i8* %1
-}
index 4e07bffd3dc3aa97373e973198cf5cece6242e4d..638c783725bf2d8f309df4131267b91385cf769a 100644 (file)
 ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
 ; CHECK-O-NEXT: Starting llvm::Function pass manager run.
 ; CHECK-O-NEXT: Running pass: Float2IntPass
+; CHECK-O-NEXT: Running pass: LowerConstantIntrinsicsPass on foo
 ; CHECK-EP-VECTORIZER-START-NEXT: Running pass: NoOpFunctionPass
 ; CHECK-O-NEXT: Running pass: FunctionToLoopPassAdaptor<{{.*}}LoopRotatePass
 ; CHECK-O-NEXT: Starting llvm::Function pass manager run.
index 686bb9b6ea9d9c6e7e1f444ae0d9d9230f5fd05b..7b6855b130e6e2740842c68f488440a1633ab0cb 100644 (file)
 ; CHECK-POSTLINK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
 ; CHECK-POSTLINK-O-NEXT: Starting llvm::Function pass manager run.
 ; CHECK-POSTLINK-O-NEXT: Running pass: Float2IntPass
+; CHECK-POSTLINK-O-NEXT: Running pass: LowerConstantIntrinsicsPass
 ; CHECK-POSTLINK-O-NEXT: Running pass: FunctionToLoopPassAdaptor<{{.*}}LoopRotatePass
 ; CHECK-POSTLINK-O-NEXT: Starting llvm::Function pass manager run
 ; CHECK-POSTLINK-O-NEXT: Running pass: LoopSimplifyPass
index f8603ef12a7b8a1099dd5ccfef6660f6069fd868..e1f19e74733eb38c2378ca3192c05433dabced3a 100644 (file)
 ; CHECK-NEXT:     FunctionPass Manager
 ; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Float to int
+; CHECK-NEXT:       Lower constant intrinsics
+; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Basic Alias Analysis (stateless AA impl)
 ; CHECK-NEXT:       Function Alias Analysis Results
 ; CHECK-NEXT:       Memory SSA
index 5f02df4ea7076122df918ec95073beb6eced19a6..3bfb921efc65caf46d46be6d6ce98d218a76d179 100644 (file)
 ; CHECK-NEXT:     FunctionPass Manager
 ; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Float to int
+; CHECK-NEXT:       Lower constant intrinsics
+; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Basic Alias Analysis (stateless AA impl)
 ; CHECK-NEXT:       Function Alias Analysis Results
 ; CHECK-NEXT:       Memory SSA
index 127ccede06093f6a7f6950b411871e80d9bc1d7c..02271fb20328979471e8b047a0ac9f751b5ea951 100644 (file)
 ; CHECK-NEXT:     FunctionPass Manager
 ; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Float to int
+; CHECK-NEXT:       Lower constant intrinsics
+; CHECK-NEXT:       Dominator Tree Construction
 ; CHECK-NEXT:       Basic Alias Analysis (stateless AA impl)
 ; CHECK-NEXT:       Function Alias Analysis Results
 ; CHECK-NEXT:       Memory SSA
index fc6d66a6082edc663aedfb94bda29fbe0b6ba68f..9ba1d7db5ad6e40b11e424f323f579e365c4383c 100644 (file)
@@ -514,26 +514,6 @@ exit:
   ret void
 }
 
-; This was crashing when trying to delay instruction removal/deletion.
-
-declare i64 @llvm.objectsize.i64.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #0
-
-define hidden fastcc void @crash() {
-; CHECK-LABEL: @crash(
-; CHECK-NEXT:    [[TMP1:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 undef, i64 undef)
-; CHECK-NEXT:    [[MATH:%.*]] = extractvalue { i64, i1 } [[TMP1]], 0
-; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
-; CHECK-NEXT:    [[T2:%.*]] = select i1 undef, i1 undef, i1 [[OV]]
-; CHECK-NEXT:    unreachable
-;
-  %t0 = add i64 undef, undef
-  %t1 = icmp ult i64 %t0, undef
-  %t2 = select i1 undef, i1 undef, i1 %t1
-  %t3 = call i64 @llvm.objectsize.i64.p0i8(i8* nonnull undef, i1 false, i1 false, i1 false)
-  %t4 = icmp ugt i64 %t3, 7
-  unreachable
-}
-
 ; Check that every instruction inserted by -codegenprepare has a debug location.
 ; DEBUG: CheckModuleDebugify: PASS
 
diff --git a/test/Transforms/CodeGenPrepare/builtin-condition.ll b/test/Transforms/CodeGenPrepare/builtin-condition.ll
deleted file mode 100644 (file)
index e42529a..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-; RUN: opt -codegenprepare -S  < %s | FileCheck %s
-
-; Ensure we act sanely on overflow.
-; CHECK-LABEL: define i32 @bar
-define i32 @bar() {
-entry:
-  ; CHECK: ret i32 -1
-  %az = alloca [2147483649 x i32], align 16
-  %a = alloca i8*, align 8
-  %arraydecay = getelementptr inbounds [2147483649 x i32], [2147483649 x i32]* %az, i32 0, i32 0
-  %0 = bitcast i32* %arraydecay to i8*
-  store i8* %0, i8** %a, align 8
-  %1 = load i8*, i8** %a, align 8
-  %2 = call i32 @llvm.objectsize.i32.p0i8(i8* %1, i1 false)
-  ret i32 %2
-}
-
-; CHECK-LABEL: define i32 @baz
-define i32 @baz(i32 %n) {
-entry:
-  ; CHECK: ret i32 -1
-  %az = alloca [1 x i32], align 16
-  %bz = alloca [4294967297 x i32], align 16
-  %tobool = icmp ne i32 %n, 0
-  %arraydecay = getelementptr inbounds [1 x i32], [1 x i32]* %az, i64 0, i64 0
-  %arraydecay1 = getelementptr inbounds [4294967297 x i32], [4294967297 x i32]* %bz, i64 0, i64 0
-  %cond = select i1 %tobool, i32* %arraydecay, i32* %arraydecay1
-  %0 = bitcast i32* %cond to i8*
-  %1 = call i32 @llvm.objectsize.i32.p0i8(i8* %0, i1 false)
-  ret i32 %1
-}
-
-declare i32 @llvm.objectsize.i32.p0i8(i8*, i1)
-
-; The following tests were generated by:
-; #include<stdlib.h>
-; #define STATIC_BUF_SIZE 10
-; #define LARGER_BUF_SIZE 30
-;
-; size_t foo1(int flag) {
-;   char *cptr;
-;   char chararray[LARGER_BUF_SIZE];
-;   char chararray2[STATIC_BUF_SIZE];
-;   if(flag)
-;     cptr = chararray2;
-;    else
-;     cptr = chararray;
-;
-;   return  __builtin_object_size(cptr, 2);
-; }
-;
-; size_t foo2(int n) {
-;   char Small[10];
-;   char Large[20];
-;   char *Ptr = n ? Small : Large + 19;
-;   return __builtin_object_size(Ptr, 0);
-; }
-;
-; void foo() {
-;   size_t ret;
-;   size_t ret1;
-;   ret = foo1(0);
-;   ret1 = foo2(0);
-;   printf("\n%d %d\n", ret, ret1);
-; }
-
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-@.str = private unnamed_addr constant [8 x i8] c"\0A%d %d\0A\00", align 1
-
-define i64 @foo1(i32 %flag) {
-entry:
-  %chararray = alloca [30 x i8], align 16
-  %chararray2 = alloca [10 x i8], align 1
-  %0 = getelementptr inbounds [30 x i8], [30 x i8]* %chararray, i64 0, i64 0
-  call void @llvm.lifetime.start.p0i8(i64 30, i8* %0)
-  %1 = getelementptr inbounds [10 x i8], [10 x i8]* %chararray2, i64 0, i64 0
-  call void @llvm.lifetime.start.p0i8(i64 10, i8* %1)
-  %tobool = icmp eq i32 %flag, 0
-  %cptr.0 = select i1 %tobool, i8* %0, i8* %1
-  %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %cptr.0, i1 true)
-  call void @llvm.lifetime.end.p0i8(i64 10, i8* %1)
-  call void @llvm.lifetime.end.p0i8(i64 30, i8* %0)
-  ret i64 %2
-; CHECK-LABEL: foo1
-; CHECK:  ret i64 10
-}
-
-declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
-
-declare i64 @llvm.objectsize.i64.p0i8(i8*, i1)
-
-declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
-
-define i64 @foo2(i32 %n) {
-entry:
-  %Small = alloca [10 x i8], align 1
-  %Large = alloca [20 x i8], align 16
-  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %Small, i64 0, i64 0
-  call void @llvm.lifetime.start.p0i8(i64 10, i8* %0)
-  %1 = getelementptr inbounds [20 x i8], [20 x i8]* %Large, i64 0, i64 0
-  call void @llvm.lifetime.start.p0i8(i64 20, i8* %1)
-  %tobool = icmp ne i32 %n, 0
-  %add.ptr = getelementptr inbounds [20 x i8], [20 x i8]* %Large, i64 0, i64 19
-  %cond = select i1 %tobool, i8* %0, i8* %add.ptr
-  %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %cond, i1 false)
-  call void @llvm.lifetime.end.p0i8(i64 20, i8* %1)
-  call void @llvm.lifetime.end.p0i8(i64 10, i8* %0)
-  ret i64 %2
-; CHECK-LABEL: foo2
-; CHECK:  ret i64 10
-}
-
-define void @foo() {
-entry:
-  %call = tail call i64 @foo1(i32 0)
-  %call1 = tail call i64 @foo2(i32 0)
-  %call2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i64 %call, i64 %call1)
-  ret void
-}
-
-declare i32 @printf(i8* nocapture readonly, ...)
diff --git a/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll b/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll
new file mode 100644 (file)
index 0000000..b2c98d2
--- /dev/null
@@ -0,0 +1,114 @@
+; RUN: opt -lower-constant-intrinsics -S < %s | FileCheck %s
+
+;; Ensure that an unfoldable is.constant gets lowered reasonably in
+;; optimized codegen, in particular, that the "true" branch is
+;; eliminated.
+
+;; Also ensure that any unfoldable objectsize is resolved in order.
+
+;; CHECK-NOT: tail call i32 @subfun_1()
+;; CHECK:     tail call i32 @subfun_2()
+;; CHECK-NOT: tail call i32 @subfun_1()
+
+declare i1 @llvm.is.constant.i32(i32 %a) nounwind readnone
+declare i1 @llvm.is.constant.i64(i64 %a) nounwind readnone
+declare i1 @llvm.is.constant.i256(i256 %a) nounwind readnone
+declare i1 @llvm.is.constant.v2i64(<2 x i64> %a) nounwind readnone
+declare i1 @llvm.is.constant.f32(float %a) nounwind readnone
+declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a) nounwind readnone
+declare i1 @llvm.is.constant.a2i64([2 x i64] %a) nounwind readnone
+declare i1 @llvm.is.constant.p0i64(i64* %a) nounwind readnone
+
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) nounwind readnone
+
+declare i32 @subfun_1()
+declare i32 @subfun_2()
+
+define i32 @test_branch(i32 %in) nounwind {
+  %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-NOT:      llvm.objectsize
+;; CHECK-NOT:      llvm.is.constant
+;; CHECK:          ret i1 true
+  %os = call i64 @llvm.objectsize.i64.p0i8(i8* %obj, i1 false, i1 false, i1 false)
+  %os1 = add i64 %os, 1
+  %v = call i1 @llvm.is.constant.i64(i64 %os1)
+  ret i1 %v
+}
+
+@test_phi_a = dso_local global i32 0, align 4
+declare dso_local i32 @test_phi_b(...)
+
+; Function Attrs: nounwind uwtable
+define dso_local i32 @test_phi() {
+entry:
+  %0 = load i32, i32* @test_phi_a, align 4
+  %1 = tail call i1 @llvm.is.constant.i32(i32 %0)
+  br i1 %1, label %cond.end, label %cond.false
+
+cond.false:                                       ; preds = %entry
+  %call = tail call i32 bitcast (i32 (...)* @test_phi_b to i32 ()*)() #3
+  %.pre = load i32, i32* @test_phi_a, align 4
+  br label %cond.end
+
+cond.end:                                         ; preds = %entry, %cond.false
+  %2 = phi i32 [ %.pre, %cond.false ], [ %0, %entry ]
+  %cond = phi i32 [ %call, %cond.false ], [ 1, %entry ]
+  %cmp = icmp eq i32 %cond, %2
+  br i1 %cmp, label %cond.true1, label %cond.end4
+
+cond.true1:                                       ; preds = %cond.end
+  %call2 = tail call i32 bitcast (i32 (...)* @test_phi_b to i32 ()*)() #3
+  br label %cond.end4
+
+cond.end4:                                        ; preds = %cond.end, %cond.true1
+  ret i32 undef
+}
+
+define i1 @test_various_types(i256 %int, float %float, <2 x i64> %vec, {i32, i32} %struct, [2 x i64] %arr, i64* %ptr) #0 {
+; CHECK-LABEL: @test_various_types(
+; 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.a2i64([2 x i64] %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.a2i64([2 x i64] [i64 -1, i64 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
+}
similarity index 87%
rename from test/Transforms/CodeGenPrepare/crash-on-large-allocas.ll
rename to test/Transforms/LowerConstantIntrinsics/crash-on-large-allocas.ll
index 5049207ec27e12b50fadbba958180f280c0a4cf3..e4e981161fd9d3bdb22f449be83a997148e2ad67 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt -S -codegenprepare %s -o - | FileCheck %s
+; RUN: opt -S -lower-constant-intrinsics %s -o - | FileCheck %s
 ;
 ; Ensure that we don't {crash,return a bad value} when given an alloca larger
 ; than what a pointer can represent.
similarity index 94%
rename from test/Transforms/CodeGenPrepare/basic.ll
rename to test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll
index 1a58d61b6e9611b39856c1943a41d891205ceb24..94aba44fcc4faeac4c4ec36e1ae4cdf48e9e3684 100644 (file)
@@ -1,12 +1,15 @@
-; RUN: opt -codegenprepare -S < %s | FileCheck %s
+; RUN: opt -lower-constant-intrinsics -S < %s | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 target triple = "x86_64-apple-darwin10.0.0"
 
+declare i64 @llvm.objectsize.i64(i8*, i1, i1, i1) nounwind readonly
+declare i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)*, i1, i1, i1) nounwind readonly
+declare void @llvm.trap() nounwind
+
 ; CHECK-LABEL: @test1(
 ; objectsize should fold to a constant, which causes the branch to fold to an
-; uncond branch. Next, we fold the control flow alltogether.
-; rdar://8785296
+; uncond branch.
 define i32 @test1(i8* %ptr) nounwind ssp noredzone align 2 {
 entry:
   %0 = tail call i64 @llvm.objectsize.i64(i8* %ptr, i1 false, i1 false, i1 false)
@@ -14,7 +17,7 @@ entry:
   br i1 %1, label %T, label %trap
 
 ; CHECK: entry:
-; CHECK-NOT: br label %
+; CHECK-NOT: label %trap
 
 trap:                                             ; preds = %0, %entry
   tail call void @llvm.trap() noreturn nounwind
@@ -78,9 +81,3 @@ entry:
                                                i1 false, i1 false)
   ret i64 %0
 }
-
-
-declare i64 @llvm.objectsize.i64(i8*, i1, i1, i1) nounwind readonly
-declare i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)*, i1, i1, i1) nounwind readonly
-
-declare void @llvm.trap() nounwind
index d09bb7029a545cd7c81e310704ae9bb71754f6e9..c6daa5081bcd978b1578e6c4a0660a953f35aa96 100644 (file)
@@ -57,6 +57,7 @@ static_library("Scalar") {
     "LowerAtomic.cpp",
     "LowerExpectIntrinsic.cpp",
     "LowerGuardIntrinsic.cpp",
+    "LowerConstantIntrinsics.cpp",
     "LowerWidenableCondition.cpp",
     "MakeGuardsExplicit.cpp",
     "MemCpyOptimizer.cpp",