diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 891b9c0af70a..25ee61e125aa 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -9427,6 +9427,46 @@ Semantics: This intrinsic is lowered to the ``val``. +'``llvm.assume``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.assume(i1 %cond) + +Overview: +""""""""" + +The ``llvm.assume`` allows the optimizer to assume that the provided +condition is true. This information can then be used in simplifying other parts +of the code. + +Arguments: +"""""""""" + +The condition which the optimizer may assume is always true. + +Semantics: +"""""""""" + +The intrinsic allows the optimizer to assume that the provided condition is +always true whenever the control flow reaches the intrinsic call. No code is +generated for this intrinsic, and instructions that contribute only to the +provided condition are not used for code generation. If the condition is +violated during execution, the behavior is undefined. + +Please note that optimizer might limit the transformations performed on values +used by the ``llvm.assume`` intrinsic in order to preserve the instructions +only used to form the intrinsic's input argument. This might prove undesirable +if the extra information provided by the ``llvm.assume`` intrinsic does cause +sufficient overall improvement in code quality. For this reason, +``llvm.assume`` should not be used to document basic mathematical invariants +that the optimizer can otherwise deduce or facts that are of little use to the +optimizer. + '``llvm.donothing``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 0b8f64fc7984..548866fbef50 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -277,6 +277,10 @@ def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; +// The assume intrinsic is marked as arbitrarily writing so that proper +// control dependencies will be maintained. +def int_assume : Intrinsic<[], [llvm_i1_ty], []>; + // Stack Protector Intrinsic - The stackprotector intrinsic writes the stack // guard to the correct place on the stack frame. def int_stackprotector : Intrinsic<[], [llvm_ptr_ty, llvm_ptrptr_ty], []>; diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 24e4bf5894b2..d7f4ebe3b9b1 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -471,10 +471,7 @@ namespace { const Location &Loc) override; ModRefResult getModRefInfo(ImmutableCallSite CS1, - ImmutableCallSite CS2) override { - // The AliasAnalysis base class has some smarts, lets use them. - return AliasAnalysis::getModRefInfo(CS1, CS2); - } + ImmutableCallSite CS2) override; /// pointsToConstantMemory - Chase pointers until we find a (constant /// global) or not. @@ -788,6 +785,14 @@ BasicAliasAnalysis::getArgLocation(ImmutableCallSite CS, unsigned ArgIdx, return Loc; } +static bool isAssumeIntrinsic(ImmutableCallSite CS) { + const IntrinsicInst *II = dyn_cast(CS.getInstruction()); + if (II && II->getIntrinsicID() == Intrinsic::assume) + return true; + + return false; +} + /// getModRefInfo - Check to see if the specified callsite can clobber the /// specified memory object. Since we only look at local properties of this /// function, we really can't say much about this query. We do, however, use @@ -840,10 +845,29 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, return NoModRef; } + // While the assume intrinsic is marked as arbitrarily writing so that + // proper control dependencies will be maintained, it never aliases any + // particular memory location. + if (isAssumeIntrinsic(CS)) + return NoModRef; + // The AliasAnalysis base class has some smarts, lets use them. return AliasAnalysis::getModRefInfo(CS, Loc); } +AliasAnalysis::ModRefResult +BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { + // While the assume intrinsic is marked as arbitrarily writing so that + // proper control dependencies will be maintained, it never aliases any + // particular memory location. + if (isAssumeIntrinsic(CS1) || isAssumeIntrinsic(CS2)) + return NoModRef; + + // The AliasAnalysis base class has some smarts, lets use them. + return AliasAnalysis::getModRefInfo(CS1, CS2); +} + /// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction /// against another pointer. We know that V1 is a GEP, but we don't know /// anything about V2. UnderlyingV1 is GetUnderlyingObject(GEP1, DL), diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index cdb0b79fd7ee..888b5cef2f8c 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -385,6 +385,7 @@ struct NoTTI final : ImmutablePass, TargetTransformInfo { // FIXME: This is wrong for libc intrinsics. return TCC_Basic; + case Intrinsic::assume: case Intrinsic::dbg_declare: case Intrinsic::dbg_value: case Intrinsic::invariant_start: diff --git a/llvm/lib/CodeGen/BasicTargetTransformInfo.cpp b/llvm/lib/CodeGen/BasicTargetTransformInfo.cpp index b2737bf754f9..d639101dd9cb 100644 --- a/llvm/lib/CodeGen/BasicTargetTransformInfo.cpp +++ b/llvm/lib/CodeGen/BasicTargetTransformInfo.cpp @@ -572,6 +572,7 @@ unsigned BasicTTI::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, case Intrinsic::pow: ISD = ISD::FPOW; break; case Intrinsic::fma: ISD = ISD::FMA; break; case Intrinsic::fmuladd: ISD = ISD::FMA; break; + // FIXME: We should return 0 whenever getIntrinsicCost == TCC_Free. case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: return 0; diff --git a/llvm/lib/CodeGen/IntrinsicLowering.cpp b/llvm/lib/CodeGen/IntrinsicLowering.cpp index a8b860034f49..9df8f3c89e7e 100644 --- a/llvm/lib/CodeGen/IntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/IntrinsicLowering.cpp @@ -459,9 +459,10 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) { CI->replaceAllUsesWith(CI->getOperand(0)); break; + case Intrinsic::assume: case Intrinsic::var_annotation: - break; // Strip out annotate intrinsic - + break; // Strip out these intrinsics + case Intrinsic::memcpy: { Type *IntPtr = DL.getIntPtrType(Context); Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index b3d6ab81ed11..4ccdb1dbc77f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5304,8 +5304,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { // Drop the intrinsic, but forward the value setValue(&I, getValue(I.getOperand(0))); return nullptr; + case Intrinsic::assume: case Intrinsic::var_annotation: - // Discard annotate attributes + // Discard annotate attributes and assumptions return nullptr; case Intrinsic::init_trampoline: { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index a5e443fcf46b..d891fc0ee1cf 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -301,6 +301,14 @@ bool llvm::isInstructionTriviallyDead(Instruction *I, if (II->getIntrinsicID() == Intrinsic::lifetime_start || II->getIntrinsicID() == Intrinsic::lifetime_end) return isa(II->getArgOperand(1)); + + // Assumptions are dead if their condition is trivially true. + if (II->getIntrinsicID() == Intrinsic::assume) { + if (ConstantInt *Cond = dyn_cast(II->getArgOperand(0))) + return !Cond->isZero(); + + return false; + } } if (isAllocLikeFn(I, TLI)) return true; @@ -1183,6 +1191,26 @@ static bool markAliveBlocks(BasicBlock *BB, // instructions into LLVM unreachable insts. The instruction combining pass // canonicalizes unreachable insts into stores to null or undef. for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;++BBI){ + // Assumptions that are known to be false are equivalent to unreachable. + // Also, if the condition is undefined, then we make the choice most + // beneficial to the optimizer, and choose that to also be unreachable. + if (IntrinsicInst *II = dyn_cast(BBI)) + if (II->getIntrinsicID() == Intrinsic::assume) { + bool MakeUnreachable = false; + if (isa(II->getArgOperand(0))) + MakeUnreachable = true; + else if (ConstantInt *Cond = + dyn_cast(II->getArgOperand(0))) + MakeUnreachable = Cond->isZero(); + + if (MakeUnreachable) { + // Don't insert a call to llvm.trap right before the unreachable. + changeToUnreachable(BBI, false); + Changed = true; + break; + } + } + if (CallInst *CI = dyn_cast(BBI)) { if (CI->doesNotReturn()) { // If we found a call to a no-return function, insert an unreachable diff --git a/llvm/test/Analysis/BasicAA/assume.ll b/llvm/test/Analysis/BasicAA/assume.ll new file mode 100644 index 000000000000..e163b5a4161c --- /dev/null +++ b/llvm/test/Analysis/BasicAA/assume.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) #0 +declare void @llvm.assume(i1) #0 + +define void @test1(i8* %P, i8* %Q) nounwind ssp { + tail call void @llvm.assume(i1 true) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) + ret void + +; CHECK-LABEL: Function: test1: + +; CHECK: MayAlias: i8* %P, i8* %Q +; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.assume(i1 true) +; CHECK: NoModRef: Ptr: i8* %Q <-> tail call void @llvm.assume(i1 true) +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.assume(i1 true) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void @llvm.assume(i1 true) +} + +attributes #0 = { nounwind } diff --git a/llvm/test/CodeGen/Generic/assume.ll b/llvm/test/CodeGen/Generic/assume.ll new file mode 100644 index 000000000000..bb045b38465d --- /dev/null +++ b/llvm/test/CodeGen/Generic/assume.ll @@ -0,0 +1,9 @@ +; RUN: llc < %s + +define void @main() { + call void @llvm.assume(i1 1) + ret void +} + +declare void @llvm.assume(i1) nounwind + diff --git a/llvm/test/Transforms/InstSimplify/assume.ll b/llvm/test/Transforms/InstSimplify/assume.ll new file mode 100644 index 000000000000..4dd0a8f4a82d --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/assume.ll @@ -0,0 +1,13 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +define void @test1() { + call void @llvm.assume(i1 1) + ret void + +; CHECK-LABEL: @test1 +; CHECK-NOT: llvm.assume +; CHECK: ret void +} + +declare void @llvm.assume(i1) nounwind + diff --git a/llvm/test/Transforms/SimplifyCFG/assume.ll b/llvm/test/Transforms/SimplifyCFG/assume.ll new file mode 100644 index 000000000000..1d1b96a58edf --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/assume.ll @@ -0,0 +1,22 @@ +; RUN: opt -simplifycfg -S < %s | FileCheck %s + +define void @test1() { + call void @llvm.assume(i1 0) + ret void + +; CHECK-LABEL: @test1 +; CHECK-NOT: llvm.assume +; CHECK: unreachable +} + +define void @test2() { + call void @llvm.assume(i1 undef) + ret void + +; CHECK-LABEL: @test2 +; CHECK-NOT: llvm.assume +; CHECK: unreachable +} + +declare void @llvm.assume(i1) nounwind +