Skip to content

[IR] Add support for nneg flag with uitofp #86141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
""""""""""

Expand All @@ -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:
""""""""
Expand All @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
10 changes: 8 additions & 2 deletions llvm/include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""){
Expand Down
10 changes: 8 additions & 2 deletions llvm/include/llvm/IR/InstrTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/IR/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -441,6 +441,7 @@ void Instruction::dropPoisonGeneratingFlags() {
cast<GetElementPtrInst>(this)->setIsInBounds(false);
break;

case Instruction::UIToFP:
case Instruction::ZExt:
setNonNeg(false);
break;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/Operator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Assembler/flags.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Bitcode/flags.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
11 changes: 11 additions & 0 deletions llvm/test/Transforms/InstCombine/freeze.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:%.*]]
Expand Down
31 changes: 31 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/HoistCode.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down