mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
Revert "Add a pass to lower is.constant and objectsize intrinsics"
This reverts commit r374743. It broke the build with Ocaml enabled: http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/19218 llvm-svn: 374768
This commit is contained in:
parent
dd292a30dc
commit
d8ea0e7773
@ -191,11 +191,6 @@ 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
|
||||
|
@ -236,12 +236,6 @@ 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);
|
||||
|
@ -147,9 +147,6 @@ 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);
|
||||
|
||||
|
@ -243,7 +243,6 @@ void initializeLoopVectorizePass(PassRegistry&);
|
||||
void initializeLoopVersioningLICMPass(PassRegistry&);
|
||||
void initializeLoopVersioningPassPass(PassRegistry&);
|
||||
void initializeLowerAtomicLegacyPassPass(PassRegistry&);
|
||||
void initializeLowerConstantIntrinsicsPass(PassRegistry&);
|
||||
void initializeLowerEmuTLSPass(PassRegistry&);
|
||||
void initializeLowerExpectIntrinsicPass(PassRegistry&);
|
||||
void initializeLowerGuardIntrinsicLegacyPassPass(PassRegistry&);
|
||||
|
@ -140,7 +140,6 @@ namespace {
|
||||
(void) llvm::createLoopVersioningLICMPass();
|
||||
(void) llvm::createLoopIdiomPass();
|
||||
(void) llvm::createLoopRotatePass();
|
||||
(void) llvm::createLowerConstantIntrinsicsPass();
|
||||
(void) llvm::createLowerExpectIntrinsicPass();
|
||||
(void) llvm::createLowerInvokePass();
|
||||
(void) llvm::createLowerSwitchPass();
|
||||
|
@ -395,13 +395,6 @@ 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
|
||||
|
@ -1,41 +0,0 @@
|
||||
//===- 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
|
@ -1868,10 +1868,24 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool &ModifiedDT) {
|
||||
});
|
||||
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::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::aarch64_stlxr:
|
||||
case Intrinsic::aarch64_stxr: {
|
||||
ZExtInst *ExtVal = dyn_cast<ZExtInst>(CI->getArgOperand(0));
|
||||
|
@ -1437,12 +1437,18 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
MIRBuilder.buildConstant(Reg, TypeID);
|
||||
return true;
|
||||
}
|
||||
case Intrinsic::objectsize:
|
||||
llvm_unreachable("llvm.objectsize.* should have been lowered already");
|
||||
case Intrinsic::objectsize: {
|
||||
// If we don't know by now, we're never going to know.
|
||||
const ConstantInt *Min = cast<ConstantInt>(CI.getArgOperand(1));
|
||||
|
||||
MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0);
|
||||
return true;
|
||||
}
|
||||
case Intrinsic::is_constant:
|
||||
llvm_unreachable("llvm.is.constant.* should have been lowered already");
|
||||
|
||||
// If this wasn't constant-folded away by now, then it's not a
|
||||
// constant.
|
||||
MIRBuilder.buildConstant(getOrCreateVReg(CI), 0);
|
||||
return true;
|
||||
case Intrinsic::stackguard:
|
||||
getStackGuard(getOrCreateVReg(CI), MIRBuilder);
|
||||
return true;
|
||||
|
@ -1454,12 +1454,24 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
|
||||
TII.get(TargetOpcode::DBG_LABEL)).addMetadata(DI->getLabel());
|
||||
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::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::launder_invariant_group:
|
||||
case Intrinsic::strip_invariant_group:
|
||||
case Intrinsic::expect: {
|
||||
|
@ -6388,11 +6388,29 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
|
||||
DAG.setRoot(Res);
|
||||
return;
|
||||
}
|
||||
case Intrinsic::objectsize:
|
||||
llvm_unreachable("llvm.objectsize.* should have been lowered already");
|
||||
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::is_constant:
|
||||
llvm_unreachable("llvm.is.constant.* should have been lowered already");
|
||||
// If this wasn't constant-folded away by now, then it's not a
|
||||
// constant.
|
||||
setValue(&I, DAG.getConstant(0, sdl, MVT::i1));
|
||||
return;
|
||||
|
||||
case Intrinsic::annotation:
|
||||
case Intrinsic::ptr_annotation:
|
||||
|
@ -657,7 +657,6 @@ 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());
|
||||
|
@ -142,7 +142,6 @@
|
||||
#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"
|
||||
@ -892,8 +891,6 @@ 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.
|
||||
|
||||
|
@ -187,7 +187,6 @@ 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())
|
||||
|
@ -654,7 +654,6 @@ void PassManagerBuilder::populateModulePassManager(
|
||||
MPM.add(createGlobalsAAWrapperPass());
|
||||
|
||||
MPM.add(createFloat2IntPass());
|
||||
MPM.add(createLowerConstantIntrinsicsPass());
|
||||
|
||||
addExtensionsToPM(EP_VectorizerStart, MPM);
|
||||
|
||||
|
@ -44,7 +44,6 @@ add_llvm_library(LLVMScalarOpts
|
||||
LoopUnswitch.cpp
|
||||
LoopVersioningLICM.cpp
|
||||
LowerAtomic.cpp
|
||||
LowerConstantIntrinsics.cpp
|
||||
LowerExpectIntrinsic.cpp
|
||||
LowerGuardIntrinsic.cpp
|
||||
LowerWidenableCondition.cpp
|
||||
|
@ -1,170 +0,0 @@
|
||||
//===- 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();
|
||||
}
|
@ -79,7 +79,6 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
|
||||
initializeLoopVersioningLICMPass(Registry);
|
||||
initializeLoopIdiomRecognizeLegacyPassPass(Registry);
|
||||
initializeLowerAtomicLegacyPassPass(Registry);
|
||||
initializeLowerConstantIntrinsicsPass(Registry);
|
||||
initializeLowerExpectIntrinsicPass(Registry);
|
||||
initializeLowerGuardIntrinsicLegacyPassPass(Registry);
|
||||
initializeLowerWidenableConditionLegacyPassPass(Registry);
|
||||
@ -285,10 +284,6 @@ void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createBasicAAWrapperPass());
|
||||
}
|
||||
|
||||
void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createLowerConstantIntrinsicsPass());
|
||||
}
|
||||
|
||||
void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM) {
|
||||
unwrap(PM)->add(createLowerExpectIntrinsicPass());
|
||||
}
|
||||
|
@ -1183,6 +1183,23 @@ 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
|
||||
|
@ -21,7 +21,6 @@
|
||||
; 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
|
||||
|
@ -38,7 +38,6 @@
|
||||
; 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
|
||||
|
@ -22,7 +22,6 @@
|
||||
; 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
|
||||
|
114
test/CodeGen/Generic/is-constant.ll
Normal file
114
test/CodeGen/Generic/is-constant.ll
Normal file
@ -0,0 +1,114 @@
|
||||
; RUN: opt -O2 -S < %s | FileCheck %s
|
||||
; RUN: llc -o /dev/null 2>&1 < %s
|
||||
; RUN: llc -O0 -o /dev/null 2>&1 < %s
|
||||
|
||||
;; The llc runs above are just to ensure it doesn't blow up upon
|
||||
;; seeing an is_constant intrinsic.
|
||||
|
||||
declare i1 @llvm.is.constant.i32(i32 %a)
|
||||
declare i1 @llvm.is.constant.i64(i64 %a)
|
||||
declare i1 @llvm.is.constant.i256(i256 %a)
|
||||
declare i1 @llvm.is.constant.v2i64(<2 x i64> %a)
|
||||
declare i1 @llvm.is.constant.f32(float %a)
|
||||
declare i1 @llvm.is.constant.sl_i32i32s({i32, i32} %a)
|
||||
declare i1 @llvm.is.constant.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 }
|
@ -24,7 +24,6 @@
|
||||
; 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
|
||||
|
@ -35,7 +35,6 @@
|
||||
; 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
|
||||
|
50
test/CodeGen/X86/is-constant.ll
Normal file
50
test/CodeGen/X86/is-constant.ll
Normal file
@ -0,0 +1,50 @@
|
||||
; RUN: llc -O2 < %s | FileCheck %s --check-prefix=CHECK-O2 --check-prefix=CHECK
|
||||
; RUN: llc -O0 -fast-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
|
||||
; RUN: llc -O0 -fast-isel=0 < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
|
||||
; RUN: llc -O0 -global-isel < %s | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=CHECK
|
||||
|
||||
;; Ensure that an unfoldable is.constant gets lowered reasonably in
|
||||
;; optimized codegen, in particular, that the "true" branch is
|
||||
;; eliminated.
|
||||
;;
|
||||
;; This isn't asserting any specific output from non-optimized runs,
|
||||
;; (e.g., currently the not-taken branch does not get eliminated). But
|
||||
;; it does ensure that lowering succeeds in all 3 codegen paths.
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
declare i1 @llvm.is.constant.i32(i32 %a) nounwind readnone
|
||||
declare i1 @llvm.is.constant.i64(i64 %a) nounwind readnone
|
||||
declare i64 @llvm.objectsize.i64.p0i8(i8*, i1, i1, 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
|
||||
}
|
55
test/CodeGen/X86/object-size.ll
Normal file
55
test/CodeGen/X86/object-size.ll
Normal file
@ -0,0 +1,55 @@
|
||||
; 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
|
||||
}
|
@ -231,7 +231,6 @@
|
||||
; 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.
|
||||
|
@ -205,7 +205,6 @@
|
||||
; 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
|
||||
|
@ -187,8 +187,6 @@
|
||||
; 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
|
||||
|
@ -192,8 +192,6 @@
|
||||
; 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
|
||||
|
@ -174,8 +174,6 @@
|
||||
; 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
|
||||
|
@ -514,6 +514,26 @@ 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
|
||||
|
||||
|
@ -1,15 +1,12 @@
|
||||
; RUN: opt -lower-constant-intrinsics -S < %s | FileCheck %s
|
||||
; 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"
|
||||
|
||||
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.
|
||||
; 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)
|
||||
@ -17,7 +14,7 @@ entry:
|
||||
br i1 %1, label %T, label %trap
|
||||
|
||||
; CHECK: entry:
|
||||
; CHECK-NOT: label %trap
|
||||
; CHECK-NOT: br label %
|
||||
|
||||
trap: ; preds = %0, %entry
|
||||
tail call void @llvm.trap() noreturn nounwind
|
||||
@ -81,3 +78,9 @@ 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
|
123
test/Transforms/CodeGenPrepare/builtin-condition.ll
Normal file
123
test/Transforms/CodeGenPrepare/builtin-condition.ll
Normal file
@ -0,0 +1,123 @@
|
||||
; 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, ...)
|
@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -lower-constant-intrinsics %s -o - | FileCheck %s
|
||||
; 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.
|
@ -1,114 +0,0 @@
|
||||
; 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
|
||||
}
|
@ -57,7 +57,6 @@ static_library("Scalar") {
|
||||
"LowerAtomic.cpp",
|
||||
"LowerExpectIntrinsic.cpp",
|
||||
"LowerGuardIntrinsic.cpp",
|
||||
"LowerConstantIntrinsics.cpp",
|
||||
"LowerWidenableCondition.cpp",
|
||||
"MakeGuardsExplicit.cpp",
|
||||
"MemCpyOptimizer.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user