forked from OSchip/llvm-project
[GlobalISel] Add G_ABS
This is equivalent to the new llvm.abs intrinsic added by D84125 with is_int_min_poison=0. Differential Revision: https://reviews.llvm.org/D85718
This commit is contained in:
parent
d4408fe17f
commit
fa2b836ea3
|
@ -309,6 +309,16 @@ Take the minimum/maximum of two values.
|
|||
|
||||
%5:_(s32) = G_SMIN %6, %2
|
||||
|
||||
G_ABS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Take the absolute value of a signed integer. The absolute value of the minimum
|
||||
negative value (e.g. the 8-bit value `0x80`) is defined to be itself.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
%1:_(s32) = G_ABS %0
|
||||
|
||||
G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_SMULO, G_UMULO
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -289,6 +289,11 @@ private:
|
|||
/// MachineBasicBlocks for the function have been created.
|
||||
void finishPendingPhis();
|
||||
|
||||
/// Translate \p Inst into a unary operation \p Opcode.
|
||||
/// \pre \p U is a unary operation.
|
||||
bool translateUnaryOp(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate \p Inst into a binary operation \p Opcode.
|
||||
/// \pre \p U is a binary operation.
|
||||
bool translateBinaryOp(unsigned Opcode, const User &U,
|
||||
|
|
|
@ -223,6 +223,7 @@ class MachineIRBuilder {
|
|||
protected:
|
||||
void validateTruncExt(const LLT Dst, const LLT Src, bool IsExtend);
|
||||
|
||||
void validateUnaryOp(const LLT Res, const LLT Op0);
|
||||
void validateBinaryOp(const LLT Res, const LLT Op0, const LLT Op1);
|
||||
void validateShiftOp(const LLT Res, const LLT Op0, const LLT Op1);
|
||||
|
||||
|
@ -1665,6 +1666,11 @@ public:
|
|||
return buildInstr(TargetOpcode::G_UMAX, {Dst}, {Src0, Src1});
|
||||
}
|
||||
|
||||
/// Build and insert \p Dst = G_ABS \p Src
|
||||
MachineInstrBuilder buildAbs(const DstOp &Dst, const SrcOp &Src) {
|
||||
return buildInstr(TargetOpcode::G_ABS, {Dst}, {Src});
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_JUMP_TABLE \p JTI
|
||||
///
|
||||
/// G_JUMP_TABLE sets \p Res to the address of the jump table specified by
|
||||
|
|
|
@ -610,6 +610,9 @@ HANDLE_TARGET_OPCODE(G_UMIN)
|
|||
/// Generic unsigned integer maximum.
|
||||
HANDLE_TARGET_OPCODE(G_UMAX)
|
||||
|
||||
/// Generic integer absolute value.
|
||||
HANDLE_TARGET_OPCODE(G_ABS)
|
||||
|
||||
/// Generic BRANCH instruction. This is an unconditional branch.
|
||||
HANDLE_TARGET_OPCODE(G_BR)
|
||||
|
||||
|
|
|
@ -414,6 +414,13 @@ def G_UMAX : GenericInstruction {
|
|||
let isCommutable = 1;
|
||||
}
|
||||
|
||||
// Generic integer absolute value.
|
||||
def G_ABS : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst);
|
||||
let InOperandList = (ins type0:$src);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Overflow ops
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
@ -135,6 +135,7 @@ def : GINodeEquiv<G_SMIN, smin>;
|
|||
def : GINodeEquiv<G_SMAX, smax>;
|
||||
def : GINodeEquiv<G_UMIN, umin>;
|
||||
def : GINodeEquiv<G_UMAX, umax>;
|
||||
def : GINodeEquiv<G_ABS, abs>;
|
||||
def : GINodeEquiv<G_FMINNUM, fminnum>;
|
||||
def : GINodeEquiv<G_FMAXNUM, fmaxnum>;
|
||||
def : GINodeEquiv<G_FMINNUM_IEEE, fminnum_ieee>;
|
||||
|
|
|
@ -295,7 +295,8 @@ bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
bool IRTranslator::translateUnaryOp(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
Register Op0 = getOrCreateVReg(*U.getOperand(0));
|
||||
Register Res = getOrCreateVReg(U);
|
||||
uint16_t Flags = 0;
|
||||
|
@ -303,10 +304,14 @@ bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
|||
const Instruction &I = cast<Instruction>(U);
|
||||
Flags = MachineInstr::copyFlagsFromInstruction(I);
|
||||
}
|
||||
MIRBuilder.buildFNeg(Res, Op0, Flags);
|
||||
MIRBuilder.buildInstr(Opcode, {Res}, {Op0}, Flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateUnaryOp(TargetOpcode::G_FNEG, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool IRTranslator::translateCompare(const User &U,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
auto *CI = dyn_cast<CmpInst>(&U);
|
||||
|
@ -1496,6 +1501,9 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|||
return translateBinaryOp(TargetOpcode::G_SMIN, CI, MIRBuilder);
|
||||
case Intrinsic::smax:
|
||||
return translateBinaryOp(TargetOpcode::G_SMAX, CI, MIRBuilder);
|
||||
case Intrinsic::abs:
|
||||
// TODO: Preserve "int min is poison" arg in GMIR?
|
||||
return translateUnaryOp(TargetOpcode::G_ABS, CI, MIRBuilder);
|
||||
case Intrinsic::smul_fix:
|
||||
return translateFixedPointIntrinsic(TargetOpcode::G_SMULFIX, CI, MIRBuilder);
|
||||
case Intrinsic::umul_fix:
|
||||
|
|
|
@ -162,6 +162,11 @@ MachineInstrBuilder MachineIRBuilder::buildJumpTable(const LLT PtrTy,
|
|||
.addJumpTableIndex(JTI);
|
||||
}
|
||||
|
||||
void MachineIRBuilder::validateUnaryOp(const LLT Res, const LLT Op0) {
|
||||
assert((Res.isScalar() || Res.isVector()) && "invalid operand type");
|
||||
assert((Res == Op0) && "type mismatch");
|
||||
}
|
||||
|
||||
void MachineIRBuilder::validateBinaryOp(const LLT Res, const LLT Op0,
|
||||
const LLT Op1) {
|
||||
assert((Res.isScalar() || Res.isVector()) && "invalid operand type");
|
||||
|
@ -949,6 +954,14 @@ MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opc,
|
|||
SrcOps[1].getLLTTy(*getMRI()), SrcOps[2].getLLTTy(*getMRI()));
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::G_FNEG:
|
||||
case TargetOpcode::G_ABS:
|
||||
// All these are unary ops.
|
||||
assert(DstOps.size() == 1 && "Invalid Dst");
|
||||
assert(SrcOps.size() == 1 && "Invalid Srcs");
|
||||
validateUnaryOp(DstOps[0].getLLTTy(*getMRI()),
|
||||
SrcOps[0].getLLTTy(*getMRI()));
|
||||
break;
|
||||
case TargetOpcode::G_ADD:
|
||||
case TargetOpcode::G_AND:
|
||||
case TargetOpcode::G_MUL:
|
||||
|
|
|
@ -496,6 +496,9 @@
|
|||
# DEBUG: G_UMAX (opcode {{[0-9]+}}): 1 type index
|
||||
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: G_ABS (opcode {{[0-9]+}}): 1 type index, 0 imm indices
|
||||
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: G_BR (opcode {{[0-9]+}}): 0 type indices, 0 imm indices
|
||||
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
|
||||
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
|
||||
|
|
|
@ -266,7 +266,7 @@ TEST_F(AArch64GISelMITest, BuildCasts) {
|
|||
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
|
||||
}
|
||||
|
||||
TEST_F(AArch64GISelMITest, BuildMinMax) {
|
||||
TEST_F(AArch64GISelMITest, BuildMinMaxAbs) {
|
||||
setUp();
|
||||
if (!TM)
|
||||
return;
|
||||
|
@ -279,6 +279,7 @@ TEST_F(AArch64GISelMITest, BuildMinMax) {
|
|||
B.buildSMax(S64, Copies[0], Copies[1]);
|
||||
B.buildUMin(S64, Copies[0], Copies[1]);
|
||||
B.buildUMax(S64, Copies[0], Copies[1]);
|
||||
B.buildAbs(S64, Copies[0]);
|
||||
|
||||
auto CheckStr = R"(
|
||||
; CHECK: [[COPY0:%[0-9]+]]:_(s64) = COPY $x0
|
||||
|
@ -287,6 +288,7 @@ TEST_F(AArch64GISelMITest, BuildMinMax) {
|
|||
; CHECK: [[SMAX0:%[0-9]+]]:_(s64) = G_SMAX [[COPY0]]:_, [[COPY1]]:_
|
||||
; CHECK: [[UMIN0:%[0-9]+]]:_(s64) = G_UMIN [[COPY0]]:_, [[COPY1]]:_
|
||||
; CHECK: [[UMAX0:%[0-9]+]]:_(s64) = G_UMAX [[COPY0]]:_, [[COPY1]]:_
|
||||
; CHECK: [[UABS0:%[0-9]+]]:_(s64) = G_ABS [[COPY0]]:_
|
||||
)";
|
||||
|
||||
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
|
||||
|
|
Loading…
Reference in New Issue