Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -11996,7 +11996,7 @@ :: - declare void @llvm.invariant.end.p0i8({}* , i64 , i8* nocapture ) + declare void @llvm.invariant.end.p0i8({}* readnone , i64 , i8* nocapture ) Overview: """"""""" Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -576,7 +576,8 @@ def int_invariant_end : Intrinsic<[], [llvm_descriptor_ty, llvm_i64_ty, llvm_anyptr_ty], - [IntrArgMemOnly, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>, + ReadNone<0>]>; def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], Index: lib/Analysis/MemoryLocation.cpp =================================================================== --- lib/Analysis/MemoryLocation.cpp +++ lib/Analysis/MemoryLocation.cpp @@ -121,9 +121,16 @@ Arg, cast(II->getArgOperand(0))->getZExtValue(), AATags); case Intrinsic::invariant_end: - assert(ArgIdx == 2 && "Invalid argument index"); - return MemoryLocation( - Arg, cast(II->getArgOperand(1))->getZExtValue(), AATags); + if (ArgIdx == 0) + // Technically, this is a token gotten from a previous invariant_start + // and not a true pointer, so return a dummy MemoryLocation. + return MemoryLocation(Arg, 0); + else if (ArgIdx == 2) + return MemoryLocation( + Arg, cast(II->getArgOperand(1))->getZExtValue(), + AATags); + // For all other argument indices, this call is invalid. + assert(false && "Invalid argument index"); case Intrinsic::arm_neon_vld1: assert(ArgIdx == 0 && "Invalid argument index"); Index: test/Analysis/BasicAA/getforargument-crash.ll =================================================================== --- /dev/null +++ test/Analysis/BasicAA/getforargument-crash.ll @@ -0,0 +1,27 @@ +; RUN: opt -disable-output 2>&1 -basicaa -aa-eval -print-all-alias-modref-info \ +; RUN: %s 2>&1 | FileCheck %s + +declare {}* @llvm.invariant.start(i64, i8* nocapture) nounwind readonly +declare void @llvm.invariant.end({}* readnone, i64, i8* nocapture) nounwind +declare void @f({}*) + +; Previously caused getModRefInfo to retrieve a MemoryLocation for an invalid +; argument to the intrinsic. +define void @tests_invariant_start_end() { +; CHECK-LABEL: tests_invariant_start_end + %a = alloca i8 + %i = call {}* @llvm.invariant.start(i64 1, i8* %a) + call void @llvm.invariant.end({}* %i, i64 1, i8* %a) + ret void +} + +; Prove that invariant.end's first argument is readnone. +define void @it_really_is_readnone({}* %g) { +; CHECK-LABEL: it_really_is_readnone + %a = alloca i8 + %i = call {}* @llvm.invariant.start(i64 1, i8* %a) + call void @f({}* %g) + call void @llvm.invariant.end({}* %i, i64 1, i8* %a) +; CHECK: NoModRef: call void @f({}* %g) <-> call void @llvm.invariant.end.p0i8({}* %1, i64 1, i8* %a) + ret void +}