diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h index fcdd73d8b65fdd..7249f812d2cc4c 100644 --- a/llvm/include/llvm/CodeGen/MachineInstr.h +++ b/llvm/include/llvm/CodeGen/MachineInstr.h @@ -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: diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index ef95ceec18a171..80b3f582592269 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -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(&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; } diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp index 870611248466f5..7bb21655320474 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -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) diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h index 0f344da5218205..6617ec68e94150 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -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, diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp index 691c60d22724f3..95924f0566283b 100644 --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -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)) @@ -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(); } diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index 8efe67a9a72be6..4cf3074ea3ffaf 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -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) diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp index 8102bb971ba66e..717c81f01bc30f 100644 --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -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(&I)) { + if (PNI->hasNonNeg()) + MIFlags |= MachineInstr::MIFlag::NonNeg; + // Copy the disjoint flag. + } else if (const PossiblyDisjointInst *PD = + dyn_cast(&I)) { + if (PD->isDisjoint()) + MIFlags |= MachineInstr::MIFlag::Disjoint; + } + // Copy the exact flag. if (const PossiblyExactOperator *PE = dyn_cast(&I)) if (PE->isExact()) @@ -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) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-nneg-disjoint.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-nneg-disjoint.ll new file mode 100644 index 00000000000000..32c742316b872a --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-nneg-disjoint.ll @@ -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 +}