forked from OSchip/llvm-project
[GISel]: Add missing opcodes for overflow intrinsics
https://reviews.llvm.org/D51197 Currently, IRTranslator (and GISel) seems to be arbitrarily picking which overflow intrinsics get mapped into opcodes which either have a carry as an input or not. For intrinsics such as Intrinsic::uadd_with_overflow, translate it to an opcode (G_UADDO) which doesn't have any carry inputs (similar to LLVM IR). This patch adds 4 missing opcodes for completeness - G_UADDO, G_USUBO, G_SSUBE and G_SADDE. llvm-svn: 340865
This commit is contained in:
parent
adb6da10b8
commit
6b4d343e13
|
@ -362,10 +362,18 @@ HANDLE_TARGET_OPCODE(G_FCMP)
|
|||
/// Generic select.
|
||||
HANDLE_TARGET_OPCODE(G_SELECT)
|
||||
|
||||
/// Generic unsigned add instruction, consuming the normal operands and
|
||||
/// producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_UADDO)
|
||||
|
||||
/// Generic unsigned add instruction, consuming the normal operands plus a carry
|
||||
/// flag, and similarly producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_UADDE)
|
||||
|
||||
/// Generic unsigned sub instruction, consuming the normal operands and
|
||||
/// producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_USUBO)
|
||||
|
||||
/// Generic unsigned subtract instruction, consuming the normal operands plus a
|
||||
/// carry flag, and similarly producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_USUBE)
|
||||
|
@ -374,10 +382,18 @@ HANDLE_TARGET_OPCODE(G_USUBE)
|
|||
/// flag.
|
||||
HANDLE_TARGET_OPCODE(G_SADDO)
|
||||
|
||||
/// Generic signed add instruction, consuming the normal operands plus a carry
|
||||
/// flag, and similarly producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_SADDE)
|
||||
|
||||
/// Generic signed subtract instruction, producing the result and a signed
|
||||
/// overflow flag.
|
||||
HANDLE_TARGET_OPCODE(G_SSUBO)
|
||||
|
||||
/// Generic signed sub instruction, consuming the normal operands plus a carry
|
||||
/// flag, and similarly producing the result and a carry flag.
|
||||
HANDLE_TARGET_OPCODE(G_SSUBE)
|
||||
|
||||
/// Generic unsigned multiply instruction, producing the result and a signed
|
||||
/// overflow flag.
|
||||
HANDLE_TARGET_OPCODE(G_UMULO)
|
||||
|
|
|
@ -311,6 +311,14 @@ def G_PTR_MASK : GenericInstruction {
|
|||
// Overflow ops
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Generic unsigned addition producing a carry flag.
|
||||
def G_UADDO : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
let InOperandList = (ins type0:$src1, type0:$src2);
|
||||
let hasSideEffects = 0;
|
||||
let isCommutable = 1;
|
||||
}
|
||||
|
||||
// Generic unsigned addition consuming and producing a carry flag.
|
||||
def G_UADDE : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
|
@ -326,6 +334,19 @@ def G_SADDO : GenericInstruction {
|
|||
let isCommutable = 1;
|
||||
}
|
||||
|
||||
// Generic signed addition consuming and producing a carry flag.
|
||||
def G_SADDE : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
let InOperandList = (ins type0:$src1, type0:$src2, type1:$carry_in);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
|
||||
// Generic unsigned subtraction producing a carry flag.
|
||||
def G_USUBO : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
let InOperandList = (ins type0:$src1, type0:$src2);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
// Generic unsigned subtraction consuming and producing a carry flag.
|
||||
def G_USUBE : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
|
@ -333,13 +354,20 @@ def G_USUBE : GenericInstruction {
|
|||
let hasSideEffects = 0;
|
||||
}
|
||||
|
||||
// Generic unsigned subtraction producing a carry flag.
|
||||
// Generic signed subtraction producing a carry flag.
|
||||
def G_SSUBO : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
let InOperandList = (ins type0:$src1, type0:$src2);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
|
||||
// Generic signed subtraction consuming and producing a carry flag.
|
||||
def G_SSUBE : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
let InOperandList = (ins type0:$src1, type0:$src2, type1:$carry_in);
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
|
||||
// Generic unsigned multiplication producing a carry flag.
|
||||
def G_UMULO : GenericInstruction {
|
||||
let OutOperandList = (outs type0:$dst, type1:$carry_out);
|
||||
|
|
|
@ -717,17 +717,11 @@ void IRTranslator::getStackGuard(unsigned DstReg,
|
|||
bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
ArrayRef<unsigned> ResRegs = getOrCreateVRegs(CI);
|
||||
auto MIB = MIRBuilder.buildInstr(Op)
|
||||
.addDef(ResRegs[0])
|
||||
.addDef(ResRegs[1])
|
||||
.addUse(getOrCreateVReg(*CI.getOperand(0)))
|
||||
.addUse(getOrCreateVReg(*CI.getOperand(1)));
|
||||
|
||||
if (Op == TargetOpcode::G_UADDE || Op == TargetOpcode::G_USUBE) {
|
||||
unsigned Zero = getOrCreateVReg(
|
||||
*Constant::getNullValue(Type::getInt1Ty(CI.getContext())));
|
||||
MIB.addUse(Zero);
|
||||
}
|
||||
MIRBuilder.buildInstr(Op)
|
||||
.addDef(ResRegs[0])
|
||||
.addDef(ResRegs[1])
|
||||
.addUse(getOrCreateVReg(*CI.getOperand(0)))
|
||||
.addUse(getOrCreateVReg(*CI.getOperand(1)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -819,11 +813,11 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|||
return true;
|
||||
}
|
||||
case Intrinsic::uadd_with_overflow:
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDE, MIRBuilder);
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDO, MIRBuilder);
|
||||
case Intrinsic::sadd_with_overflow:
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_SADDO, MIRBuilder);
|
||||
case Intrinsic::usub_with_overflow:
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_USUBE, MIRBuilder);
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_USUBO, MIRBuilder);
|
||||
case Intrinsic::ssub_with_overflow:
|
||||
return translateOverflowIntrinsic(CI, TargetOpcode::G_SSUBO, MIRBuilder);
|
||||
case Intrinsic::umul_with_overflow:
|
||||
|
|
|
@ -844,8 +844,7 @@ define void @test_sadd_overflow(i32 %lhs, i32 %rhs, { i32, i1 }* %addr) {
|
|||
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||||
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||||
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||||
; CHECK: [[ZERO:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
|
||||
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_UADDE [[LHS]], [[RHS]], [[ZERO]]
|
||||
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_UADDO [[LHS]], [[RHS]]
|
||||
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store 4 into %ir.addr)
|
||||
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||||
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
|
||||
|
@ -877,8 +876,7 @@ define void @test_ssub_overflow(i32 %lhs, i32 %rhs, { i32, i1 }* %subr) {
|
|||
; CHECK: [[LHS:%[0-9]+]]:_(s32) = COPY $w0
|
||||
; CHECK: [[RHS:%[0-9]+]]:_(s32) = COPY $w1
|
||||
; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
|
||||
; CHECK: [[ZERO:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
|
||||
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_USUBE [[LHS]], [[RHS]], [[ZERO]]
|
||||
; CHECK: [[VAL:%[0-9]+]]:_(s32), [[OVERFLOW:%[0-9]+]]:_(s1) = G_USUBO [[LHS]], [[RHS]]
|
||||
; CHECK: G_STORE [[VAL]](s32), [[ADDR]](p0) :: (store 4 into %ir.subr)
|
||||
; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
|
||||
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
|
||||
|
|
|
@ -189,18 +189,30 @@
|
|||
# DEBUG-NEXT: G_SELECT (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
# DEBUG-NEXT: G_UADDO (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. type index coverage check SKIPPED: no rules defined
|
||||
#
|
||||
# DEBUG-NEXT: G_UADDE (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
# DEBUG-NEXT: G_USUBO (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. type index coverage check SKIPPED: no rules defined
|
||||
#
|
||||
# DEBUG-NEXT: G_USUBE (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
# DEBUG-NEXT: G_SADDO (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
# DEBUG-NEXT: G_SADDE (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. type index coverage check SKIPPED: no rules defined
|
||||
#
|
||||
# DEBUG-NEXT: G_SSUBO (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
# DEBUG-NEXT: G_SSUBE (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. type index coverage check SKIPPED: no rules defined
|
||||
#
|
||||
# DEBUG-NEXT: G_UMULO (opcode {{[0-9]+}}): 2 type indices
|
||||
# DEBUG: .. the first uncovered type index: 2, OK
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue