Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -19575,6 +19575,77 @@ This function returns the same values as the libm ``trunc`` functions would and handles error conditions in the same way. +.. _int_experimental_noalias_scope_decl: + +'``llvm.experimental.noalias.scope.decl``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + + +:: + + declare void @llvm.experimental.noalias.scope.decl(metadata !id.scope) + +Overview: +""""""""" + +The ``llvm.experimental.noalias.scope.decl`` intrinsic identifies where a +noalias scope is declared. When the intrinsic is duplicated, also a decision +must be made about the scope: depending on the reason of the duplication, +sometimes the scope must be duplicated as well. + + +Arguments: +"""""""""" + +The ``!id.scope`` argument is metadata that is a list of ``noalias`` +metadata references. The format is identical to that required for ``noalias`` +metadata. This list must have exactly one element. + +Semantics: +"""""""""" + +The ``llvm.experimental.noalias.scope.decl`` intrinsic identifies where a +noalias scope is declared. When the intrinsic is duplicated, also a decision +must be made about the scope: depending on the reason of the duplication, +sometimes the scope must be duplicated as well. + +For example, when the intrinsic is used inside a loop body, and that loop is +unrolled, it is an indication that the associate noalias scope must also +be duplicated. Otherwise, the noalias property it signifies would spill +across loop iterations, whereas it was only valid within a single iteration. + +.. code-block:: llvm + + ; This examples shows two possible positions for noalias.decl: + ; If it is outside the loop (version 1), then %a and %b are noalias across *all* iterations. + ; If it is inside the loop (version 2), then %a and %b are noalias only within *one* iteration. + declare void @decl_in_loop(i8* %a.base, i8* %b.base) { + entry: + ; call void @llvm.experimental.noalias.scope.decl(metadata !2) ; Version 1: noalias decl outside loop + br label %loop + + loop: + %a = phi i8* [ %a.base, %entry ], [ %a.inc, %loop ] + %b = phi i8* [ %b.base, %entry ], [ %b.inc, %loop ] + ; call void @llvm.experimental.noalias.scope.decl(metadata !2) ; Version 2: noalias decl inside loop + %val = load i8, i8* %a, !alias.scope !2 + store i8 %val, i8* %b, !noalias !2 + %a.inc = getelementptr inbounds i8, i8* %a, i64 1 + %b.inc = getelementptr inbounds i8, i8* %a, i64 1 + %cond = call i1 @cond() + br i1 %cond, label %loop, label %exit + + exit: + ret void + } + + !0 = !{!0} ; domain + !1 = !{!1, !0} ; scope + !2 = !{!1} ; scope list + Floating Point Environment Manipulation intrinsics -------------------------------------------------- Index: llvm/include/llvm/IR/IRBuilder.h =================================================================== --- llvm/include/llvm/IR/IRBuilder.h +++ llvm/include/llvm/IR/IRBuilder.h @@ -858,6 +858,13 @@ CallInst *CreateAssumption(Value *Cond, ArrayRef OpBundles = llvm::None); + /// Create a llvm.experimental.noalias.scope.decl intrinsic call. + Instruction *CreateNoAliasScopeDeclaration(Value *Scope); + Instruction *CreateNoAliasScopeDeclaration(MDNode *ScopeTag) { + return CreateNoAliasScopeDeclaration( + MetadataAsValue::get(Context, ScopeTag)); + } + /// Create a call to the experimental.gc.statepoint intrinsic to /// start a new statepoint sequence. CallInst *CreateGCStatepointCall(uint64_t ID, uint32_t NumPatchBytes, Index: llvm/include/llvm/IR/Intrinsics.h =================================================================== --- llvm/include/llvm/IR/Intrinsics.h +++ llvm/include/llvm/IR/Intrinsics.h @@ -34,6 +34,9 @@ /// function known by LLVM. The enum values are returned by /// Function::getIntrinsicID(). namespace Intrinsic { + // Abstraction for the arguments of the noalias intrinsics + static const int NoAliasScopeDeclScopeArg = 0; + // Intrinsic ID type. This is an opaque typedef to facilitate splitting up // the enum into target-specific enums. typedef unsigned ID; Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -539,6 +539,16 @@ def int_assume : DefaultAttrsIntrinsic<[], [llvm_i1_ty], [IntrWillReturn, NoUndef>]>; +// 'llvm.experimental.noalias.scope.decl' intrinsic: Inserted at the location of +// noalias scope declaration. Makes it possible to identify that a noalias scope +// is only valid inside the body of a loop. +// +// Purpose of the different arguments: +// - arg0: id.scope: metadata representing the scope declaration. +def int_experimental_noalias_scope_decl + : DefaultAttrsIntrinsic<[], [llvm_metadata_ty], + [IntrInaccessibleMemOnly]>; // blocks LICM and some more + // Stack Protector Intrinsic - The stackprotector intrinsic writes the stack // guard to the correct place on the stack frame. def int_stackprotector : DefaultAttrsIntrinsic<[], [llvm_ptr_ty, llvm_ptrptr_ty], []>; Index: llvm/lib/CodeGen/IntrinsicLowering.cpp =================================================================== --- llvm/lib/CodeGen/IntrinsicLowering.cpp +++ llvm/lib/CodeGen/IntrinsicLowering.cpp @@ -329,6 +329,7 @@ break; case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::var_annotation: break; // Strip out these intrinsics Index: llvm/lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1375,6 +1375,8 @@ case Intrinsic::sideeffect: // Neither does the assume intrinsic; it's also OK not to codegen its operand. case Intrinsic::assume: + // Neither does the llvm.experimental.noalias.scope.decl intrinsic + case Intrinsic::experimental_noalias_scope_decl: return true; case Intrinsic::dbg_declare: { const DbgDeclareInst *DI = cast(II); Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6404,7 +6404,7 @@ return; } case Intrinsic::stackprotector: { - // Emit code into the DAG to store the stack guard onto the stack. + // Emit code into the DAG tostore the stack guard onto the stack. MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); SDValue Src, Chain = getRoot(); @@ -6444,10 +6444,13 @@ // Drop the intrinsic, but forward the value setValue(&I, getValue(I.getOperand(0))); return; + case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::var_annotation: case Intrinsic::sideeffect: - // Discard annotate attributes, assumptions, and artificial side-effects. + // Discard annotate attributes, noalias scope declarations, assumptions, and + // artificial side-effects. return; case Intrinsic::codeview_annotation: { Index: llvm/lib/IR/IRBuilder.cpp =================================================================== --- llvm/lib/IR/IRBuilder.cpp +++ llvm/lib/IR/IRBuilder.cpp @@ -452,6 +452,15 @@ return createCallHelper(FnAssume, Ops, this, "", nullptr, OpBundles); } +Instruction *IRBuilderBase::CreateNoAliasScopeDeclaration(Value *Scope) { + SmallVector Ops = {Scope}; + + Module *M = BB->getModule(); + auto *FnIntrinsic = Intrinsic::getDeclaration( + M, Intrinsic::experimental_noalias_scope_decl, {}); + return createCallHelper(FnIntrinsic, Ops, this); +} + /// Create a call to a Masked Load intrinsic. /// \p Ptr - base pointer for the load /// \p Alignment - alignment of the source location