diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2378,22 +2378,33 @@ ^^^^^^^^^^^^^^^^^^^^^^ Operand bundles on an :ref:`llvm.assume ` allows representing -assumptions that a :ref:`parameter attribute ` or a -:ref:`function attribute ` holds for a certain value at a certain -location. Operand bundles enable assumptions that are either hard or impossible -to represent as a boolean argument of an :ref:`llvm.assume `. +various assumptions. This is most commonly used to represent assumptions that a +:ref:`parameter attribute ` or a :ref:`function attribute ` +holds for a certain value at a certain location. Operand bundles enable +assumptions that are either hard or impossible to represent as a boolean +argument of an :ref:`llvm.assume `. An assume operand bundle has the form: :: - ""([ [, ] ]) + ""([ [, ] ]) -* The tag of the operand bundle is usually the name of attribute that can be - assumed to hold. It can also be `ignore`, this tag doesn't contain any +* The tag of the operand bundle can be the name of attribute that can be + assumed to hold. + + * The first argument if present is the value for which the attribute holds. + * The second argument if present is an argument of the attribute. + +* The tag can be `load_eq`, meaning that the value pointed to by the pointer + argument is known to be a certain value. + + * The first argument is the pointer argument. + * The second argument is the value that the pointer argument is known to point + to. + +* The tag can be `ignore`, meaning this tag doesn't contain any information and should be ignored. -* The first argument if present is the value for which the attribute hold. -* The second argument if present is an argument of the attribute. If there are no arguments the attribute is a property of the call location. diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -4651,35 +4651,51 @@ case Intrinsic::assume: { for (auto &Elem : Call.bundle_op_infos()) { Assert(Elem.Tag->getKey() == "ignore" || + Elem.Tag->getKey() == "load_eq" || Attribute::isExistingAttribute(Elem.Tag->getKey()), "tags must be valid attribute names", Call); - Attribute::AttrKind Kind = - Attribute::getAttrKindFromName(Elem.Tag->getKey()); unsigned ArgCount = Elem.End - Elem.Begin; - if (Kind == Attribute::Alignment) { - Assert(ArgCount <= 3 && ArgCount >= 2, - "alignment assumptions should have 2 or 3 arguments", Call); - Assert(Call.getOperand(Elem.Begin)->getType()->isPointerTy(), - "first argument should be a pointer", Call); - Assert(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(), - "second argument should be an integer", Call); - if (ArgCount == 3) - Assert(Call.getOperand(Elem.Begin + 2)->getType()->isIntegerTy(), - "third argument should be an integer if present", Call); - return; - } - Assert(ArgCount <= 2, "too many arguments", Call); - if (Kind == Attribute::None) - break; - if (Attribute::isIntAttrKind(Kind)) { - Assert(ArgCount == 2, "this attribute should have 2 arguments", Call); - Assert(isa(Call.getOperand(Elem.Begin + 1)), - "the second argument should be a constant integral value", Call); - } else if (Attribute::canUseAsParamAttr(Kind)) { - Assert((ArgCount) == 1, "this attribute should have one argument", + if (Elem.Tag->getKey() == "load_eq") { + Assert(ArgCount == 2, "load_eq assume should have 2 arguments", Call); + auto *PTy = + dyn_cast(Call.getOperand(Elem.Begin)->getType()); + Assert(PTy, "load_eq assume's first argument should be a pointer", Call); - } else if (Attribute::canUseAsFnAttr(Kind)) { - Assert((ArgCount) == 0, "this attribute has no argument", Call); + auto *VTy = Call.getOperand(Elem.Begin + 1)->getType(); + Assert( + PTy->isOpaqueOrPointeeTypeMatches(VTy), + "load_eq assume's first argument should be a pointer to the second " + "argument's type", + Call); + } else { + Attribute::AttrKind Kind = + Attribute::getAttrKindFromName(Elem.Tag->getKey()); + if (Kind == Attribute::Alignment) { + Assert(ArgCount <= 3 && ArgCount >= 2, + "alignment assumptions should have 2 or 3 arguments", Call); + Assert(Call.getOperand(Elem.Begin)->getType()->isPointerTy(), + "first argument should be a pointer", Call); + Assert(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(), + "second argument should be an integer", Call); + if (ArgCount == 3) + Assert(Call.getOperand(Elem.Begin + 2)->getType()->isIntegerTy(), + "third argument should be an integer if present", Call); + return; + } + Assert(ArgCount <= 2, "too many arguments", Call); + if (Kind == Attribute::None) + break; + if (Attribute::isIntAttrKind(Kind)) { + Assert(ArgCount == 2, "this attribute should have 2 arguments", Call); + Assert(isa(Call.getOperand(Elem.Begin + 1)), + "the second argument should be a constant integral value", + Call); + } else if (Attribute::canUseAsParamAttr(Kind)) { + Assert((ArgCount) == 1, "this attribute should have one argument", + Call); + } else if (Attribute::canUseAsFnAttr(Kind)) { + Assert((ArgCount) == 0, "this attribute has no argument", Call); + } } } break; diff --git a/llvm/test/Verifier/assume-bundles.ll b/llvm/test/Verifier/assume-bundles.ll --- a/llvm/test/Verifier/assume-bundles.ll +++ b/llvm/test/Verifier/assume-bundles.ll @@ -24,5 +24,11 @@ call void @llvm.assume(i1 true) ["align"(i32* %P, i32* %P2)] ; CHECK: third argument should be an integer if present call void @llvm.assume(i1 true) ["align"(i32* %P, i32 %P1, i32* %P2)] +; CHECK: load_eq assume should have 2 arguments + call void @llvm.assume(i1 true) ["load_eq"(i32* %P)] +; CHECK: load_eq assume's first argument should be a pointer + call void @llvm.assume(i1 true) ["load_eq"(i32 %P1, i32 %P1)] +; CHECK: load_eq assume's first argument should be a pointer to the second argument's type + call void @llvm.assume(i1 true) ["load_eq"(i32* %P, i16 2)] ret void }