Skip to content

[GlobalISel] Introduce G_POISON #127825

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

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 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
9 changes: 9 additions & 0 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ An undefined value.

%0:_(s32) = G_IMPLICIT_DEF

G_POISON
^^^^^^^^

A poison value.

.. code-block:: none

%0:_(s32) = G_POISON

G_CONSTANT
^^^^^^^^^^

Expand Down
17 changes: 17 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,16 +432,27 @@ class CombinerHelper {
/// G_IMPLICIT_DEF.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI) const;

/// Return true if any explicit use operand on \p MI is defined by a
/// G_POISON.
bool matchAnyExplicitUseIsPoison(MachineInstr &MI) const;

/// Return true if all register explicit use operands on \p MI are defined by
/// a G_IMPLICIT_DEF.
bool matchAllExplicitUsesAreUndef(MachineInstr &MI) const;

/// Return true if all register explicit use operands on \p MI are defined by
/// a G_POISON.
bool matchAllExplicitUsesArePoison(MachineInstr &MI) const;

/// Return true if a G_SHUFFLE_VECTOR instruction \p MI has an undef mask.
bool matchUndefShuffleVectorMask(MachineInstr &MI) const;

/// Return true if a G_STORE instruction \p MI is storing an undef value.
bool matchUndefStore(MachineInstr &MI) const;

/// Return true if a G_STORE instruction \p MI is storing a poison value.
bool matchPoisonStore(MachineInstr &MI) const;

/// Return true if a G_SELECT instruction \p MI has an undef comparison.
bool matchUndefSelectCmp(MachineInstr &MI) const;

Expand All @@ -467,6 +478,9 @@ class CombinerHelper {
/// Replace an instruction with a G_IMPLICIT_DEF.
void replaceInstWithUndef(MachineInstr &MI) const;

/// Replace an instruction with a G_POISON.
void replaceInstWithPoison(MachineInstr &MI) const;

/// Delete \p MI and replace all of its uses with its \p OpIdx-th operand.
void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) const;

Expand Down Expand Up @@ -507,6 +521,9 @@ class CombinerHelper {
/// Check if operand \p OpIdx is undef.
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx) const;

/// Check if operand \p OpIdx is poison.
bool matchOperandIsPoison(MachineInstr &MI, unsigned OpIdx) const;

/// Check if operand \p OpIdx is known to be a power of 2.
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI,
unsigned OpIdx) const;
Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,14 @@ class GImplicitDef : public GenericMachineInstr {
}
};

/// Represents a G_POISON.
class GPoison : public GenericMachineInstr {
public:
static bool classof(const MachineInstr *MI) {
return MI->getOpcode() == TargetOpcode::G_POISON;
}
};

/// Represents a G_SELECT.
class GSelect : public GenericMachineInstr {
public:
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1017,9 +1017,12 @@ class MachineIRBuilder {
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildExtract(const DstOp &Res, const SrcOp &Src, uint64_t Index);

/// Build and insert \p Res = IMPLICIT_DEF.
/// Build and insert \p Res = G_IMPLICIT_DEF.
MachineInstrBuilder buildUndef(const DstOp &Res);

/// Build and insert \p Res = G_POISON.
MachineInstrBuilder buildPoison(const DstOp &Res);

/// Build and insert \p Res = G_MERGE_VALUES \p Op0, ...
///
/// G_MERGE_VALUES combines the input elements contiguously into a larger
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,12 @@ HANDLE_TARGET_OPCODE(G_ABDS)
/// Generic absolute difference unsigned instruction.
HANDLE_TARGET_OPCODE(G_ABDU)


// Generic implicit definition.
HANDLE_TARGET_OPCODE(G_IMPLICIT_DEF)

// Generic poison value.
HANDLE_TARGET_OPCODE(G_POISON)

/// Generic PHI instruction with types.
HANDLE_TARGET_OPCODE(G_PHI)

Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ def G_IMPLICIT_DEF : GenericInstruction {
let hasSideEffects = false;
}

def G_POISON : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins);
let hasSideEffects = false;
}

def G_PHI : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins variable_ops);
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ bool CSEConfigFull::shouldCSEOpc(unsigned Opc) {
case TargetOpcode::G_CONSTANT:
case TargetOpcode::G_FCONSTANT:
case TargetOpcode::G_IMPLICIT_DEF:
case TargetOpcode::G_POISON:
case TargetOpcode::G_ZEXT:
case TargetOpcode::G_SEXT:
case TargetOpcode::G_ANYEXT:
Expand Down Expand Up @@ -82,7 +83,7 @@ bool CSEConfigFull::shouldCSEOpc(unsigned Opc) {

bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) {
return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT ||
Opc == TargetOpcode::G_IMPLICIT_DEF;
Opc == TargetOpcode::G_IMPLICIT_DEF || Opc == TargetOpcode::G_POISON;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beyond the scope of this patch, but we probably should stop CSEing G_IMPLICIT_DEF, and only do it for G_POISON

}

std::unique_ptr<CSEConfigBase>
Expand Down
37 changes: 35 additions & 2 deletions llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ bool CombinerHelper::matchCombineConcatVectors(
for (const MachineOperand &BuildVecMO : Def->uses())
Ops.push_back(BuildVecMO.getReg());
break;
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF: {
LLT OpType = MRI.getType(Reg);
// Keep one undef value for all the undef operands.
Expand Down Expand Up @@ -2736,13 +2737,26 @@ bool CombinerHelper::matchAnyExplicitUseIsUndef(MachineInstr &MI) const {
});
}

bool CombinerHelper::matchAnyExplicitUseIsPoison(MachineInstr &MI) const {
return any_of(MI.explicit_uses(), [this](const MachineOperand &MO) {
return MO.isReg() && getOpcodeDef(TargetOpcode::G_POISON, MO.getReg(), MRI);
});
}

bool CombinerHelper::matchAllExplicitUsesAreUndef(MachineInstr &MI) const {
return all_of(MI.explicit_uses(), [this](const MachineOperand &MO) {
return !MO.isReg() ||
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also catch the poison case (separate patch though, getOpcodeDef is a bad interface)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

});
}

bool CombinerHelper::matchAllExplicitUsesArePoison(MachineInstr &MI) const {
return all_of(MI.explicit_uses(), [this](const MachineOperand &MO) {
return !MO.isReg() ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't need to check if the operand is a register, but this is consistent with the other cases

getOpcodeDef(TargetOpcode::G_POISON, MO.getReg(), MRI);
});
}

bool CombinerHelper::matchUndefShuffleVectorMask(MachineInstr &MI) const {
assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
Expand All @@ -2755,6 +2769,11 @@ bool CombinerHelper::matchUndefStore(MachineInstr &MI) const {
MRI);
}

bool CombinerHelper::matchPoisonStore(MachineInstr &MI) const {
assert(MI.getOpcode() == TargetOpcode::G_STORE);
return getOpcodeDef(TargetOpcode::G_POISON, MI.getOperand(0).getReg(), MRI);
}

bool CombinerHelper::matchUndefSelectCmp(MachineInstr &MI) const {
assert(MI.getOpcode() == TargetOpcode::G_SELECT);
return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(1).getReg(),
Expand Down Expand Up @@ -2994,6 +3013,12 @@ bool CombinerHelper::matchOperandIsUndef(MachineInstr &MI,
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
}

bool CombinerHelper::matchOperandIsPoison(MachineInstr &MI,
unsigned OpIdx) const {
MachineOperand &MO = MI.getOperand(OpIdx);
return MO.isReg() && getOpcodeDef(TargetOpcode::G_POISON, MO.getReg(), MRI);
}

bool CombinerHelper::matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI,
unsigned OpIdx) const {
MachineOperand &MO = MI.getOperand(OpIdx);
Expand Down Expand Up @@ -3033,6 +3058,12 @@ void CombinerHelper::replaceInstWithUndef(MachineInstr &MI) const {
MI.eraseFromParent();
}

void CombinerHelper::replaceInstWithPoison(MachineInstr &MI) const {
assert(MI.getNumDefs() == 1 && "Expected only one def?");
Builder.buildPoison(MI.getOperand(0));
MI.eraseFromParent();
}

bool CombinerHelper::matchSimplifyAddToSub(
MachineInstr &MI, std::tuple<Register, Register> &MatchInfo) const {
Register LHS = MI.getOperand(1).getReg();
Expand Down Expand Up @@ -3097,6 +3128,7 @@ bool CombinerHelper::matchCombineInsertVecElts(
// If we didn't end in a G_IMPLICIT_DEF and the source is not fully
// overwritten, bail out.
return TmpInst->getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
TmpInst->getOpcode() == TargetOpcode::G_POISON ||
all_of(MatchInfo, [](Register Reg) { return !!Reg; });
}

Expand Down Expand Up @@ -3467,12 +3499,13 @@ bool CombinerHelper::matchUseVectorTruncate(MachineInstr &MI,
if (I < 2)
return false;

// Check the remaining source elements are only G_IMPLICIT_DEF
// Check the remaining source elements are only G_IMPLICIT_DEF or G_POISON
for (; I < NumOperands; ++I) {
auto SrcMI = MRI.getVRegDef(BuildMI->getSourceReg(I));
auto SrcMIOpc = SrcMI->getOpcode();

if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF &&
SrcMIOpc != TargetOpcode::G_POISON)
return false;
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3649,6 +3649,8 @@ bool IRTranslator::translate(const Constant &C, Register Reg) {
EntryBuilder->buildConstant(Reg, *CI);
else if (auto CF = dyn_cast<ConstantFP>(&C))
EntryBuilder->buildFConstant(Reg, *CF);
else if (isa<PoisonValue>(C))
EntryBuilder->buildPoison(Reg);
else if (isa<UndefValue>(C))
EntryBuilder->buildUndef(Reg);
else if (isa<ConstantPointerNull>(C))
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ LegacyLegalizerInfo::LegacyLegalizerInfo() {

setLegalizeScalarToDifferentSizeStrategy(
TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall);
setLegalizeScalarToDifferentSizeStrategy(
TargetOpcode::G_POISON, 0, narrowToSmallerAndUnsupportedIfTooSmall);
setLegalizeScalarToDifferentSizeStrategy(
TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
setLegalizeScalarToDifferentSizeStrategy(
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
switch (MI.getOpcode()) {
default:
return UnableToLegalize;
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF: {
Register DstReg = MI.getOperand(0).getReg();
LLT DstTy = MRI.getType(DstReg);
Expand Down Expand Up @@ -3082,6 +3083,7 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
MI.eraseFromParent();
return Legalized;
}
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF: {
Observer.changingInstr(MI);
widenScalarDst(MI, WideTy);
Expand Down Expand Up @@ -5307,6 +5309,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,

switch (MI.getOpcode()) {
case G_IMPLICIT_DEF:
case G_POISON:
case G_TRUNC:
case G_AND:
case G_OR:
Expand Down Expand Up @@ -6047,6 +6050,7 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
LLT MoreTy) {
unsigned Opc = MI.getOpcode();
switch (Opc) {
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF:
case TargetOpcode::G_LOAD: {
if (TypeIdx != 0)
Expand Down Expand Up @@ -8451,7 +8455,8 @@ LegalizerHelper::lowerVECTOR_COMPRESS(llvm::MachineInstr &MI) {
auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);

bool HasPassthru =
MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;
MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF &&
MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_POISON;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid 2 x getVRegDef

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!


if (HasPassthru)
MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/GlobalISel/LostDebugLocObserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ static bool irTranslatorNeverAddsLocations(unsigned Opcode) {
case TargetOpcode::G_CONSTANT:
case TargetOpcode::G_FCONSTANT:
case TargetOpcode::G_IMPLICIT_DEF:
case TargetOpcode::G_POISON:
case TargetOpcode::G_GLOBAL_VALUE:
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ MachineInstrBuilder MachineIRBuilder::buildUndef(const DstOp &Res) {
return buildInstr(TargetOpcode::G_IMPLICIT_DEF, {Res}, {});
}

MachineInstrBuilder MachineIRBuilder::buildPoison(const DstOp &Res) {
return buildInstr(TargetOpcode::G_POISON, {Res}, {});
}

MachineInstrBuilder MachineIRBuilder::buildMergeValues(const DstOp &Res,
ArrayRef<Register> Ops) {
// Unfortunately to convert from ArrayRef<LLT> to ArrayRef<SrcOp>,
Expand Down
10 changes: 8 additions & 2 deletions llvm/lib/CodeGen/GlobalISel/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,7 @@ static bool isConstantScalar(const MachineInstr &MI,
switch (MI.getOpcode()) {
case TargetOpcode::G_CONSTANT:
case TargetOpcode::G_IMPLICIT_DEF:
case TargetOpcode::G_POISON:
return true;
case TargetOpcode::G_FCONSTANT:
return AllowFP;
Expand Down Expand Up @@ -1547,6 +1548,7 @@ llvm::isConstantOrConstantSplatVectorFP(MachineInstr &MI,
bool llvm::isNullOrNullSplat(const MachineInstr &MI,
const MachineRegisterInfo &MRI, bool AllowUndefs) {
switch (MI.getOpcode()) {
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF:
return AllowUndefs;
case TargetOpcode::G_CONSTANT:
Expand All @@ -1566,6 +1568,7 @@ bool llvm::isAllOnesOrAllOnesSplat(const MachineInstr &MI,
const MachineRegisterInfo &MRI,
bool AllowUndefs) {
switch (MI.getOpcode()) {
case TargetOpcode::G_POISON:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need revisiting, poison could be more aggressive here

case TargetOpcode::G_IMPLICIT_DEF:
return AllowUndefs;
case TargetOpcode::G_CONSTANT:
Expand All @@ -1582,7 +1585,8 @@ bool llvm::matchUnaryPredicate(
std::function<bool(const Constant *ConstVal)> Match, bool AllowUndefs) {

const MachineInstr *Def = getDefIgnoringCopies(Reg, MRI);
if (AllowUndefs && Def->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
if (AllowUndefs && (Def->getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
Def->getOpcode() == TargetOpcode::G_POISON))
return Match(nullptr);

// TODO: Also handle fconstant
Expand All @@ -1595,7 +1599,8 @@ bool llvm::matchUnaryPredicate(
for (unsigned I = 1, E = Def->getNumOperands(); I != E; ++I) {
Register SrcElt = Def->getOperand(I).getReg();
const MachineInstr *SrcDef = getDefIgnoringCopies(SrcElt, MRI);
if (AllowUndefs && SrcDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) {
if (AllowUndefs && (Def->getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
Def->getOpcode() == TargetOpcode::G_POISON)) {
if (!Match(nullptr))
return false;
continue;
Expand Down Expand Up @@ -1914,6 +1919,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(Register Reg,
switch (RegDef->getOpcode()) {
case TargetOpcode::G_FREEZE:
return true;
case TargetOpcode::G_POISON:
case TargetOpcode::G_IMPLICIT_DEF:
return !includesUndef(Kind);
case TargetOpcode::G_CONSTANT:
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/MachineSSAContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ const MachineBasicBlock *MachineSSAContext::getDefBlock(Register value) const {

static bool isUndef(const MachineInstr &MI) {
return MI.getOpcode() == TargetOpcode::G_IMPLICIT_DEF ||
MI.getOpcode() == TargetOpcode::IMPLICIT_DEF;
MI.getOpcode() == TargetOpcode::IMPLICIT_DEF ||
MI.getOpcode() == TargetOpcode::G_POISON;
}

/// MachineInstr equivalent of PHINode::hasConstantOrUndefValue() for G_PHI.
Expand Down
Loading
Loading