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::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: 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 @@ -232,6 +232,12 @@ } /* [ unit */ +CAMLprim value llvm_add_lower_constant_intrinsics(LLVMPassManagerRef PM) { + LLVMAddLowerConstantIntrinsicsPass(PM); + return Val_unit; +} + +/* [ unit */ CAMLprim value llvm_add_type_based_alias_analysis(LLVMPassManagerRef PM) { LLVMAddTypeBasedAliasAnalysisPass(PM); return Val_unit; 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::createLowerConstantIntrinsicsPass function */ +void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM); + /** See llvm::createTypeBasedAliasAnalysisPass function */ void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM); Index: include/llvm/Analysis/InstructionSimplify.h =================================================================== --- include/llvm/Analysis/InstructionSimplify.h +++ include/llvm/Analysis/InstructionSimplify.h @@ -31,6 +31,7 @@ #ifndef LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H #define LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H +#include "llvm/ADT/SetVector.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Operator.h" #include "llvm/IR/User.h" @@ -261,12 +262,16 @@ /// This first performs a normal RAUW of I with SimpleV. It then recursively /// attempts to simplify those users updated by the operation. The 'I' /// instruction must not be equal to the simplified value 'SimpleV'. +/// If Failed is provided, instructions that could not be simplified are +/// added to it. /// /// The function returns true if any simplifications were performed. bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI = nullptr, const DominatorTree *DT = nullptr, - AssumptionCache *AC = nullptr); + AssumptionCache *AC = nullptr, + SmallSetVector + *Failed = nullptr); /// Recursively attempt to simplify an instruction. /// 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 initializeLowerConstantIntrinsicsPass(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::createLowerConstantIntrinsicsPass(); (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 @@ -397,6 +397,13 @@ //===----------------------------------------------------------------------===// // +// 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 // calls such as sqrt. // Index: include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h =================================================================== --- include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h +++ include/llvm/Transforms/Scalar/LowerConstantIntrinsics.h @@ -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 { +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: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -5219,14 +5219,17 @@ /// If we have a pre-simplified value in 'SimpleV', that is forcibly used to /// replace the instruction 'I'. Otherwise, we simply add 'I' to the list of /// instructions to process and attempt to simplify it using -/// InstructionSimplify. +/// InstructionSimplify. Instructions that did not simplify are optionally added +/// to the Failed set for further processing by the caller. /// /// This routine returns 'true' only when *it* simplifies something. The passed /// in simplified value does not count toward this. static bool replaceAndRecursivelySimplifyImpl(Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI, const DominatorTree *DT, - AssumptionCache *AC) { + AssumptionCache *AC, + SmallSetVector + *Failed = nullptr) { bool Simplified = false; SmallSetVector Worklist; const DataLayout &DL = I->getModule()->getDataLayout(); @@ -5256,8 +5259,11 @@ // See if this instruction simplifies. SimpleV = SimplifyInstruction(I, {DL, TLI, DT, AC}); - if (!SimpleV) + if (!SimpleV) { + if (Failed) + Failed->insert(I); continue; + } Simplified = true; @@ -5283,16 +5289,18 @@ const TargetLibraryInfo *TLI, const DominatorTree *DT, AssumptionCache *AC) { - return replaceAndRecursivelySimplifyImpl(I, nullptr, TLI, DT, AC); + return replaceAndRecursivelySimplifyImpl(I, nullptr, TLI, DT, AC, nullptr); } bool llvm::replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI, const DominatorTree *DT, - AssumptionCache *AC) { + AssumptionCache *AC, + SmallSetVector + *Failed) { assert(I != SimpleV && "replaceAndRecursivelySimplify(X,X) is not valid!"); assert(SimpleV && "Must provide a simplified value."); - return replaceAndRecursivelySimplifyImpl(I, SimpleV, TLI, DT, AC); + return replaceAndRecursivelySimplifyImpl(I, SimpleV, TLI, DT, AC, Failed); } namespace llvm { Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -1867,24 +1867,10 @@ }); 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(CI->getArgOperand(0)); Index: lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- lib/CodeGen/GlobalISel/IRTranslator.cpp +++ lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1434,18 +1434,12 @@ 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(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: lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FastISel.cpp +++ lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1453,24 +1453,12 @@ TII.get(TargetOpcode::DBG_LABEL)).addMetadata(DI->getLabel()); return true; } - case Intrinsic::objectsize: { - ConstantInt *CI = cast(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: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6376,29 +6376,11 @@ DAG.setRoot(Res); return; } - case Intrinsic::objectsize: { - // If we don't know by now, we're never going to know. - ConstantInt *CI = dyn_cast(I.getArgOperand(1)); + case Intrinsic::objectsize: + llvm_unreachable("llvm.objectsize.* should have been lowered already"); - 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::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: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -654,6 +654,7 @@ // 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: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -141,6 +141,7 @@ #include "llvm/Transforms/Scalar/LowerAtomic.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h" +#include "llvm/Transforms/Scalar/LowerConstantIntrinsics.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 @@ -186,6 +186,7 @@ FUNCTION_PASS("loweratomic", LowerAtomicPass()) FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass()) FUNCTION_PASS("lower-guard-intrinsic", LowerGuardIntrinsicPass()) +FUNCTION_PASS("lower-is-constant", LowerConstantIntrinsicsPass()) 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 + LowerConstantIntrinsics.cpp LowerWidenableCondition.cpp MakeGuardsExplicit.cpp MemCpyOptimizer.cpp Index: lib/Transforms/Scalar/LowerConstantIntrinsics.cpp =================================================================== --- lib/Transforms/Scalar/LowerConstantIntrinsics.cpp +++ lib/Transforms/Scalar/LowerConstantIntrinsics.cpp @@ -0,0 +1,163 @@ +//===- 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/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/Scalar/LowerConstantIntrinsics.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"); + +#include + +static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { + Value *Op = II->getOperand(0); + Value *Result; + + if (isa(Op)) + Result = ConstantInt::getTrue(II->getType()); + else + Result = ConstantInt::getFalse(II->getType()); + return Result; +} + +static bool replaceWithSimplifyCFG(Instruction *II, Value *NewValue) +{ + bool HasDeadBlocks = false; + SmallSetVector Worklist; + replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr, + &Worklist); + for (auto I: Worklist) { + BranchInst *BI = dyn_cast(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 Changed = false, HasDeadBlocks = false; + const auto &DL = F.getParent()->getDataLayout(); + + for (BasicBlock &BB : F) { + for (BasicBlock::iterator I = BB.begin(); I != BB.end();) { + Instruction *Inst = &*I++; + + if (IntrinsicInst *II = dyn_cast(Inst)) { + 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; + } + WeakTrackingVH InstPtr(&*I); + HasDeadBlocks = replaceWithSimplifyCFG(Inst, NewValue); + Changed = true; + if (!InstPtr || !I->getParent()) + I = BB.begin(); + } + } + } + if (HasDeadBlocks) + removeUnreachableBlocks(F); + return Changed; +} + +PreservedAnalyses LowerConstantIntrinsicsPass::run( + Function &F, FunctionAnalysisManager &AM) { + if (lowerConstantIntrinsics(F, 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'. 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(); + const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr; + return lowerConstantIntrinsics(F, TLI); + } +}; +} + +char LowerConstantIntrinsics::ID = 0; +INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics", + "Lower constant intrinsics", false, false) + +FunctionPass *llvm::createLowerConstantIntrinsicsPass() { + return new LowerConstantIntrinsics(); +} 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); + initializeLowerConstantIntrinsicsPass(Registry); initializeLowerWidenableConditionLegacyPassPass(Registry); initializeMemCpyOptLegacyPassPass(Registry); initializeMergeICmpsLegacyPassPass(Registry); @@ -284,6 +285,10 @@ unwrap(PM)->add(createLowerExpectIntrinsicPass()); } +void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createLowerConstantIntrinsicsPass()); +} + void LLVMAddUnifyFunctionExitNodesPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createUnifyFunctionExitNodesPass()); } Index: test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll =================================================================== --- test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll +++ test/CodeGen/AArch64/GlobalISel/arm64-irtranslator.ll @@ -1174,23 +1174,6 @@ 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: test/CodeGen/AArch64/O0-pipeline.ll =================================================================== --- test/CodeGen/AArch64/O0-pipeline.ll +++ test/CodeGen/AArch64/O0-pipeline.ll @@ -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: test/CodeGen/AArch64/O3-pipeline.ll =================================================================== --- test/CodeGen/AArch64/O3-pipeline.ll +++ test/CodeGen/AArch64/O3-pipeline.ll @@ -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: test/CodeGen/ARM/O3-pipeline.ll =================================================================== --- test/CodeGen/ARM/O3-pipeline.ll +++ test/CodeGen/ARM/O3-pipeline.ll @@ -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 Index: test/CodeGen/X86/O0-pipeline.ll =================================================================== --- test/CodeGen/X86/O0-pipeline.ll +++ test/CodeGen/X86/O0-pipeline.ll @@ -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: test/CodeGen/X86/O3-pipeline.ll =================================================================== --- test/CodeGen/X86/O3-pipeline.ll +++ test/CodeGen/X86/O3-pipeline.ll @@ -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 Index: test/CodeGen/X86/is-constant.ll =================================================================== --- test/CodeGen/X86/is-constant.ll +++ test/CodeGen/X86/is-constant.ll @@ -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 -} Index: test/CodeGen/X86/object-size.ll =================================================================== --- test/CodeGen/X86/object-size.ll +++ test/CodeGen/X86/object-size.ll @@ -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 ; [#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 ; [#uses=1] - %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp, i1 0) ; [#uses=1] - %cmp = icmp ne i64 %0, -1 ; [#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 ; [#uses=1] - %tmp2 = load i8*, i8** @p ; [#uses=1] - %1 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp2, i1 1) ; [#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 ; [#uses=1] - br label %cond.end - -cond.false: ; preds = %entry - %tmp3 = load i8*, i8** @p ; [#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 ; [#uses=1] - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i8* [ %call, %cond.true ], [ %call4, %cond.false ] ; [#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* ; [#uses=2] - %__dest.addr = alloca i8* ; [#uses=3] - %__src.addr = alloca i8* ; [#uses=2] - store i8* %__dest, i8** %__dest.addr - store i8* %__src, i8** %__src.addr - %tmp = load i8*, i8** %__dest.addr ; [#uses=1] - %tmp1 = load i8*, i8** %__src.addr ; [#uses=1] - %tmp2 = load i8*, i8** %__dest.addr ; [#uses=1] - %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %tmp2, i1 1) ; [#uses=1] - %call = call i8* @__strcpy_chk(i8* %tmp, i8* %tmp1, i64 %0) ssp ; [#uses=1] - store i8* %call, i8** %retval - %1 = load i8*, i8** %retval ; [#uses=1] - ret i8* %1 -} Index: test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll =================================================================== --- test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll +++ test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll @@ -514,26 +514,6 @@ 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 Index: test/Transforms/CodeGenPrepare/basic.ll =================================================================== --- test/Transforms/CodeGenPrepare/basic.ll +++ test/Transforms/CodeGenPrepare/basic.ll @@ -1,86 +0,0 @@ -; RUN: opt -codegenprepare -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" - -; 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 -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) - %1 = icmp ugt i64 %0, 3 - br i1 %1, label %T, label %trap - -; CHECK: entry: -; CHECK-NOT: br label % - -trap: ; preds = %0, %entry - tail call void @llvm.trap() noreturn nounwind - unreachable - -T: -; CHECK: ret i32 4 - ret i32 4 -} - -; CHECK-LABEL: @test_objectsize_null_flag( -define i64 @test_objectsize_null_flag(i8* %ptr) { -entry: - ; CHECK: ret i64 -1 - %0 = tail call i64 @llvm.objectsize.i64(i8* null, i1 false, i1 true, i1 false) - ret i64 %0 -} - -; CHECK-LABEL: @test_objectsize_null_flag_min( -define i64 @test_objectsize_null_flag_min(i8* %ptr) { -entry: - ; CHECK: ret i64 0 - %0 = tail call i64 @llvm.objectsize.i64(i8* null, i1 true, i1 true, i1 false) - ret i64 %0 -} - -; Test foldable null pointers because we evaluate them with non-exact modes in -; CodeGenPrepare. -; CHECK-LABEL: @test_objectsize_null_flag_noas0( -define i64 @test_objectsize_null_flag_noas0() { -entry: - ; CHECK: ret i64 -1 - %0 = tail call i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)* null, i1 false, - i1 true, i1 false) - ret i64 %0 -} - -; CHECK-LABEL: @test_objectsize_null_flag_min_noas0( -define i64 @test_objectsize_null_flag_min_noas0() { -entry: - ; CHECK: ret i64 0 - %0 = tail call i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)* null, i1 true, - i1 true, i1 false) - ret i64 %0 -} - -; CHECK-LABEL: @test_objectsize_null_known_flag_noas0 -define i64 @test_objectsize_null_known_flag_noas0() { -entry: - ; CHECK: ret i64 -1 - %0 = tail call i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)* null, i1 false, - i1 false, i1 false) - ret i64 %0 -} - -; CHECK-LABEL: @test_objectsize_null_known_flag_min_noas0 -define i64 @test_objectsize_null_known_flag_min_noas0() { -entry: - ; CHECK: ret i64 0 - %0 = tail call i64 @llvm.objectsize.i64.p1i8(i8 addrspace(1)* null, i1 true, - 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: test/Transforms/CodeGenPrepare/builtin-condition.ll =================================================================== --- test/Transforms/CodeGenPrepare/builtin-condition.ll +++ test/Transforms/CodeGenPrepare/builtin-condition.ll @@ -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 -; #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, ...) Index: test/Transforms/CodeGenPrepare/crash-on-large-allocas.ll =================================================================== --- test/Transforms/CodeGenPrepare/crash-on-large-allocas.ll +++ test/Transforms/CodeGenPrepare/crash-on-large-allocas.ll @@ -1,16 +0,0 @@ -; RUN: opt -S -codegenprepare %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. - -target datalayout = "p:16:16" - -; CHECK-LABEL: @alloca_overflow_is_unknown( -define i16 @alloca_overflow_is_unknown() { - %i = alloca i8, i32 65537 - %j = call i16 @llvm.objectsize.i16.p0i8(i8* %i, i1 false, i1 false, i1 false) - ; CHECK: ret i16 -1 - ret i16 %j -} - -declare i16 @llvm.objectsize.i16.p0i8(i8*, i1, i1, i1) Index: test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll =================================================================== --- test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll +++ test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll @@ -1,18 +1,15 @@ -; 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 +; 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. -;; -;; 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" +;; 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 i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, i1) nounwind readnone @@ -21,9 +18,6 @@ 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 @@ -40,11 +34,41 @@ ;; 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 +;; 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) - %v = call i1 @llvm.is.constant.i64(i64 %os) + %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 +} Index: test/Transforms/LowerConstantIntrinsics/crash-on-large-allocas.ll =================================================================== --- test/Transforms/LowerConstantIntrinsics/crash-on-large-allocas.ll +++ test/Transforms/LowerConstantIntrinsics/crash-on-large-allocas.ll @@ -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. Index: test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll =================================================================== --- test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll +++ test/Transforms/LowerConstantIntrinsics/objectsize_basic.ll @@ -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 @@ 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 @@ 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: 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", + "LowerConstantIntrinsics.cpp", "LowerWidenableCondition.cpp", "MakeGuardsExplicit.cpp", "MemCpyOptimizer.cpp",