Skip to content

Commit 156943d

Browse files
committed
[IR][DAG] 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.
1 parent 3fefeaf commit 156943d

File tree

13 files changed

+115
-26
lines changed

13 files changed

+115
-26
lines changed

llvm/docs/LangRef.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11616,6 +11616,10 @@ Overview:
1161611616
The '``uitofp``' instruction regards ``value`` as an unsigned integer
1161711617
and converts that value to the ``ty2`` type.
1161811618

11619+
The ``nneg`` (non-negative) flag, if present, specifies that the
11620+
operand is non-negative. This property may be used by optimization
11621+
passes to later convert the ``uitofp`` into a ``sitofp``.
11622+
1161911623
Arguments:
1162011624
""""""""""
1162111625

@@ -11633,6 +11637,9 @@ integer quantity and converts it to the corresponding floating-point
1163311637
value. If the value cannot be exactly represented, it is rounded using
1163411638
the default rounding mode.
1163511639

11640+
If the ``nneg`` flag is set, and the ``uitofp`` argument is negative,
11641+
the result is a poison value.
11642+
1163611643

1163711644
Example:
1163811645
""""""""
@@ -11642,6 +11649,9 @@ Example:
1164211649
%X = uitofp i32 257 to float ; yields float:257.0
1164311650
%Y = uitofp i8 -1 to double ; yields double:255.0
1164411651

11652+
%a = uitofp nneg i32 256 to i32 ; yields float:257.0
11653+
%b = uitofp nneg i32 -256 to i32 ; yields i32 poison
11654+
1164511655
'``sitofp .. to``' Instruction
1164611656
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1164711657

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3005,6 +3005,12 @@ class TargetLoweringBase {
30053005
return false;
30063006
}
30073007

3008+
/// Return true if sitofp from FromTy to ToTy is cheaper than
3009+
/// uitofp.
3010+
virtual bool isSIToFPCheaperThanUIToFP(EVT FromTy, EVT ToTy) const {
3011+
return false;
3012+
}
3013+
30083014
/// Return true if this constant should be sign extended when promoting to
30093015
/// a larger type.
30103016
virtual bool signExtendConstant(const ConstantInt *C) const { return false; }

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,14 +2009,7 @@ class IRBuilderBase {
20092009

20102010
Value *CreateZExt(Value *V, Type *DestTy, const Twine &Name = "",
20112011
bool IsNonNeg = false) {
2012-
if (V->getType() == DestTy)
2013-
return V;
2014-
if (Value *Folded = Folder.FoldCast(Instruction::ZExt, V, DestTy))
2015-
return Folded;
2016-
Instruction *I = Insert(new ZExtInst(V, DestTy), Name);
2017-
if (IsNonNeg)
2018-
I->setNonNeg();
2019-
return I;
2012+
return CreateCast(Instruction::ZExt, V, DestTy, Name, IsNonNeg);
20202013
}
20212014

20222015
Value *CreateSExt(Value *V, Type *DestTy, const Twine &Name = "") {
@@ -2067,11 +2060,12 @@ class IRBuilderBase {
20672060
return CreateCast(Instruction::FPToSI, V, DestTy, Name);
20682061
}
20692062

2070-
Value *CreateUIToFP(Value *V, Type *DestTy, const Twine &Name = ""){
2063+
Value *CreateUIToFP(Value *V, Type *DestTy, const Twine &Name = "",
2064+
bool IsNonNeg = false) {
20712065
if (IsFPConstrained)
20722066
return CreateConstrainedFPCast(Intrinsic::experimental_constrained_uitofp,
20732067
V, DestTy, nullptr, Name);
2074-
return CreateCast(Instruction::UIToFP, V, DestTy, Name);
2068+
return CreateCast(Instruction::UIToFP, V, DestTy, Name, IsNonNeg);
20752069
}
20762070

20772071
Value *CreateSIToFP(Value *V, Type *DestTy, const Twine &Name = ""){
@@ -2142,12 +2136,17 @@ class IRBuilderBase {
21422136
}
21432137

21442138
Value *CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy,
2145-
const Twine &Name = "") {
2139+
const Twine &Name = "", bool IsNonNeg = false) {
21462140
if (V->getType() == DestTy)
21472141
return V;
21482142
if (Value *Folded = Folder.FoldCast(Op, V, DestTy))
21492143
return Folded;
2150-
return Insert(CastInst::Create(Op, V, DestTy), Name);
2144+
Instruction *I = Insert(CastInst::Create(Op, V, DestTy), Name);
2145+
if (IsNonNeg) {
2146+
assert(isa<PossiblyNonNegInst>(I) && "Invalid use of IsNonNeg");
2147+
I->setNonNeg();
2148+
}
2149+
return I;
21512150
}
21522151

21532152
Value *CreatePointerCast(Value *V, Type *DestTy,

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,13 +933,19 @@ class CastInst : public UnaryInstruction {
933933
}
934934
};
935935

936-
/// Instruction that can have a nneg flag (only zext).
936+
/// Instruction that can have a nneg flag (zext/uitofp).
937937
class PossiblyNonNegInst : public CastInst {
938938
public:
939939
enum { NonNeg = (1 << 0) };
940940

941941
static bool classof(const Instruction *I) {
942-
return I->getOpcode() == Instruction::ZExt;
942+
switch (I->getOpcode()) {
943+
case Instruction::ZExt:
944+
case Instruction::UIToFP:
945+
return true;
946+
default:
947+
return false;
948+
}
943949
}
944950

945951
static bool classof(const Value *V) {

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6801,6 +6801,7 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
68016801
}
68026802

68036803
// Casts.
6804+
case lltok::kw_uitofp:
68046805
case lltok::kw_zext: {
68056806
bool NonNeg = EatIfPresent(lltok::kw_nneg);
68066807
bool Res = parseCast(Inst, PFS, KeywordVal);
@@ -6816,7 +6817,6 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
68166817
case lltok::kw_fpext:
68176818
case lltok::kw_bitcast:
68186819
case lltok::kw_addrspacecast:
6819-
case lltok::kw_uitofp:
68206820
case lltok::kw_sitofp:
68216821
case lltok::kw_fptoui:
68226822
case lltok::kw_fptosi:

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4019,13 +4019,13 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
40194019
}
40204020

40214021
// smax(a,b) - smin(a,b) --> abds(a,b)
4022-
if (hasOperation(ISD::ABDS, VT) &&
4022+
if (hasOperation(ISD::ABDS, VT) &&
40234023
sd_match(N0, m_SMax(m_Value(A), m_Value(B))) &&
40244024
sd_match(N1, m_SMin(m_Specific(A), m_Specific(B))))
40254025
return DAG.getNode(ISD::ABDS, DL, VT, A, B);
40264026

40274027
// umax(a,b) - umin(a,b) --> abdu(a,b)
4028-
if (hasOperation(ISD::ABDU, VT) &&
4028+
if (hasOperation(ISD::ABDU, VT) &&
40294029
sd_match(N0, m_UMax(m_Value(A), m_Value(B))) &&
40304030
sd_match(N1, m_UMin(m_Specific(A), m_Specific(B))))
40314031
return DAG.getNode(ISD::ABDU, DL, VT, A, B);
@@ -17413,12 +17413,16 @@ SDValue DAGCombiner::visitUINT_TO_FP(SDNode *N) {
1741317413
TLI.isOperationLegalOrCustom(ISD::ConstantFP, VT)))
1741417414
return DAG.getNode(ISD::UINT_TO_FP, SDLoc(N), VT, N0);
1741517415

17416-
// If the input is a legal type, and UINT_TO_FP is not legal on this target,
17417-
// but SINT_TO_FP is legal on this target, try to convert.
17418-
if (!hasOperation(ISD::UINT_TO_FP, OpVT) &&
17419-
hasOperation(ISD::SINT_TO_FP, OpVT)) {
17420-
// If the sign bit is known to be zero, we can change this to SINT_TO_FP.
17421-
if (DAG.SignBitIsZero(N0))
17416+
SDNodeFlags Flags = N->getFlags();
17417+
bool NonNeg = Flags.hasNonNeg() || DAG.SignBitIsZero(N0);
17418+
17419+
// If the sign bit is known to be zero, we can change this to SINT_TO_FP.
17420+
if (NonNeg && hasOperation(ISD::SINT_TO_FP, OpVT)) {
17421+
// If the input is a legal type, and UINT_TO_FP is not legal on this target,
17422+
// but SINT_TO_FP is legal on this target, convert it.
17423+
// Or, if the target prefers SINT_TO_FP, convert it.
17424+
if (!hasOperation(ISD::UINT_TO_FP, OpVT) ||
17425+
DAG.getTargetLoweringInfo().isSIToFPCheaperThanUIToFP(VT, OpVT))
1742217426
return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, N0);
1742317427
}
1742417428

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3882,7 +3882,16 @@ void SelectionDAGBuilder::visitUIToFP(const User &I) {
38823882
SDValue N = getValue(I.getOperand(0));
38833883
EVT DestVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
38843884
I.getType());
3885-
setValue(&I, DAG.getNode(ISD::UINT_TO_FP, getCurSDLoc(), DestVT, N));
3885+
SDNodeFlags Flags;
3886+
if (auto *PNI = dyn_cast<PossiblyNonNegInst>(&I))
3887+
Flags.setNonNeg(PNI->hasNonNeg());
3888+
3889+
if (Flags.hasNonNeg() &&
3890+
DAG.getTargetLoweringInfo().isSIToFPCheaperThanUIToFP(N.getValueType(),
3891+
DestVT))
3892+
setValue(&I, DAG.getNode(ISD::SINT_TO_FP, getCurSDLoc(), DestVT, N));
3893+
3894+
setValue(&I, DAG.getNode(ISD::UINT_TO_FP, getCurSDLoc(), DestVT, N, Flags));
38863895
}
38873896

38883897
void SelectionDAGBuilder::visitSIToFP(const User &I) {

llvm/lib/IR/Instruction.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ void Instruction::setIsExact(bool b) {
382382
}
383383

384384
void Instruction::setNonNeg(bool b) {
385-
assert(isa<PossiblyNonNegInst>(this) && "Must be zext");
385+
assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
386386
SubclassOptionalData = (SubclassOptionalData & ~PossiblyNonNegInst::NonNeg) |
387387
(b * PossiblyNonNegInst::NonNeg);
388388
}
@@ -396,7 +396,7 @@ bool Instruction::hasNoSignedWrap() const {
396396
}
397397

398398
bool Instruction::hasNonNeg() const {
399-
assert(isa<PossiblyNonNegInst>(this) && "Must be zext");
399+
assert(isa<PossiblyNonNegInst>(this) && "Must be zext/uitofp");
400400
return (SubclassOptionalData & PossiblyNonNegInst::NonNeg) != 0;
401401
}
402402

@@ -429,6 +429,7 @@ void Instruction::dropPoisonGeneratingFlags() {
429429
cast<GetElementPtrInst>(this)->setIsInBounds(false);
430430
break;
431431

432+
case Instruction::UIToFP:
432433
case Instruction::ZExt:
433434
setNonNeg(false);
434435
break;

llvm/lib/IR/Operator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ bool Operator::hasPoisonGeneratingFlags() const {
3939
// Note: inrange exists on constexpr only
4040
return GEP->isInBounds() || GEP->getInRange() != std::nullopt;
4141
}
42+
case Instruction::UIToFP:
4243
case Instruction::ZExt:
4344
if (auto *NNI = dyn_cast<PossiblyNonNegInst>(this))
4445
return NNI->hasNonNeg();

llvm/test/Assembler/flags.ll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ define i64 @test_zext(i32 %a) {
256256
ret i64 %res
257257
}
258258

259+
define float @test_uitofp(i32 %a) {
260+
; CHECK: %res = uitofp nneg i32 %a to float
261+
%res = uitofp nneg i32 %a to float
262+
ret float %res
263+
}
264+
265+
259266
define i64 @test_or(i64 %a, i64 %b) {
260267
; CHECK: %res = or disjoint i64 %a, %b
261268
%res = or disjoint i64 %a, %b

llvm/test/Bitcode/flags.ll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ second: ; preds = %first
1818
%z = add i32 %a, 0 ; <i32> [#uses=0]
1919
%hh = zext nneg i32 %a to i64
2020
%ll = zext i32 %s to i64
21+
%ff = uitofp nneg i32 %a to float
22+
%bb = uitofp i32 %s to float
2123
%jj = or disjoint i32 %a, 0
2224
%oo = or i32 %a, 0
2325
unreachable
@@ -30,6 +32,8 @@ first: ; preds = %entry
3032
%zz = add i32 %a, 0 ; <i32> [#uses=0]
3133
%kk = zext nneg i32 %a to i64
3234
%rr = zext i32 %ss to i64
35+
%ww = uitofp nneg i32 %a to float
36+
%xx = uitofp i32 %ss to float
3337
%mm = or disjoint i32 %a, 0
3438
%nn = or i32 %a, 0
3539
br label %second

llvm/test/Transforms/InstCombine/freeze.ll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,17 @@ define i32 @freeze_zext_nneg(i8 %x) {
11271127
ret i32 %fr
11281128
}
11291129

1130+
define float @freeze_uitofp_nneg(i8 %x) {
1131+
; CHECK-LABEL: @freeze_uitofp_nneg(
1132+
; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]]
1133+
; CHECK-NEXT: [[UITOFP:%.*]] = uitofp i8 [[X_FR]] to float
1134+
; CHECK-NEXT: ret float [[UITOFP]]
1135+
;
1136+
%uitofp = uitofp nneg i8 %x to float
1137+
%fr = freeze float %uitofp
1138+
ret float %fr
1139+
}
1140+
11301141
define i32 @propagate_drop_flags_or(i32 %arg) {
11311142
; CHECK-LABEL: @propagate_drop_flags_or(
11321143
; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]

llvm/test/Transforms/SimplifyCFG/HoistCode.ll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,37 @@ F:
125125
ret i32 %z2
126126
}
127127

128+
129+
define float @hoist_uitofp_flags_preserve(i1 %C, i8 %x) {
130+
; CHECK-LABEL: @hoist_uitofp_flags_preserve(
131+
; CHECK-NEXT: common.ret:
132+
; CHECK-NEXT: [[Z1:%.*]] = uitofp nneg i8 [[X:%.*]] to float
133+
; CHECK-NEXT: ret float [[Z1]]
134+
;
135+
br i1 %C, label %T, label %F
136+
T:
137+
%z1 = uitofp nneg i8 %x to float
138+
ret float %z1
139+
F:
140+
%z2 = uitofp nneg i8 %x to float
141+
ret float %z2
142+
}
143+
144+
define float @hoist_uitofp_flags_drop(i1 %C, i8 %x) {
145+
; CHECK-LABEL: @hoist_uitofp_flags_drop(
146+
; CHECK-NEXT: common.ret:
147+
; CHECK-NEXT: [[Z1:%.*]] = uitofp i8 [[X:%.*]] to float
148+
; CHECK-NEXT: ret float [[Z1]]
149+
;
150+
br i1 %C, label %T, label %F
151+
T:
152+
%z1 = uitofp nneg i8 %x to float
153+
ret float %z1
154+
F:
155+
%z2 = uitofp i8 %x to float
156+
ret float %z2
157+
}
158+
128159
define i32 @hoist_or_flags_preserve(i1 %C, i32 %x, i32 %y) {
129160
; CHECK-LABEL: @hoist_or_flags_preserve(
130161
; CHECK-NEXT: common.ret:

0 commit comments

Comments
 (0)