Index: bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli =================================================================== --- bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli +++ bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli @@ -186,6 +186,11 @@ : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit = "llvm_add_lower_expect_intrinsic" +(** See the [llvm::createLowerIsConstantIntrinsicPass] function. *) +external add_lower_is_constant_intrinsic + : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit + = "llvm_add_lower_is_constant_intrinsic" + (** See the [llvm::createTypeBasedAliasAnalysisPass] function. *) external add_type_based_alias_analysis : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit Index: bindings/ocaml/transforms/scalar_opts/scalar_opts_ocaml.c =================================================================== --- bindings/ocaml/transforms/scalar_opts/scalar_opts_ocaml.c +++ bindings/ocaml/transforms/scalar_opts/scalar_opts_ocaml.c @@ -231,6 +231,12 @@ return Val_unit; } +/* [ unit */ +CAMLprim value llvm_add_lower_is_constant_intrinsic(LLVMPassManagerRef PM) { + LLVMAddLowerIsConstantIntrinsicPass(PM); + return Val_unit; +} + /* [ unit */ CAMLprim value llvm_add_type_based_alias_analysis(LLVMPassManagerRef PM) { LLVMAddTypeBasedAliasAnalysisPass(PM); Index: include/llvm-c/Transforms/Scalar.h =================================================================== --- include/llvm-c/Transforms/Scalar.h +++ include/llvm-c/Transforms/Scalar.h @@ -144,6 +144,9 @@ /** See llvm::createLowerExpectIntrinsicPass function */ void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM); +/** See llvm::createLowerIsConstantIntrinsicPass function */ +void LLVMAddLowerIsConstantIntrinsicPass(LLVMPassManagerRef PM); + /** See llvm::createTypeBasedAliasAnalysisPass function */ void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM); Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -244,6 +244,7 @@ void initializeLowerEmuTLSPass(PassRegistry&); void initializeLowerExpectIntrinsicPass(PassRegistry&); void initializeLowerGuardIntrinsicLegacyPassPass(PassRegistry&); +void initializeLowerIsConstantIntrinsicPass(PassRegistry&); void initializeLowerWidenableConditionLegacyPassPass(PassRegistry&); void initializeLowerIntrinsicsPass(PassRegistry&); void initializeLowerInvokeLegacyPassPass(PassRegistry&); Index: include/llvm/LinkAllPasses.h =================================================================== --- include/llvm/LinkAllPasses.h +++ include/llvm/LinkAllPasses.h @@ -141,6 +141,7 @@ (void) llvm::createLoopIdiomPass(); (void) llvm::createLoopRotatePass(); (void) llvm::createLowerExpectIntrinsicPass(); + (void) llvm::createLowerIsConstantIntrinsicPass(); (void) llvm::createLowerInvokePass(); (void) llvm::createLowerSwitchPass(); (void) llvm::createNaryReassociatePass(); Index: include/llvm/Transforms/Scalar.h =================================================================== --- include/llvm/Transforms/Scalar.h +++ include/llvm/Transforms/Scalar.h @@ -395,6 +395,13 @@ // "block_weights" metadata. FunctionPass *createLowerExpectIntrinsicPass(); +//===----------------------------------------------------------------------===// +// +// LowerIsConstantIntrinsics - Converts llvm.is.constant intrinsics into 'true' +// or 'false'. +// +FunctionPass *createLowerIsConstantIntrinsicPass(bool Final = false); + //===----------------------------------------------------------------------===// // // PartiallyInlineLibCalls - Tries to inline the fast path of library Index: include/llvm/Transforms/Scalar/LowerIsConstantIntrinsic.h =================================================================== --- /dev/null +++ include/llvm/Transforms/Scalar/LowerIsConstantIntrinsic.h @@ -0,0 +1,41 @@ +//===- LowerIsConstantIntrinsic.h - Lower is.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 LowerIsConstantIntrinsic pass as used by the new pass +/// manager. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOWERISCONSTANTINTRINSIC_H +#define LLVM_TRANSFORMS_SCALAR_LOWERISCONSTANTINTRINSIC_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LowerIsConstantIntrinsicPass : + PassInfoMixin { +private: + bool Final; +public: + explicit LowerIsConstantIntrinsicPass(bool Final = false) + : Final(Final) {} + + /// Run the pass over the function. + /// + /// This will lower all of the 'is.constant'` intrinsic calls in this function + /// into 'true' or 'false'. We want to resolve to 'true' as early as possible + /// and 'false' as late as possible. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); +}; + +} + +#endif Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -140,6 +140,7 @@ #include "llvm/Transforms/Scalar/LowerAtomic.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h" +#include "llvm/Transforms/Scalar/LowerIsConstantIntrinsic.h" #include "llvm/Transforms/Scalar/LowerWidenableCondition.h" #include "llvm/Transforms/Scalar/MakeGuardsExplicit.h" #include "llvm/Transforms/Scalar/MemCpyOptimizer.h" Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -185,6 +185,7 @@ FUNCTION_PASS("loweratomic", LowerAtomicPass()) FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass()) FUNCTION_PASS("lower-guard-intrinsic", LowerGuardIntrinsicPass()) +FUNCTION_PASS("lower-is-constant", LowerIsConstantIntrinsicPass()) FUNCTION_PASS("lower-widenable-condition", LowerWidenableConditionPass()) FUNCTION_PASS("guard-widening", GuardWideningPass()) FUNCTION_PASS("gvn", GVN()) Index: lib/Transforms/Scalar/CMakeLists.txt =================================================================== --- lib/Transforms/Scalar/CMakeLists.txt +++ lib/Transforms/Scalar/CMakeLists.txt @@ -46,6 +46,7 @@ LowerAtomic.cpp LowerExpectIntrinsic.cpp LowerGuardIntrinsic.cpp + LowerIsConstantIntrinsic.cpp LowerWidenableCondition.cpp MakeGuardsExplicit.cpp MemCpyOptimizer.cpp Index: lib/Transforms/Scalar/LowerIsConstantIntrinsic.cpp =================================================================== --- /dev/null +++ lib/Transforms/Scalar/LowerIsConstantIntrinsic.cpp @@ -0,0 +1,112 @@ +//===- LowerIsConstantIntrinsic.cpp - Lower is.constant intrinsic ---------===// +// +// 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 the 'is.constant' intrinsic to 'true' or 'false'. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/LowerIsConstantIntrinsic.h" +#include "llvm/ADT/Statistic.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/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/Local.h" + +using namespace llvm; + +#define DEBUG_TYPE "lower-is-constant-intrinsic" + +STATISTIC(IsConstantIntrinsicsHandled, + "Number of 'is.constant' intrinsic instructions handled"); + +static bool handleIsConstantIntrinsic(IntrinsicInst *II, bool Final) { + Value *Op = II->getOperand(0); + Value *Exp = nullptr; + + if (isa(Op)) + Exp = ConstantInt::getTrue(II->getType()); + else if (Final) + Exp = ConstantInt::getFalse(II->getType()); + + if (Exp) { + II->replaceAllUsesWith(Exp); + II->eraseFromParent(); + return true; + } + + return false; +} + +static bool lowerIsConstantIntrinsic(Function &F, bool Final, + const TargetLibraryInfo *TLI) { + bool Changed = false; + + for (BasicBlock &BB : F) { + bool Handled = false; + for (auto BI = BB.begin(), BE = BB.end(); BI != BE;) { + Instruction *I = &*BI++; + if (IntrinsicInst *II = dyn_cast(I)) { + if (II->getIntrinsicID() != Intrinsic::is_constant) + continue; + Handled |= handleIsConstantIntrinsic(II, Final); + IsConstantIntrinsicsHandled++; + } + } + Changed |= Handled && SimplifyInstructionsInBlock(&BB, TLI); + } + + return Changed; +} + +PreservedAnalyses LowerIsConstantIntrinsicPass::run( + Function &F, FunctionAnalysisManager &AM) { + if (lowerIsConstantIntrinsic(F, Final, + AM.getCachedResult(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'. We want to convert to 'true' as early in the +/// pipeline as possible and 'false' as late as possible. +class LowerIsConstantIntrinsic : public FunctionPass { + bool Final; +public: + static char ID; + LowerIsConstantIntrinsic(bool Final = false) + : FunctionPass(ID), Final(Final) { + initializeLowerIsConstantIntrinsicPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + auto *TLIP = getAnalysisIfAvailable(); + const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr; + return lowerIsConstantIntrinsic(F, Final, TLI); + } +}; +} + +char LowerIsConstantIntrinsic::ID = 0; +INITIALIZE_PASS(LowerIsConstantIntrinsic, "lower-is-constant", + "Lower 'is.constant' Intrinsics", false, false) + +FunctionPass *llvm::createLowerIsConstantIntrinsicPass(bool Final) { + return new LowerIsConstantIntrinsic(Final); +} Index: lib/Transforms/Scalar/Scalar.cpp =================================================================== --- lib/Transforms/Scalar/Scalar.cpp +++ lib/Transforms/Scalar/Scalar.cpp @@ -81,6 +81,7 @@ initializeLowerAtomicLegacyPassPass(Registry); initializeLowerExpectIntrinsicPass(Registry); initializeLowerGuardIntrinsicLegacyPassPass(Registry); + initializeLowerIsConstantIntrinsicPass(Registry); initializeLowerWidenableConditionLegacyPassPass(Registry); initializeMemCpyOptLegacyPassPass(Registry); initializeMergeICmpsLegacyPassPass(Registry); @@ -284,6 +285,10 @@ unwrap(PM)->add(createLowerExpectIntrinsicPass()); } +void LLVMAddLowerIsConstantIntrinsicPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createLowerIsConstantIntrinsicPass()); +} + void LLVMAddUnifyFunctionExitNodesPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createUnifyFunctionExitNodesPass()); } Index: utils/gn/secondary/llvm/lib/Transforms/Scalar/BUILD.gn =================================================================== --- utils/gn/secondary/llvm/lib/Transforms/Scalar/BUILD.gn +++ utils/gn/secondary/llvm/lib/Transforms/Scalar/BUILD.gn @@ -57,6 +57,7 @@ "LowerAtomic.cpp", "LowerExpectIntrinsic.cpp", "LowerGuardIntrinsic.cpp", + "LowerIsConstantIntrinsic.cpp", "LowerWidenableCondition.cpp", "MakeGuardsExplicit.cpp", "MemCpyOptimizer.cpp",