Skip to content

[CodeGen] Add nneg and disjoint flags #86650

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

Merged
merged 6 commits into from
Mar 26, 2024
Merged
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
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/MachineInstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class MachineInstr
// this instruction.
Unpredictable = 1 << 16, // Instruction with unpredictable condition.
NoConvergent = 1 << 17, // Call does not require convergence guarantees.
NonNeg = 1 << 18, // The operand is non-negative.
Disjoint = 1 << 19, // Each bit is zero in at least one of the inputs.
};

private:
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1562,9 +1562,14 @@ bool IRTranslator::translateCast(unsigned Opcode, const User &U,
if (U.getType()->getScalarType()->isBFloatTy() ||
U.getOperand(0)->getType()->getScalarType()->isBFloatTy())
return false;

uint32_t Flags = 0;
if (const Instruction *I = dyn_cast<Instruction>(&U))
Flags = MachineInstr::copyFlagsFromInstruction(*I);

Register Op = getOrCreateVReg(*U.getOperand(0));
Register Res = getOrCreateVReg(U);
MIRBuilder.buildInstr(Opcode, {Res}, {Op});
MIRBuilder.buildInstr(Opcode, {Res}, {Op}, Flags);
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("nuw", MIToken::kw_nuw)
.Case("nsw", MIToken::kw_nsw)
.Case("exact", MIToken::kw_exact)
.Case("nneg", MIToken::kw_nneg)
.Case("disjoint", MIToken::kw_disjoint)
.Case("nofpexcept", MIToken::kw_nofpexcept)
.Case("unpredictable", MIToken::kw_unpredictable)
.Case("debug-location", MIToken::kw_debug_location)
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct MIToken {
kw_exact,
kw_nofpexcept,
kw_unpredictable,
kw_nneg,
kw_disjoint,
kw_debug_location,
kw_debug_instr_number,
kw_dbg_instr_ref,
Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/CodeGen/MIRParser/MIParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,9 @@ bool MIParser::parseInstruction(unsigned &OpCode, unsigned &Flags) {
Token.is(MIToken::kw_exact) ||
Token.is(MIToken::kw_nofpexcept) ||
Token.is(MIToken::kw_noconvergent) ||
Token.is(MIToken::kw_unpredictable)) {
Token.is(MIToken::kw_unpredictable) ||
Token.is(MIToken::kw_nneg) ||
Token.is(MIToken::kw_disjoint)) {
// clang-format on
// Mine frame and fast math flags
if (Token.is(MIToken::kw_frame_setup))
Expand Down Expand Up @@ -1504,6 +1506,10 @@ bool MIParser::parseInstruction(unsigned &OpCode, unsigned &Flags) {
Flags |= MachineInstr::Unpredictable;
if (Token.is(MIToken::kw_noconvergent))
Flags |= MachineInstr::NoConvergent;
if (Token.is(MIToken::kw_nneg))
Flags |= MachineInstr::NonNeg;
if (Token.is(MIToken::kw_disjoint))
Flags |= MachineInstr::Disjoint;

lex();
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/MIRPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,10 @@ void MIPrinter::print(const MachineInstr &MI) {
OS << "unpredictable ";
if (MI.getFlag(MachineInstr::NoConvergent))
OS << "noconvergent ";
if (MI.getFlag(MachineInstr::NonNeg))
OS << "nneg ";
if (MI.getFlag(MachineInstr::Disjoint))
OS << "disjoint ";

OS << TII->getName(MI.getOpcode());
if (I < E)
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/CodeGen/MachineInstr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,17 @@ uint32_t MachineInstr::copyFlagsFromInstruction(const Instruction &I) {
MIFlags |= MachineInstr::MIFlag::NoUWrap;
}

// Copy the nonneg flag.
if (const PossiblyNonNegInst *PNI = dyn_cast<PossiblyNonNegInst>(&I)) {
if (PNI->hasNonNeg())
MIFlags |= MachineInstr::MIFlag::NonNeg;
// Copy the disjoint flag.
} else if (const PossiblyDisjointInst *PD =
dyn_cast<PossiblyDisjointInst>(&I)) {
if (PD->isDisjoint())
MIFlags |= MachineInstr::MIFlag::Disjoint;
}

// Copy the exact flag.
if (const PossiblyExactOperator *PE = dyn_cast<PossiblyExactOperator>(&I))
if (PE->isExact())
Expand Down Expand Up @@ -1706,6 +1717,10 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
OS << "nofpexcept ";
if (getFlag(MachineInstr::NoMerge))
OS << "nomerge ";
if (getFlag(MachineInstr::NonNeg))
OS << "nneg ";
if (getFlag(MachineInstr::Disjoint))
OS << "disjoint ";

// Print the opcode name.
if (TII)
Expand Down
135 changes: 135 additions & 0 deletions llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-nneg-disjoint.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
; RUN: llc -mtriple=aarch64-linux-gnu -O0 -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s

define i32 @call_nneg(i16 %a) {
; CHECK-LABEL: name: call_nneg
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
; CHECK-NEXT: %2:_(s32) = nneg G_ZEXT [[TRUNC]](s16)
; CHECK-NEXT: $w0 = COPY %2(s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
entry:
%result = zext nneg i16 %a to i32
ret i32 %result
}

define i32 @call_not_nneg(i16 %a) {
; CHECK-LABEL: name: call_not_nneg
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s16)
; CHECK-NEXT: $w0 = COPY [[ZEXT]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
entry:
%result = zext i16 %a to i32
ret i32 %result
}

define i32 @call_disjoint(i32 %a, i32 %b) {
; CHECK-LABEL: name: call_disjoint
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $w0, $w1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
; CHECK-NEXT: %2:_(s32) = disjoint G_OR [[COPY]], [[COPY1]]
; CHECK-NEXT: $w0 = COPY %2(s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
entry:
%result = or disjoint i32 %a, %b
ret i32 %result
}

define i32 @call_add(i32 %a, i32 %b) {
; CHECK-LABEL: name: call_add
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $w0, $w1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s32) = nsw G_ADD [[COPY]], [[COPY1]]
; CHECK-NEXT: $w0 = COPY [[ADD]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
entry:
%result = add nsw i32 %a, %b
ret i32 %result
}

define i32 @call_not_disjoint(i32 %a, i32 %b) {
; CHECK-LABEL: name: call_not_disjoint
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $w0, $w1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
; CHECK-NEXT: [[OR:%[0-9]+]]:_(s32) = G_OR [[COPY]], [[COPY1]]
; CHECK-NEXT: $w0 = COPY [[OR]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
entry:
%result = or i32 %a, %b
ret i32 %result
}

define <2 x i64> @call_not_disjoint_vector(<2 x i64> %a, <2 x i64> %b) {
; CHECK-LABEL: name: call_not_disjoint_vector
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $q0, $q1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<2 x s64>) = COPY $q1
; CHECK-NEXT: [[OR:%[0-9]+]]:_(<2 x s64>) = G_OR [[COPY]], [[COPY1]]
; CHECK-NEXT: $q0 = COPY [[OR]](<2 x s64>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
entry:
%result = or <2 x i64> %a, %b
ret <2 x i64> %result
}

define <2 x i64> @call_disjoint_vector(<2 x i64> %a, <2 x i64> %b) {
; CHECK-LABEL: name: call_disjoint_vector
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $q0, $q1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(<2 x s64>) = COPY $q1
; CHECK-NEXT: %2:_(<2 x s64>) = disjoint G_OR [[COPY]], [[COPY1]]
; CHECK-NEXT: $q0 = COPY %2(<2 x s64>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
entry:
%result = or disjoint <2 x i64> %a, %b
ret <2 x i64> %result
}

define <2 x i64> @call_nneg_vector(<2 x i32> %a) {
; CHECK-LABEL: name: call_nneg_vector
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $d0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s32>) = COPY $d0
; CHECK-NEXT: %1:_(<2 x s64>) = nneg G_ZEXT [[COPY]](<2 x s32>)
; CHECK-NEXT: $q0 = COPY %1(<2 x s64>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
entry:
%result = zext nneg <2 x i32> %a to <2 x i64>
ret <2 x i64> %result
}

define <2 x i64> @call_not_nneg_vector(<2 x i32> %a) {
; CHECK-LABEL: name: call_not_nneg_vector
; CHECK: bb.1.entry:
; CHECK-NEXT: liveins: $d0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s32>) = COPY $d0
; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(<2 x s64>) = G_ZEXT [[COPY]](<2 x s32>)
; CHECK-NEXT: $q0 = COPY [[ZEXT]](<2 x s64>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
entry:
%result = zext <2 x i32> %a to <2 x i64>
ret <2 x i64> %result
}