[llvm] 9170e38 - Add support for `nneg` flag with `uitofp`
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 9 16:12:48 PDT 2024
Author: Noah Goldstein
Date: 2024-04-09T18:12:33-05:00
New Revision: 9170e3857521324c096240bf38877e0ffe1a402e
URL: https://github.com/llvm/llvm-project/commit/9170e3857521324c096240bf38877e0ffe1a402e
DIFF: https://github.com/llvm/llvm-project/commit/9170e3857521324c096240bf38877e0ffe1a402e.diff
LOG: Add support for `nneg` flag with `uitofp`
As noted when #82404 was pushed (canonicalizing `sitofp` -> `uitofp`),
different signedness on fp casts can have dramatic performance
implications on different backends.
So, it makes to create a reliable means for the backend to pick its
cast signedness if either are correct.
Further, this allows us to start canonicalizing `sitofp`- > `uitofp`
which may easy middle end analysis.
Closes #86141
Added:
Modified:
llvm/docs/LangRef.rst
llvm/include/llvm/IR/IRBuilder.h
llvm/include/llvm/IR/InstrTypes.h
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/Bitcode/Reader/BitcodeReader.cpp
llvm/lib/IR/Instruction.cpp
llvm/lib/IR/Operator.cpp
llvm/test/Assembler/flags.ll
llvm/test/Bitcode/flags.ll
llvm/test/Transforms/InstCombine/freeze.ll
llvm/test/Transforms/SimplifyCFG/HoistCode.ll
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 18fc46584d09ad..f6ada292b93b10 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11751,6 +11751,10 @@ Overview:
The '``uitofp``' instruction regards ``value`` as an unsigned integer
and converts that value to the ``ty2`` type.
+The ``nneg`` (non-negative) flag, if present, specifies that the
+operand is non-negative. This property may be used by optimization
+passes to later convert the ``uitofp`` into a ``sitofp``.
+
Arguments:
""""""""""
@@ -11768,6 +11772,9 @@ integer quantity and converts it to the corresponding floating-point
value. If the value cannot be exactly represented, it is rounded using
the default rounding mode.
+If the ``nneg`` flag is set, and the ``uitofp`` argument is negative,
+the result is a poison value.
+
Example:
""""""""
@@ -11777,6 +11784,9 @@ Example:
%X = uitofp i32 257 to float ; yields float:257.0
%Y = uitofp i8 -1 to double ; yields double:255.0
+ %a = uitofp nneg i32 256 to i32 ; yields float:256.0
+ %b = uitofp nneg i32 -256 to i32 ; yields i32 poison
+
'``sitofp .. to``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 2e2ec9a1c83026..f381273c46cfb8 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2068,11 +2068,17 @@ class IRBuilderBase {
return CreateCast(Instruction::FPToSI, V, DestTy, Name);
}
- Value *CreateUIToFP(Value *V, Type *DestTy, const Twine &Name = ""){
+ Value *CreateUIToFP(Value *V, Type *DestTy, const Twine &Name = "",
+ bool IsNonNeg = false) {
if (IsFPConstrained)
return CreateConstrainedFPCast(Intrinsic::experimental_constrained_uitofp,
V, DestTy, nullptr, Name);
- return CreateCast(Instruction::UIToFP, V, DestTy, Name);
+ if (Value *Folded = Folder.FoldCast(Instruction::UIToFP, V, DestTy))
+ return Folded;
+ Instruction *I = Insert(new UIToFPInst(V, DestTy), Name);
+ if (IsNonNeg)
+ I->setNonNeg();
+ return I;
}
Value *CreateSIToFP(Value *V, Type *DestTy, const Twine &Name = ""){
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index e4e5fa15c399eb..cfe1b11ade5a4e 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -927,13 +927,19 @@ class CastInst : public UnaryInstruction {
}
};
-/// Instruction that can have a nneg flag (only zext).
+/// Instruction that can have a nneg flag (zext/uitofp).
class PossiblyNonNegInst : public CastInst {
public:
enum { NonNeg = (1 << 0) };
static bool classof(const Instruction *I) {
- return I->getOpcode() == Instruction::ZExt;
+ switch (I->getOpcode()) {
+ case Instruction::ZExt:
+ case Instruction::UIToFP:
+ return true;
+ default:
+ return false;
+ }
}
static bool classof(const Value *V) {
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 8609f3d6276ceb..f546e05a5d37d4 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -6816,6 +6816,7 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
}
// Casts.
+ case lltok::kw_uitofp:
case lltok::kw_zext: {
bool NonNeg = EatIfPresent(lltok::kw_nneg);
bool Res = parseCast(Inst, PFS, KeywordVal);
@@ -6843,7 +6844,6 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
case lltok::kw_fpext:
case lltok::kw_bitcast:
case lltok::kw_addrspacecast:
- case lltok::kw_uitofp:
case lltok::kw_sitofp:
case lltok::kw_fptoui:
case lltok::kw_fptosi:
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 5ea6cc2c6b526e..92c349525aff56 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -5039,7 +5039,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
}
if (OpNum < Record.size()) {
- if (Opc == Instruction::ZExt) {
+ if (Opc == Instruction::ZExt || Opc == Instruction::UIToFP) {
if (Record[OpNum] & (1 << bitc::PNNI_NON_NEG))
cast<PossiblyNonNegInst>(I)->setNonNeg(true);
} else if (Opc == Instruction::Trunc) {
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 0602a55b9fe7f3..b9efe9cdcfe310 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -388,7 +388,7 @@ void Instruction::setIsExact(bool b) {
}
void Instruction::setNonNeg(bool b) {
- assert(isa<PossiblyNonNegInst>(this) && "Must be zext");
+ assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
SubclassOptionalData = (SubclassOptionalData & ~PossiblyNonNegInst::NonNeg) |
(b * PossiblyNonNegInst::NonNeg);
}
@@ -408,7 +408,7 @@ bool Instruction::hasNoSignedWrap() const {
}
bool Instruction::hasNonNeg() const {
- assert(isa<PossiblyNonNegInst>(this) && "Must be zext");
+ assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
return (SubclassOptionalData & PossiblyNonNegInst::NonNeg) != 0;
}
@@ -441,6 +441,7 @@ void Instruction::dropPoisonGeneratingFlags() {
cast<GetElementPtrInst>(this)->setIsInBounds(false);
break;
+ case Instruction::UIToFP:
case Instruction::ZExt:
setNonNeg(false);
break;
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index 7b4449cd825f9b..ccc624d854429c 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -44,6 +44,7 @@ bool Operator::hasPoisonGeneratingFlags() const {
// Note: inrange exists on constexpr only
return GEP->isInBounds() || GEP->getInRange() != std::nullopt;
}
+ case Instruction::UIToFP:
case Instruction::ZExt:
if (auto *NNI = dyn_cast<PossiblyNonNegInst>(this))
return NNI->hasNonNeg();
diff --git a/llvm/test/Assembler/flags.ll b/llvm/test/Assembler/flags.ll
index d75b0cb0ea8246..e0ad8bf000be15 100644
--- a/llvm/test/Assembler/flags.ll
+++ b/llvm/test/Assembler/flags.ll
@@ -256,6 +256,13 @@ define i64 @test_zext(i32 %a) {
ret i64 %res
}
+define float @test_uitofp(i32 %a) {
+; CHECK: %res = uitofp nneg i32 %a to float
+ %res = uitofp nneg i32 %a to float
+ ret float %res
+}
+
+
define i64 @test_or(i64 %a, i64 %b) {
; CHECK: %res = or disjoint i64 %a, %b
%res = or disjoint i64 %a, %b
diff --git a/llvm/test/Bitcode/flags.ll b/llvm/test/Bitcode/flags.ll
index 96995ec570c935..fd56694ccceb2c 100644
--- a/llvm/test/Bitcode/flags.ll
+++ b/llvm/test/Bitcode/flags.ll
@@ -18,6 +18,8 @@ second: ; preds = %first
%z = add i32 %a, 0 ; <i32> [#uses=0]
%hh = zext nneg i32 %a to i64
%ll = zext i32 %s to i64
+ %ff = uitofp nneg i32 %a to float
+ %bb = uitofp i32 %s to float
%jj = or disjoint i32 %a, 0
%oo = or i32 %a, 0
%tu = trunc nuw i32 %a to i16
@@ -39,6 +41,8 @@ first: ; preds = %entry
%zz = add i32 %a, 0 ; <i32> [#uses=0]
%kk = zext nneg i32 %a to i64
%rr = zext i32 %ss to i64
+ %ww = uitofp nneg i32 %a to float
+ %xx = uitofp i32 %ss to float
%mm = or disjoint i32 %a, 0
%nn = or i32 %a, 0
%tuu = trunc nuw i32 %a to i16
diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll
index e8105b6287d0c5..668f3033ed4b73 100644
--- a/llvm/test/Transforms/InstCombine/freeze.ll
+++ b/llvm/test/Transforms/InstCombine/freeze.ll
@@ -1127,6 +1127,17 @@ define i32 @freeze_zext_nneg(i8 %x) {
ret i32 %fr
}
+define float @freeze_uitofp_nneg(i8 %x) {
+; CHECK-LABEL: @freeze_uitofp_nneg(
+; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]]
+; CHECK-NEXT: [[UITOFP:%.*]] = uitofp i8 [[X_FR]] to float
+; CHECK-NEXT: ret float [[UITOFP]]
+;
+ %uitofp = uitofp nneg i8 %x to float
+ %fr = freeze float %uitofp
+ ret float %fr
+}
+
define i32 @propagate_drop_flags_or(i32 %arg) {
; CHECK-LABEL: @propagate_drop_flags_or(
; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
diff --git a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
index 4a4c94098ab94c..887d1820168181 100644
--- a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
+++ b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
@@ -125,6 +125,37 @@ F:
ret i32 %z2
}
+
+define float @hoist_uitofp_flags_preserve(i1 %C, i8 %x) {
+; CHECK-LABEL: @hoist_uitofp_flags_preserve(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = uitofp nneg i8 [[X:%.*]] to float
+; CHECK-NEXT: ret float [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = uitofp nneg i8 %x to float
+ ret float %z1
+F:
+ %z2 = uitofp nneg i8 %x to float
+ ret float %z2
+}
+
+define float @hoist_uitofp_flags_drop(i1 %C, i8 %x) {
+; CHECK-LABEL: @hoist_uitofp_flags_drop(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = uitofp i8 [[X:%.*]] to float
+; CHECK-NEXT: ret float [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = uitofp nneg i8 %x to float
+ ret float %z1
+F:
+ %z2 = uitofp i8 %x to float
+ ret float %z2
+}
+
define i32 @hoist_or_flags_preserve(i1 %C, i32 %x, i32 %y) {
; CHECK-LABEL: @hoist_or_flags_preserve(
; CHECK-NEXT: common.ret:
More information about the llvm-commits
mailing list