[llvm] [CodeGen][NFC] Add laneBitmask as new MachineOperand type, utilised by newly defined COPY_LANEMASK instruction (PR #151944)
Vikash Gupta via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 6 04:37:55 PDT 2025
https://github.com/vg0204 updated https://github.com/llvm/llvm-project/pull/151944
>From 4c7f52d999740d2499ccf3270f984ddb09292d34 Mon Sep 17 00:00:00 2001
From: vikashgu <Vikash.Gupta at amd.com>
Date: Mon, 4 Aug 2025 11:04:28 +0000
Subject: [PATCH 1/2] [CodeGen][NFC] Add laneBitmask as new MachineOperand Type
This patch adds a new MachineOperand type to represent the
laneBitmask as MO_LaneMask that can be used in the instructions
to represent the relevant information associated with the register
operands of the same such as liveness.
---
llvm/docs/MIRLangRef.rst | 1 +
.../llvm/CodeGen/MachineInstrBuilder.h | 5 ++++
llvm/include/llvm/CodeGen/MachineOperand.h | 17 ++++++++++-
llvm/lib/CodeGen/MIRParser/MILexer.cpp | 1 +
llvm/lib/CodeGen/MIRParser/MILexer.h | 1 +
llvm/lib/CodeGen/MIRParser/MIParser.cpp | 29 +++++++++++++++++++
llvm/lib/CodeGen/MIRPrinter.cpp | 3 +-
llvm/lib/CodeGen/MIRVRegNamerUtils.cpp | 1 +
llvm/lib/CodeGen/MachineOperand.cpp | 19 ++++++++++--
llvm/lib/CodeGen/MachineStableHash.cpp | 4 +++
llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp | 1 +
llvm/unittests/CodeGen/MachineOperandTest.cpp | 17 +++++++++++
12 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/llvm/docs/MIRLangRef.rst b/llvm/docs/MIRLangRef.rst
index a505c1ea4b0aa..4e12239e0e68f 100644
--- a/llvm/docs/MIRLangRef.rst
+++ b/llvm/docs/MIRLangRef.rst
@@ -819,6 +819,7 @@ For an int eq predicate ``ICMP_EQ``, the syntax is:
.. TODO: Describe the syntax of the metadata machine operands, and the
instructions debug location attribute.
.. TODO: Describe the syntax of the register live out machine operands.
+.. TODO: Describe the syntax of the lanemask machine operands.
.. TODO: Describe the syntax of the machine memory operands.
Comments
diff --git a/llvm/include/llvm/CodeGen/MachineInstrBuilder.h b/llvm/include/llvm/CodeGen/MachineInstrBuilder.h
index e705d7d99544c..a07fea19a4785 100644
--- a/llvm/include/llvm/CodeGen/MachineInstrBuilder.h
+++ b/llvm/include/llvm/CodeGen/MachineInstrBuilder.h
@@ -292,6 +292,11 @@ class MachineInstrBuilder {
return *this;
}
+ const MachineInstrBuilder &addLaneMask(LaneBitmask LaneMask) const {
+ MI->addOperand(*MF, MachineOperand::CreateLaneMask(LaneMask));
+ return *this;
+ }
+
const MachineInstrBuilder &addSym(MCSymbol *Sym,
unsigned char TargetFlags = 0) const {
MI->addOperand(*MF, MachineOperand::CreateMCSymbol(Sym, TargetFlags));
diff --git a/llvm/include/llvm/CodeGen/MachineOperand.h b/llvm/include/llvm/CodeGen/MachineOperand.h
index 646588a2a92a5..0fd999364234b 100644
--- a/llvm/include/llvm/CodeGen/MachineOperand.h
+++ b/llvm/include/llvm/CodeGen/MachineOperand.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/MC/LaneBitmask.h"
#include "llvm/Support/Compiler.h"
#include <cassert>
@@ -69,7 +70,8 @@ class MachineOperand {
MO_Predicate, ///< Generic predicate for ISel
MO_ShuffleMask, ///< Other IR Constant for ISel (shuffle masks)
MO_DbgInstrRef, ///< Integer indices referring to an instruction+operand
- MO_Last = MO_DbgInstrRef
+ MO_LaneMask, ///< Mask to represent active parts of registers
+ MO_Last = MO_LaneMask
};
private:
@@ -178,6 +180,7 @@ class MachineOperand {
Intrinsic::ID IntrinsicID; // For MO_IntrinsicID.
unsigned Pred; // For MO_Predicate
ArrayRef<int> ShuffleMask; // For MO_ShuffleMask
+ LaneBitmask LaneMask; // For MO_LaneMask
struct { // For MO_Register.
// Register number is in SmallContents.RegNo.
@@ -360,6 +363,7 @@ class MachineOperand {
bool isIntrinsicID() const { return OpKind == MO_IntrinsicID; }
bool isPredicate() const { return OpKind == MO_Predicate; }
bool isShuffleMask() const { return OpKind == MO_ShuffleMask; }
+ bool isLaneMask() const { return OpKind == MO_LaneMask; }
//===--------------------------------------------------------------------===//
// Accessors for Register Operands
//===--------------------------------------------------------------------===//
@@ -624,6 +628,11 @@ class MachineOperand {
return Contents.ShuffleMask;
}
+ LaneBitmask getLaneMask() const {
+ assert(isLaneMask() && "Wrong MachineOperand accessor");
+ return Contents.LaneMask;
+ }
+
/// Return the offset from the symbol in this operand. This always returns 0
/// for ExternalSymbol operands.
int64_t getOffset() const {
@@ -989,6 +998,12 @@ class MachineOperand {
return Op;
}
+ static MachineOperand CreateLaneMask(LaneBitmask LaneMask) {
+ MachineOperand Op(MachineOperand::MO_LaneMask);
+ Op.Contents.LaneMask = LaneMask;
+ return Op;
+ }
+
friend class MachineInstr;
friend class MachineRegisterInfo;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 8b72c295416a2..bb714653d79dc 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -266,6 +266,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("constant-pool", MIToken::kw_constant_pool)
.Case("call-entry", MIToken::kw_call_entry)
.Case("custom", MIToken::kw_custom)
+ .Case("lanemask", MIToken::kw_lanemask)
.Case("liveout", MIToken::kw_liveout)
.Case("landing-pad", MIToken::kw_landing_pad)
.Case("inlineasm-br-indirect-target",
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 0627f176b9e00..8c4fb0e63895a 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -122,6 +122,7 @@ struct MIToken {
kw_constant_pool,
kw_call_entry,
kw_custom,
+ kw_lanemask,
kw_liveout,
kw_landing_pad,
kw_inlineasm_br_indirect_target,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 6a464d9dd6886..c09734ab8f87c 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -496,6 +496,7 @@ class MIParser {
bool parseTargetIndexOperand(MachineOperand &Dest);
bool parseDbgInstrRefOperand(MachineOperand &Dest);
bool parseCustomRegisterMaskOperand(MachineOperand &Dest);
+ bool parseLaneMaskOperand(MachineOperand &Dest);
bool parseLiveoutRegisterMaskOperand(MachineOperand &Dest);
bool parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
MachineOperand &Dest,
@@ -2870,6 +2871,32 @@ bool MIParser::parseCustomRegisterMaskOperand(MachineOperand &Dest) {
return false;
}
+bool MIParser::parseLaneMaskOperand(MachineOperand &Dest) {
+ assert(Token.is(MIToken::kw_lanemask));
+
+ lex();
+ if (expectAndConsume(MIToken::lparen))
+ return error("expected syntax lanemask(...)");
+
+ LaneBitmask LaneMask = LaneBitmask::getAll();
+ // Parse lanemask.
+ if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral))
+ return error("expected a lane mask");
+ static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t),
+ "Use correct get-function for lane mask");
+ LaneBitmask::Type V;
+ if (getUint64(V))
+ return error("invalid lanemask value");
+ LaneMask = LaneBitmask(V);
+ lex();
+
+ if (expectAndConsume(MIToken::rparen))
+ return error("lanemask should be terminated by ')'.");
+
+ Dest = MachineOperand::CreateLaneMask(LaneMask);
+ return false;
+}
+
bool MIParser::parseLiveoutRegisterMaskOperand(MachineOperand &Dest) {
assert(Token.is(MIToken::kw_liveout));
uint32_t *Mask = MF.allocateRegMask();
@@ -2970,6 +2997,8 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
return parseIntrinsicOperand(Dest);
case MIToken::kw_target_index:
return parseTargetIndexOperand(Dest);
+ case MIToken::kw_lanemask:
+ return parseLaneMaskOperand(Dest);
case MIToken::kw_liveout:
return parseLiveoutRegisterMaskOperand(Dest);
case MIToken::kw_floatpred:
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index ce1834a90ca54..3945acbb505fe 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -928,7 +928,8 @@ static void printMIOperand(raw_ostream &OS, MFPrintState &State,
case MachineOperand::MO_Predicate:
case MachineOperand::MO_BlockAddress:
case MachineOperand::MO_DbgInstrRef:
- case MachineOperand::MO_ShuffleMask: {
+ case MachineOperand::MO_ShuffleMask:
+ case MachineOperand::MO_LaneMask: {
unsigned TiedOperandIdx = 0;
if (ShouldPrintRegisterTies && Op.isReg() && Op.isTied() && !Op.isDef())
TiedOperandIdx = Op.getParent()->findTiedOperandIdx(OpIdx);
diff --git a/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp b/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp
index a22cc91b90542..0afb53e1d8f2c 100644
--- a/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp
+++ b/llvm/lib/CodeGen/MIRVRegNamerUtils.cpp
@@ -106,6 +106,7 @@ std::string VRegRenamer::getInstructionOpcodeHash(MachineInstr &MI) {
case MachineOperand::MO_ExternalSymbol:
case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_BlockAddress:
+ case MachineOperand::MO_LaneMask:
case MachineOperand::MO_RegisterMask:
case MachineOperand::MO_RegisterLiveOut:
case MachineOperand::MO_Metadata:
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index c612f8de7b50b..4d1ce8894e0d0 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -380,6 +380,8 @@ bool MachineOperand::isIdenticalTo(const MachineOperand &Other) const {
return getPredicate() == Other.getPredicate();
case MachineOperand::MO_ShuffleMask:
return getShuffleMask() == Other.getShuffleMask();
+ case MachineOperand::MO_LaneMask:
+ return getLaneMask() == Other.getLaneMask();
}
llvm_unreachable("Invalid machine operand type");
}
@@ -445,6 +447,9 @@ hash_code llvm::hash_value(const MachineOperand &MO) {
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getPredicate());
case MachineOperand::MO_ShuffleMask:
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getShuffleMask());
+ case MachineOperand::MO_LaneMask:
+ return hash_combine(MO.getType(), MO.getTargetFlags(),
+ MO.getLaneMask().getAsInteger());
}
llvm_unreachable("Invalid machine operand type");
}
@@ -1004,11 +1009,11 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
}
case MachineOperand::MO_Predicate: {
auto Pred = static_cast<CmpInst::Predicate>(getPredicate());
- OS << (CmpInst::isIntPredicate(Pred) ? "int" : "float") << "pred("
- << Pred << ')';
+ OS << (CmpInst::isIntPredicate(Pred) ? "int" : "float") << "pred(" << Pred
+ << ')';
break;
}
- case MachineOperand::MO_ShuffleMask:
+ case MachineOperand::MO_ShuffleMask: {
OS << "shufflemask(";
ArrayRef<int> Mask = getShuffleMask();
StringRef Separator;
@@ -1023,6 +1028,14 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
OS << ')';
break;
}
+ case MachineOperand::MO_LaneMask: {
+ OS << "lanemask(";
+ LaneBitmask LaneMask = getLaneMask();
+ OS << "0x" << PrintLaneMask(LaneMask);
+ OS << ')';
+ break;
+ }
+ }
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
diff --git a/llvm/lib/CodeGen/MachineStableHash.cpp b/llvm/lib/CodeGen/MachineStableHash.cpp
index 9d56696079478..70e66e712b8f1 100644
--- a/llvm/lib/CodeGen/MachineStableHash.cpp
+++ b/llvm/lib/CodeGen/MachineStableHash.cpp
@@ -164,6 +164,10 @@ stable_hash llvm::stableHashValue(const MachineOperand &MO) {
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
stable_hash_name(SymbolName));
}
+ case MachineOperand::MO_LaneMask: {
+ return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
+ MO.getLaneMask().getAsInteger());
+ }
case MachineOperand::MO_CFIIndex:
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
MO.getCFIIndex());
diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index 57141ab69223f..0dc54b4f4aad1 100644
--- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -930,6 +930,7 @@ static bool IsAnAddressOperand(const MachineOperand &MO) {
return true;
case MachineOperand::MO_RegisterMask:
case MachineOperand::MO_RegisterLiveOut:
+ case MachineOperand::MO_LaneMask:
return false;
case MachineOperand::MO_Metadata:
case MachineOperand::MO_MCSymbol:
diff --git a/llvm/unittests/CodeGen/MachineOperandTest.cpp b/llvm/unittests/CodeGen/MachineOperandTest.cpp
index 3f3f48fcc7c58..dcd731e5cb896 100644
--- a/llvm/unittests/CodeGen/MachineOperandTest.cpp
+++ b/llvm/unittests/CodeGen/MachineOperandTest.cpp
@@ -288,6 +288,23 @@ TEST(MachineOperandTest, PrintGlobalAddress) {
}
}
+TEST(MachineOperandTest, PrintLaneMask) {
+ // Create a MachineOperand with a lanemask and print it.
+ LaneBitmask LaneMask = LaneBitmask(12);
+ MachineOperand MO = MachineOperand::CreateLaneMask(LaneMask);
+
+ // Checking some preconditions on the newly created
+ // MachineOperand.
+ ASSERT_TRUE(MO.isLaneMask());
+ ASSERT_TRUE(MO.getLaneMask() == LaneMask);
+
+ std::string str;
+ // Print a MachineOperand that is lanemask as in HEX representation.
+ raw_string_ostream OS(str);
+ MO.print(OS, /*TRI=*/nullptr);
+ ASSERT_TRUE(str == "lanemask(0x000000000000000C)");
+}
+
TEST(MachineOperandTest, PrintRegisterLiveOut) {
// Create a MachineOperand with a register live out list and print it.
uint32_t Mask = 0;
>From 98ee227ae4bbc54914901832efcf6c995621d3bb Mon Sep 17 00:00:00 2001
From: vikashgu <Vikash.Gupta at amd.com>
Date: Wed, 6 Aug 2025 11:15:38 +0000
Subject: [PATCH 2/2] [CodeGen]Added support for COPY_LANEMASK instruction
This new instruction takes laneMask as an operand with
respect to the input operand storing the essential information.
---
llvm/include/llvm/CodeGen/MachineInstr.h | 4 ++-
llvm/include/llvm/Support/TargetOpcodes.def | 5 ++++
llvm/include/llvm/Target/Target.td | 7 +++++
llvm/lib/CodeGen/MIRParser/MIParser.cpp | 6 ++--
llvm/lib/CodeGen/MachineVerifier.cpp | 28 +++++++++++++++++++
.../parse-lanemask-operand-invalid-0.mir | 13 +++++++++
.../parse-lanemask-operand-invalid-1.mir | 13 +++++++++
.../parse-lanemask-operand-invalid-2.mir | 13 +++++++++
.../MIR/AMDGPU/parse-lanemask-operand.mir | 17 +++++++++++
.../verifier-copyLanemask0.mir | 24 ++++++++++++++++
.../verifier-copyLanemask1.mir | 28 +++++++++++++++++++
11 files changed, 154 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-0.mir
create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-1.mir
create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-2.mir
create mode 100644 llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand.mir
create mode 100644 llvm/test/MachineVerifier/verifier-copyLanemask0.mir
create mode 100644 llvm/test/MachineVerifier/verifier-copyLanemask1.mir
diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h
index 10a9b1ff1411d..afbb3ae4d33d7 100644
--- a/llvm/include/llvm/CodeGen/MachineInstr.h
+++ b/llvm/include/llvm/CodeGen/MachineInstr.h
@@ -1429,7 +1429,8 @@ class MachineInstr
}
bool isCopy() const {
- return getOpcode() == TargetOpcode::COPY;
+ return (getOpcode() == TargetOpcode::COPY ||
+ getOpcode() == TargetOpcode::COPY_LANEMASK);
}
bool isFullCopy() const {
@@ -1465,6 +1466,7 @@ class MachineInstr
case TargetOpcode::PHI:
case TargetOpcode::G_PHI:
case TargetOpcode::COPY:
+ case TargetOpcode::COPY_LANEMASK:
case TargetOpcode::INSERT_SUBREG:
case TargetOpcode::SUBREG_TO_REG:
case TargetOpcode::REG_SEQUENCE:
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index b905576b61791..570ed3ec30491 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -114,6 +114,11 @@ HANDLE_TARGET_OPCODE(REG_SEQUENCE)
/// used to copy between subregisters of virtual registers.
HANDLE_TARGET_OPCODE(COPY)
+/// COPY_LANEMASK - Target-independent register copy for active mask in
+/// register as represented by the lanemask. This instruction can only be
+/// used to copy between physical registers.
+HANDLE_TARGET_OPCODE(COPY_LANEMASK)
+
/// BUNDLE - This instruction represents an instruction bundle. Instructions
/// which immediately follow a BUNDLE instruction which are marked with
/// 'InsideBundle' flag are inside the bundle.
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 4c83f8a580aa0..0b7a6ee81c29f 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1329,6 +1329,13 @@ def COPY : StandardPseudoInstruction {
let isAsCheapAsAMove = true;
let hasNoSchedulingInfo = false;
}
+def COPY_LANEMASK : StandardPseudoInstruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$src, unknown:$lanemask);
+ let AsmString = "";
+ let hasSideEffects = false;
+ let isAsCheapAsAMove = true;
+}
def BUNDLE : StandardPseudoInstruction {
let OutOperandList = (outs);
let InOperandList = (ins variable_ops);
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index c09734ab8f87c..6a42c924d161f 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2876,14 +2876,14 @@ bool MIParser::parseLaneMaskOperand(MachineOperand &Dest) {
lex();
if (expectAndConsume(MIToken::lparen))
- return error("expected syntax lanemask(...)");
+ return error("lanemask should begin with '('.");
LaneBitmask LaneMask = LaneBitmask::getAll();
// Parse lanemask.
if (Token.isNot(MIToken::IntegerLiteral) && Token.isNot(MIToken::HexLiteral))
- return error("expected a lane mask");
+ return error("expected a valid lane mask value.");
static_assert(sizeof(LaneBitmask::Type) == sizeof(uint64_t),
- "Use correct get-function for lane mask");
+ "Use correct get-function for lane mask.");
LaneBitmask::Type V;
if (getUint64(V))
return error("invalid lanemask value");
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 01703fe09b79a..3f7d361f09647 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2414,6 +2414,34 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
}
break;
}
+ case TargetOpcode::COPY_LANEMASK: {
+ const MachineOperand &DstOp = MI->getOperand(0);
+ const MachineOperand &SrcOp = MI->getOperand(1);
+ const MachineOperand &LaneMaskOp = MI->getOperand(2);
+ const Register SrcReg = SrcOp.getReg();
+ const Register DstReg = DstOp.getReg();
+ const LaneBitmask LaneMask = LaneMaskOp.getLaneMask();
+
+ if (!SrcReg.isPhysical() || !DstReg.isPhysical()) {
+ if (!SrcReg.isPhysical()) {
+ report("Copy with lanemask Instruction uses virtual register", &SrcOp,
+ 1);
+ }
+ if (!DstReg.isPhysical()) {
+ report("Copy with lanemask Instruction uses virtual register", &DstOp,
+ 0);
+ }
+ break;
+ }
+
+ if (LaneMask.none())
+ report("Lanemask takes up the zero value", MI);
+
+ if (LaneMask.all())
+ report("Copy Instruction can be used instead of copy with lanemask", MI);
+
+ break;
+ }
case TargetOpcode::STATEPOINT: {
StatepointOpers SO(MI);
if (!MI->getOperand(SO.getIDPos()).isImm() ||
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-0.mir b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-0.mir
new file mode 100644
index 0000000000000..5bb397e8bcd08
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-0.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s
+
+---
+name: test_missing_rparen
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK: [[@LINE+1]]:47: lanemask should be terminated by ')'.
+ $vgpr1 = COPY_LANEMASK $vgpr0, lanemask(16
+ S_ENDPGM 0
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-1.mir b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-1.mir
new file mode 100644
index 0000000000000..bb4ca36e29511
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-1.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s
+
+---
+name: test_missing_lparen
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK: [[@LINE+1]]:45: lanemask should begin with '('.
+ $vgpr1 = COPY_LANEMASK $vgpr0, lanemask 14)
+ S_ENDPGM 0
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-2.mir b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-2.mir
new file mode 100644
index 0000000000000..fe520056f475c
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand-invalid-2.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s
+
+---
+name: test_wrong_lanemask_type
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ ; CHECK: [[@LINE+1]]:45: expected a valid lane mask value.
+ $vgpr1 = COPY_LANEMASK $vgpr0, lanemask(undef)
+ S_ENDPGM 0
+...
diff --git a/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand.mir b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand.mir
new file mode 100644
index 0000000000000..92c58826a5031
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/parse-lanemask-operand.mir
@@ -0,0 +1,17 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs -o - %s | FileCheck %s
+
+# This test checks for the correctness of the MIR parser for lanemask
+
+# CHECK-LABEL: name: test_lanemask_operand
+# CHECK: COPY_LANEMASK $vgpr0, lanemask(0x0000000000000020)
+---
+name: test_lanemask_operand
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0
+
+ $vgpr1 = COPY_LANEMASK $vgpr0, lanemask(32)
+ S_ENDPGM 0
+...
+
diff --git a/llvm/test/MachineVerifier/verifier-copyLanemask0.mir b/llvm/test/MachineVerifier/verifier-copyLanemask0.mir
new file mode 100644
index 0000000000000..88d368c98ba32
--- /dev/null
+++ b/llvm/test/MachineVerifier/verifier-copyLanemask0.mir
@@ -0,0 +1,24 @@
+# RUN: not --crash llc -o - -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: amdgpu-registered-target
+
+# CHECK: *** Bad machine code: Lanemask takes up the zero value ***
+# CHECK-NEXT: - function: test_copy_lanemask_instruction_0
+# CHECK-NEXT: - basic block: %bb.0
+# CHECK-NEXT: - instruction: $vgpr2 = COPY_LANEMASK $vgpr0, lanemask(0x0000000000000000)
+
+# CHECK: *** Bad machine code: Copy Instruction can be used instead of copy with lanemask ***
+# CHECK-NEXT: - function: test_copy_lanemask_instruction_0
+# CHECK-NEXT: - basic block: %bb.0
+# CHECK-NEXT: - instruction: $vgpr3 = COPY_LANEMASK $vgpr1, lanemask(0xFFFFFFFFFFFFFFFF)
+
+---
+name: test_copy_lanemask_instruction_0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+
+ $vgpr2 = COPY_LANEMASK $vgpr0, lanemask(0)
+ $vgpr3 = COPY_LANEMASK $vgpr1, lanemask(0xFFFFFFFFFFFFFFFF)
+ S_ENDPGM 0
+...
diff --git a/llvm/test/MachineVerifier/verifier-copyLanemask1.mir b/llvm/test/MachineVerifier/verifier-copyLanemask1.mir
new file mode 100644
index 0000000000000..b4386dcae7760
--- /dev/null
+++ b/llvm/test/MachineVerifier/verifier-copyLanemask1.mir
@@ -0,0 +1,28 @@
+# RUN: not --crash llc -o - -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
+# REQUIRES: amdgpu-registered-target
+
+# CHECK: *** Bad machine code: Copy with lanemask Instruction uses virtual register ***
+# CHECK-NEXT: - function: test_copy_lanemask_instruction_1
+# CHECK-NEXT: - basic block: %bb.0
+# CHECK-NEXT: - instruction: $vgpr2 = COPY_LANEMASK %0:vgpr_32, lanemask(0x0000000000000018)
+# CHECK-NEXT: - operand 1: %0:vgpr_32
+
+# CHECK: *** Bad machine code: Copy with lanemask Instruction uses virtual register ***
+# CHECK-NEXT: - function: test_copy_lanemask_instruction_1
+# CHECK-NEXT: - basic block: %bb.0
+# CHECK-NEXT: - instruction: %1:vgpr_32 = COPY_LANEMASK $vgpr1, lanemask(0x00000000000000FF)
+# CHECK-NEXT: - operand 0: %1:vgpr_32
+
+---
+name: test_copy_lanemask_instruction_1
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+
+ %0:vgpr_32 = COPY $vgpr0
+ $vgpr2 = COPY_LANEMASK %0, lanemask(24)
+ %1:vgpr_32 = COPY_LANEMASK $vgpr1, lanemask(0x000000000000FF)
+ S_ENDPGM 0
+...
+
More information about the llvm-commits
mailing list