Commit 2e26633a authored by Sanjay Patel's avatar Sanjay Patel
Browse files

[IR] document and update ctlz/cttz intrinsics to optionally return poison rather than undef

The behavior in Analysis (knownbits) implements poison semantics already,
and we expect the transforms (for example, in instcombine) derived from
those semantics, so this patch changes the LangRef and remaining code to
be consistent. This is one more step in removing "undef" from LLVM.

Without this, I think https://github.com/llvm/llvm-project/issues/53330
has a legitimate complaint because that report wants to allow subsequent
code to mask off bits, and that is allowed with undef values. The clang
builtins are not actually documented anywhere AFAICT, but we might want
to add that to remove more uncertainty.

Differential Revision: https://reviews.llvm.org/D117912
parent 7c66aadd
......@@ -14958,12 +14958,8 @@ targets support all bit widths or vector types, however.
 
::
 
declare i8 @llvm.ctlz.i8 (i8 <src>, i1 <is_zero_undef>)
declare i16 @llvm.ctlz.i16 (i16 <src>, i1 <is_zero_undef>)
declare i32 @llvm.ctlz.i32 (i32 <src>, i1 <is_zero_undef>)
declare i64 @llvm.ctlz.i64 (i64 <src>, i1 <is_zero_undef>)
declare i256 @llvm.ctlz.i256(i256 <src>, i1 <is_zero_undef>)
declare <2 x i32> @llvm.ctlz.v2i32(<2 x i32> <src>, i1 <is_zero_undef>)
declare i8 @llvm.ctlz.i8 (i8 <src>, i1 <is_zero_poison>)
declare <2 x i37> @llvm.ctlz.v2i37(<2 x i37> <src>, i1 <is_zero_poison>)
 
Overview:
"""""""""
......@@ -14978,11 +14974,12 @@ The first argument is the value to be counted. This argument may be of
any integer type, or a vector with integer element type. The return
type must match the first argument type.
 
The second argument must be a constant and is a flag to indicate whether
the intrinsic should ensure that a zero as the first argument produces a
defined result. Historically some architectures did not provide a
defined result for zero values as efficiently, and many algorithms are
now predicated on avoiding zero-value inputs.
The second argument is a constant flag that indicates whether the intrinsic
returns a valid result if the first argument is zero. If the first
argument is zero and the second argument is true, the result is poison.
Historically some architectures did not provide a defined result for zero
values as efficiently, and many algorithms are now predicated on avoiding
zero-value inputs.
 
Semantics:
""""""""""
......@@ -14990,7 +14987,7 @@ Semantics:
The '``llvm.ctlz``' intrinsic counts the leading (most significant)
zeros in a variable, or within each element of the vector. If
``src == 0`` then the result is the size in bits of the type of ``src``
if ``is_zero_undef == 0`` and ``undef`` otherwise. For example,
if ``is_zero_poison == 0`` and ``poison`` otherwise. For example,
``llvm.ctlz(i32 2) = 30``.
 
'``llvm.cttz.*``' Intrinsic
......@@ -15005,12 +15002,8 @@ support all bit widths or vector types, however.
 
::
 
declare i8 @llvm.cttz.i8 (i8 <src>, i1 <is_zero_undef>)
declare i16 @llvm.cttz.i16 (i16 <src>, i1 <is_zero_undef>)
declare i32 @llvm.cttz.i32 (i32 <src>, i1 <is_zero_undef>)
declare i64 @llvm.cttz.i64 (i64 <src>, i1 <is_zero_undef>)
declare i256 @llvm.cttz.i256(i256 <src>, i1 <is_zero_undef>)
declare <2 x i32> @llvm.cttz.v2i32(<2 x i32> <src>, i1 <is_zero_undef>)
declare i42 @llvm.cttz.i42 (i42 <src>, i1 <is_zero_poison>)
declare <2 x i32> @llvm.cttz.v2i32(<2 x i32> <src>, i1 <is_zero_poison>)
 
Overview:
"""""""""
......@@ -15025,11 +15018,12 @@ The first argument is the value to be counted. This argument may be of
any integer type, or a vector with integer element type. The return
type must match the first argument type.
 
The second argument must be a constant and is a flag to indicate whether
the intrinsic should ensure that a zero as the first argument produces a
defined result. Historically some architectures did not provide a
defined result for zero values as efficiently, and many algorithms are
now predicated on avoiding zero-value inputs.
The second argument is a constant flag that indicates whether the intrinsic
returns a valid result if the first argument is zero. If the first
argument is zero and the second argument is true, the result is poison.
Historically some architectures did not provide a defined result for zero
values as efficiently, and many algorithms are now predicated on avoiding
zero-value inputs.
 
Semantics:
""""""""""
......@@ -15037,7 +15031,7 @@ Semantics:
The '``llvm.cttz``' intrinsic counts the trailing (least significant)
zeros in a variable, or within each element of a vector. If ``src == 0``
then the result is the size in bits of the type of ``src`` if
``is_zero_undef == 0`` and ``undef`` otherwise. For example,
``is_zero_poison == 0`` and ``poison`` otherwise. For example,
``llvm.cttz(2) = 1``.
 
.. _int_overflow:
......
......@@ -2572,9 +2572,9 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
case Intrinsic::ctlz:
assert(C1 && "Must be constant int");
// cttz(0, 1) and ctlz(0, 1) are undef.
// cttz(0, 1) and ctlz(0, 1) are poison.
if (C1->isOne() && (!C0 || C0->isZero()))
return UndefValue::get(Ty);
return PoisonValue::get(Ty);
if (!C0)
return Constant::getNullValue(Ty);
if (IntrinsicID == Intrinsic::cttz)
......
......@@ -1593,7 +1593,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
// If we have a known 1, its position is our upper bound.
unsigned PossibleLZ = Known2.countMaxLeadingZeros();
// If this call is undefined for 0, the result will be less than 2^n.
// If this call is poison for 0 input, the result will be less than 2^n.
if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext()))
PossibleLZ = std::min(PossibleLZ, BitWidth - 1);
unsigned LowBits = Log2_32(PossibleLZ)+1;
......@@ -1604,7 +1604,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q);
// If we have a known 1, its position is our upper bound.
unsigned PossibleTZ = Known2.countMaxTrailingZeros();
// If this call is undefined for 0, the result will be less than 2^n.
// If this call is poison for 0 input, the result will be less than 2^n.
if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext()))
PossibleTZ = std::min(PossibleTZ, BitWidth - 1);
unsigned LowBits = Log2_32(PossibleTZ)+1;
......
......@@ -494,7 +494,7 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
// ctlz/cttz i1 Op0 --> not Op0
if (match(Op1, m_Zero()))
return BinaryOperator::CreateNot(Op0);
// If zero is undef, then the input can be assumed to be "true", so the
// If zero is poison, then the input can be assumed to be "true", so the
// instruction simplifies to "false".
assert(match(Op1, m_One()) && "Expected ctlz/cttz operand to be 0 or 1");
return IC.replaceInstUsesWith(II, ConstantInt::getNullValue(II.getType()));
......@@ -519,7 +519,7 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
}
// Zext doesn't change the number of trailing zeros, so narrow:
// cttz(zext(x)) -> zext(cttz(x)) if the 'ZeroIsUndef' parameter is 'true'.
// cttz(zext(x)) -> zext(cttz(x)) if the 'ZeroIsPoison' parameter is 'true'.
if (match(Op0, m_OneUse(m_ZExt(m_Value(X)))) && match(Op1, m_One())) {
auto *Cttz = IC.Builder.CreateBinaryIntrinsic(Intrinsic::cttz, X,
IC.Builder.getTrue());
......@@ -556,7 +556,7 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
}
// If the input to cttz/ctlz is known to be non-zero,
// then change the 'ZeroIsUndef' parameter to 'true'
// then change the 'ZeroIsPoison' parameter to 'true'
// because we know the zero behavior can't affect the result.
if (!Known.One.isZero() ||
isKnownNonZero(Op0, IC.getDataLayout(), 0, &IC.getAssumptionCache(), &II,
......
......@@ -943,7 +943,7 @@ static Instruction *foldSelectCtlzToCttz(ICmpInst *ICI, Value *TrueVal,
}
/// Attempt to fold a cttz/ctlz followed by a icmp plus select into a single
/// call to cttz/ctlz with flag 'is_zero_undef' cleared.
/// call to cttz/ctlz with flag 'is_zero_poison' cleared.
///
/// For example, we can fold the following code sequence:
/// \code
......@@ -987,7 +987,7 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
// sizeof in bits of 'Count'.
unsigned SizeOfInBits = Count->getType()->getScalarSizeInBits();
if (match(ValueOnZero, m_SpecificInt(SizeOfInBits))) {
// Explicitly clear the 'undef_on_zero' flag. It's always valid to go from
// Explicitly clear the 'is_zero_poison' flag. It's always valid to go from
// true to false on this flag, so we can replace it for all users.
II->setArgOperand(1, ConstantInt::getFalse(II->getContext()));
return SelectArg;
......@@ -995,7 +995,7 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
// The ValueOnZero is not the bitwidth. But if the cttz/ctlz (and optional
// zext/trunc) have one use (ending at the select), the cttz/ctlz result will
// not be used if the input is zero. Relax to 'undef_on_zero' for that case.
// not be used if the input is zero. Relax to 'zero is poison' for that case.
if (II->hasOneUse() && SelectArg->hasOneUse() &&
!match(II->getArgOperand(1), m_One()))
II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
......
......@@ -36,7 +36,7 @@ define i32 @ctlz_sel_const_true(i1 %b, i32 %x) {
define <3 x i17> @ctlz_sel_const_false(<3 x i1> %b, <3 x i17> %x) {
; CHECK-LABEL: @ctlz_sel_const_false(
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i17> @llvm.ctlz.v3i17(<3 x i17> [[X:%.*]], i1 true)
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i17> [[TMP1]], <3 x i17> <i17 14, i17 0, i17 undef>
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i17> [[TMP1]], <3 x i17> <i17 14, i17 0, i17 poison>
; CHECK-NEXT: ret <3 x i17> [[C]]
;
%s = select <3 x i1> %b, <3 x i17> %x, <3 x i17> <i17 7, i17 -1, i17 0>
......
......@@ -79,8 +79,8 @@ define i1 @cttz_i1(i1 %arg) {
ret i1 %cnt
}
define i1 @cttz_i1_zero_is_undef(i1 %arg) {
; CHECK-LABEL: @cttz_i1_zero_is_undef(
define i1 @cttz_i1_zero_is_poison(i1 %arg) {
; CHECK-LABEL: @cttz_i1_zero_is_poison(
; CHECK-NEXT: ret i1 false
;
%cnt = call i1 @llvm.cttz.i1(i1 %arg, i1 true) nounwind readnone
......@@ -96,8 +96,8 @@ define <2 x i1> @cttz_v2i1(<2 x i1> %arg) {
ret <2 x i1> %cnt
}
define <2 x i1> @cttz_v2i1_zero_is_undef(<2 x i1> %arg) {
; CHECK-LABEL: @cttz_v2i1_zero_is_undef(
define <2 x i1> @cttz_v2i1_zero_is_poison(<2 x i1> %arg) {
; CHECK-LABEL: @cttz_v2i1_zero_is_poison(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%cnt = call <2 x i1> @llvm.cttz.v2i1(<2 x i1> %arg, i1 true) nounwind readnone
......@@ -196,8 +196,8 @@ define i1 @ctlz_i1(i1 %arg) {
ret i1 %cnt
}
define i1 @ctlz_i1_zero_is_undef(i1 %arg) {
; CHECK-LABEL: @ctlz_i1_zero_is_undef(
define i1 @ctlz_i1_zero_is_poison(i1 %arg) {
; CHECK-LABEL: @ctlz_i1_zero_is_poison(
; CHECK-NEXT: ret i1 false
;
%cnt = call i1 @llvm.ctlz.i1(i1 %arg, i1 true) nounwind readnone
......@@ -213,8 +213,8 @@ define <2 x i1> @ctlz_v2i1(<2 x i1> %arg) {
ret <2 x i1> %cnt
}
define <2 x i1> @ctlz_v2i1_zero_is_undef(<2 x i1> %arg) {
; CHECK-LABEL: @ctlz_v2i1_zero_is_undef(
define <2 x i1> @ctlz_v2i1_zero_is_poison(<2 x i1> %arg) {
; CHECK-LABEL: @ctlz_v2i1_zero_is_poison(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%cnt = call <2 x i1> @llvm.ctlz.v2i1(<2 x i1> %arg, i1 true) nounwind readnone
......@@ -283,24 +283,24 @@ define <2 x i1> @ctlz_knownbits3_vec(<2 x i8> %arg) {
ret <2 x i1> %res
}
define i32 @ctlz_undef(i32 %Value) {
; CHECK-LABEL: @ctlz_undef(
; CHECK-NEXT: ret i32 undef
define i32 @ctlz_poison(i32 %Value) {
; CHECK-LABEL: @ctlz_poison(
; CHECK-NEXT: ret i32 poison
;
%ctlz = call i32 @llvm.ctlz.i32(i32 0, i1 true)
ret i32 %ctlz
}
define <2 x i32> @ctlz_undef_vec(<2 x i32> %Value) {
; CHECK-LABEL: @ctlz_undef_vec(
; CHECK-NEXT: ret <2 x i32> undef
define <2 x i32> @ctlz_poison_vec(<2 x i32> %Value) {
; CHECK-LABEL: @ctlz_poison_vec(
; CHECK-NEXT: ret <2 x i32> poison
;
%ctlz = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> zeroinitializer, i1 true)
ret <2 x i32> %ctlz
}
define i32 @ctlz_make_undef(i32 %a) {
; CHECK-LABEL: @ctlz_make_undef(
define i32 @ctlz_no_zero(i32 %a) {
; CHECK-LABEL: @ctlz_no_zero(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], 8
; CHECK-NEXT: [[CTLZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[OR]], i1 true), !range [[RNG2:![0-9]+]]
; CHECK-NEXT: ret i32 [[CTLZ]]
......@@ -310,8 +310,8 @@ define i32 @ctlz_make_undef(i32 %a) {
ret i32 %ctlz
}
define <2 x i32> @ctlz_make_undef_vec(<2 x i32> %a) {
; CHECK-LABEL: @ctlz_make_undef_vec(
define <2 x i32> @ctlz_no_zero_vec(<2 x i32> %a) {
; CHECK-LABEL: @ctlz_no_zero_vec(
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[A:%.*]], <i32 8, i32 8>
; CHECK-NEXT: [[CTLZ:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[OR]], i1 true)
; CHECK-NEXT: ret <2 x i32> [[CTLZ]]
......@@ -321,24 +321,24 @@ define <2 x i32> @ctlz_make_undef_vec(<2 x i32> %a) {
ret <2 x i32> %ctlz
}
define i32 @cttz_undef(i32 %Value) nounwind {
; CHECK-LABEL: @cttz_undef(
; CHECK-NEXT: ret i32 undef
define i32 @cttz_poison(i32 %Value) {
; CHECK-LABEL: @cttz_poison(
; CHECK-NEXT: ret i32 poison
;
%cttz = call i32 @llvm.cttz.i32(i32 0, i1 true)
ret i32 %cttz
}
define <2 x i32> @cttz_undef_vec(<2 x i32> %Value) nounwind {
; CHECK-LABEL: @cttz_undef_vec(
; CHECK-NEXT: ret <2 x i32> undef
define <2 x i32> @cttz_poison_vec(<2 x i32> %Value) {
; CHECK-LABEL: @cttz_poison_vec(
; CHECK-NEXT: ret <2 x i32> poison
;
%cttz = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> zeroinitializer, i1 true)
ret <2 x i32> %cttz
}
define i32 @cttz_make_undef(i32 %a) {
; CHECK-LABEL: @cttz_make_undef(
define i32 @cttz_no_zero(i32 %a) {
; CHECK-LABEL: @cttz_no_zero(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], 8
; CHECK-NEXT: [[CTTZ:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[OR]], i1 true), !range [[RNG3:![0-9]+]]
; CHECK-NEXT: ret i32 [[CTTZ]]
......@@ -348,8 +348,8 @@ define i32 @cttz_make_undef(i32 %a) {
ret i32 %cttz
}
define <2 x i32> @cttz_make_undef_vec(<2 x i32> %a) {
; CHECK-LABEL: @cttz_make_undef_vec(
define <2 x i32> @cttz_no_zero_vec(<2 x i32> %a) {
; CHECK-LABEL: @cttz_no_zero_vec(
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[A:%.*]], <i32 8, i32 8>
; CHECK-NEXT: [[CTTZ:%.*]] = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true)
; CHECK-NEXT: ret <2 x i32> [[CTTZ]]
......
......@@ -48,9 +48,9 @@ define i32 @cttz_zero_defined() {
ret i32 %x
}
define i32 @cttz_zero_undefined() {
; CHECK-LABEL: @cttz_zero_undefined(
; CHECK-NEXT: ret i32 undef
define i32 @cttz_zero_is_poison() {
; CHECK-LABEL: @cttz_zero_is_poison(
; CHECK-NEXT: ret i32 poison
;
%x = call i32 @llvm.cttz.i32(i32 0, i1 true)
ret i32 %x
......@@ -64,9 +64,9 @@ define i33 @ctlz_zero_defined() {
ret i33 %x
}
define i33 @ctlz_zero_undefined() {
; CHECK-LABEL: @ctlz_zero_undefined(
; CHECK-NEXT: ret i33 undef
define i33 @ctlz_zero_is_poison() {
; CHECK-LABEL: @ctlz_zero_is_poison(
; CHECK-NEXT: ret i33 poison
;
%x = call i33 @llvm.ctlz.i33(i33 0, i1 true)
ret i33 %x
......@@ -88,9 +88,9 @@ define i32 @cttz_undef_defined() {
ret i32 %x
}
define i32 @cttz_undef_undefined() {
; CHECK-LABEL: @cttz_undef_undefined(
; CHECK-NEXT: ret i32 undef
define i32 @cttz_undef_zero_is_poison() {
; CHECK-LABEL: @cttz_undef_zero_is_poison(
; CHECK-NEXT: ret i32 poison
;
%x = call i32 @llvm.cttz.i32(i32 undef, i1 true)
ret i32 %x
......@@ -104,9 +104,9 @@ define i33 @ctlz_undef_defined() {
ret i33 %x
}
define i33 @ctlz_undef_undefined() {
; CHECK-LABEL: @ctlz_undef_undefined(
; CHECK-NEXT: ret i33 undef
define i33 @ctlz_undef_zero_is_poison() {
; CHECK-LABEL: @ctlz_undef_zero_is_poison(
; CHECK-NEXT: ret i33 poison
;
%x = call i33 @llvm.ctlz.i33(i33 undef, i1 true)
ret i33 %x
......@@ -144,9 +144,9 @@ define <2 x i32> @cttz_vector_undef_defined() {
ret <2 x i32> %x
}
define <2 x i32> @cttz_vector_undef_undefined() {
; CHECK-LABEL: @cttz_vector_undef_undefined(
; CHECK-NEXT: ret <2 x i32> undef
define <2 x i32> @cttz_vector_undef_zero_is_poison() {
; CHECK-LABEL: @cttz_vector_undef_zero_is_poison(
; CHECK-NEXT: ret <2 x i32> poison
;
%x = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> <i32 0, i32 undef>, i1 true)
ret <2 x i32> %x
......@@ -168,9 +168,9 @@ define <2 x i33> @ctlz_vector_undef_defined() {
ret <2 x i33> %x
}
define <2 x i33> @ctlz_vector_undef_undefined() {
; CHECK-LABEL: @ctlz_vector_undef_undefined(
; CHECK-NEXT: ret <2 x i33> undef
define <2 x i33> @ctlz_vector_undef_zero_is_poison() {
; CHECK-LABEL: @ctlz_vector_undef_zero_is_poison(
; CHECK-NEXT: ret <2 x i33> poison
;
%x = call <2 x i33> @llvm.ctlz.v2i33(<2 x i33> <i33 0, i33 undef>, i1 true)
ret <2 x i33> %x
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment