Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -9347,6 +9347,41 @@ 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 ``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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -277,6 +277,10 @@ 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], []>; Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -482,10 +482,7 @@ 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. @@ -799,6 +796,14 @@ 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 @@ -851,10 +856,29 @@ 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), Index: lib/Analysis/TargetTransformInfo.cpp =================================================================== --- lib/Analysis/TargetTransformInfo.cpp +++ lib/Analysis/TargetTransformInfo.cpp @@ -385,6 +385,7 @@ // 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: Index: lib/CodeGen/BasicTargetTransformInfo.cpp =================================================================== --- lib/CodeGen/BasicTargetTransformInfo.cpp +++ lib/CodeGen/BasicTargetTransformInfo.cpp @@ -572,6 +572,7 @@ 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; Index: lib/CodeGen/IntrinsicLowering.cpp =================================================================== --- lib/CodeGen/IntrinsicLowering.cpp +++ lib/CodeGen/IntrinsicLowering.cpp @@ -459,9 +459,10 @@ 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, Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5260,8 +5260,9 @@ // 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: { Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -301,6 +301,14 @@ 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,24 @@ // 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. + 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 Index: test/Analysis/BasicAA/assume.ll =================================================================== --- /dev/null +++ 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 } Index: test/CodeGen/Generic/assume.ll =================================================================== --- /dev/null +++ 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 + Index: test/Transforms/InstSimplify/assume.ll =================================================================== --- /dev/null +++ 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 + Index: test/Transforms/SimplifyCFG/assume.ll =================================================================== --- /dev/null +++ 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 +