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 7 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
59 changes: 51 additions & 8 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 @@ -454,7 +455,8 @@ bool CombinerHelper::matchCombineShuffleConcat(
return false;
}
if (!isLegalOrBeforeLegalizer(
{TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}))
{TargetOpcode::G_IMPLICIT_DEF, {ConcatSrcTy}}) ||
!isLegalOrBeforeLegalizer({TargetOpcode::G_POISON, {ConcatSrcTy}}))
return false;
Ops.push_back(0);
} else if (Mask[i] % ConcatSrcNumElt == 0) {
Expand Down Expand Up @@ -2732,14 +2734,29 @@ void CombinerHelper::applyCombineTruncOfShift(
bool CombinerHelper::matchAnyExplicitUseIsUndef(MachineInstr &MI) const {
return any_of(MI.explicit_uses(), [this](const MachineOperand &MO) {
return MO.isReg() &&
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
(getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI) ||
getOpcodeDef(TargetOpcode::G_POISON, MO.getReg(), MRI));
Comment on lines +2739 to +2740
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a fixme? We shouldn't look up copy chains twice just to check 2 opcodes. We should delete getOpcodeDef as a helper, it's not good

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! In the next patch I can come up with some helpers where getOpcodeDef accepts a set of opcodes.

});
}

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);
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI) ||
getOpcodeDef(TargetOpcode::G_POISON, MO.getReg(), MRI);
});
}

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);
});
}

Expand All @@ -2752,12 +2769,21 @@ bool CombinerHelper::matchUndefShuffleVectorMask(MachineInstr &MI) const {
bool CombinerHelper::matchUndefStore(MachineInstr &MI) const {
assert(MI.getOpcode() == TargetOpcode::G_STORE);
return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(0).getReg(),
MRI) ||
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(0).getReg(),
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(),
MRI) ||
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(1).getReg(),
MRI);
}

Expand Down Expand Up @@ -2991,7 +3017,14 @@ bool CombinerHelper::matchOperandIsUndef(MachineInstr &MI,
unsigned OpIdx) const {
MachineOperand &MO = MI.getOperand(OpIdx);
return MO.isReg() &&
getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI);
(getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI) ||
getOpcodeDef(TargetOpcode::G_POISON, 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,
Expand Down Expand Up @@ -3033,6 +3066,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 +3136,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 +3507,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 Expand Up @@ -7927,10 +7968,12 @@ bool CombinerHelper::matchShuffleDisjointMask(MachineInstr &MI,
auto &Shuffle = cast<GShuffleVector>(MI);
// If any of the two inputs is already undef, don't check the mask again to
// prevent infinite loop
if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(), MRI))
if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc1Reg(), MRI) ||
getOpcodeDef(TargetOpcode::G_POISON, Shuffle.getSrc1Reg(), MRI))
return false;

if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(), MRI))
if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Shuffle.getSrc2Reg(), MRI) ||
getOpcodeDef(TargetOpcode::G_POISON, Shuffle.getSrc2Reg(), MRI))
return false;

const LLT DstTy = MRI.getType(Shuffle.getReg(0));
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
11 changes: 8 additions & 3 deletions 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 @@ -8450,15 +8454,16 @@ LegalizerHelper::lowerVECTOR_COMPRESS(llvm::MachineInstr &MI) {

auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);

bool HasPassthru =
MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;
auto *PassthruMI = MRI.getVRegDef(Passthru);
bool HasPassthru = PassthruMI->getOpcode() != TargetOpcode::G_IMPLICIT_DEF &&
PassthruMI->getOpcode() != TargetOpcode::G_POISON;

if (HasPassthru)
MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);

Register LastWriteVal;
std::optional<APInt> PassthruSplatVal =
isConstantOrConstantSplatVector(*MRI.getVRegDef(Passthru), MRI);
isConstantOrConstantSplatVector(*PassthruMI, MRI);

if (PassthruSplatVal.has_value()) {
LastWriteVal =
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
Loading
Loading