diff options
| -rw-r--r-- | llvm/include/llvm/Target/GenericOpcodes.td | 18 | ||||
| -rw-r--r-- | llvm/include/llvm/Target/TargetOpcodes.def | 8 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 27 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp | 5 | ||||
| -rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir | 20 |
5 files changed, 77 insertions, 1 deletions
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 6352a6990f2..8d01bd2c5bd 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -280,6 +280,24 @@ def G_SMULO : Instruction { let isCommutable = 1; } +// Multiply two numbers at twice the incoming bit width (unsigned) and return +// the high half of the result. +def G_UMULH : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +// Multiply two numbers at twice the incoming bit width (signed) and return +// the high half of the result. +def G_SMULH : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + //------------------------------------------------------------------------------ // Floating Point Unary Ops. //------------------------------------------------------------------------------ diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def index a0d6a6309dc..8f209ecb03b 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.def +++ b/llvm/include/llvm/Target/TargetOpcodes.def @@ -331,6 +331,14 @@ HANDLE_TARGET_OPCODE(G_UMULO) /// overflow flag. HANDLE_TARGET_OPCODE(G_SMULO) +// Multiply two numbers at twice the incoming bit width (unsigned) and return +// the high half of the result. +HANDLE_TARGET_OPCODE(G_UMULH) + +// Multiply two numbers at twice the incoming bit width (signed) and return +// the high half of the result. +HANDLE_TARGET_OPCODE(G_SMULH) + /// Generic FP addition. HANDLE_TARGET_OPCODE(G_FADD) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index aeb89a41aa9..f41af0547a3 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -519,6 +519,33 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { MI.eraseFromParent(); return Legalized; } + case TargetOpcode::G_SMULO: + case TargetOpcode::G_UMULO: { + // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the + // result. + unsigned Res = MI.getOperand(0).getReg(); + unsigned Overflow = MI.getOperand(1).getReg(); + unsigned LHS = MI.getOperand(2).getReg(); + unsigned RHS = MI.getOperand(3).getReg(); + + MIRBuilder.buildMul(Res, LHS, RHS); + + unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO + ? TargetOpcode::G_SMULH + : TargetOpcode::G_UMULH; + + unsigned HiPart = MRI.createGenericVirtualRegister(Ty); + MIRBuilder.buildInstr(Opcode) + .addDef(HiPart) + .addUse(LHS) + .addUse(RHS); + + unsigned Zero = MRI.createGenericVirtualRegister(Ty); + MIRBuilder.buildConstant(Zero, 0); + MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero); + MI.eraseFromParent(); + return Legalized; + } } } diff --git a/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp index ad0482ac7d5..32f9c5f80d0 100644 --- a/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp @@ -64,7 +64,10 @@ AArch64LegalizerInfo::AArch64LegalizerInfo() { for (auto Ty : { s1, s8, s16, s32, s64 }) setAction({BinOp, Ty}, Lower); - for (unsigned Op : {G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_SMULO, G_UMULO}) { + for (unsigned Op : {G_SMULO, G_UMULO}) + setAction({Op, s64}, Lower); + + for (unsigned Op : {G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_SMULH, G_UMULH}) { for (auto Ty : { s32, s64 }) setAction({Op, Ty}, Legal); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir index e56eef0bc4f..36726b7a30c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir @@ -7,6 +7,7 @@ entry: ret void } + define void @test_mul_overflow() { ret void } ... --- @@ -35,3 +36,22 @@ body: | %5(s64) = G_ANYEXT %2 %x0 = COPY %5 ... + + +--- +name: test_mul_overflow +body: | + bb.0: + liveins: %x0, %x1, %w2, %w3 + + %0:_(s64) = COPY %x0 + %1:_(s64) = COPY %x1 + + ; CHECK-LABEL: name: test_mul_overflow + ; CHECK: %2(s64) = G_MUL %0, %1 + ; CHECK: [[HI:%[0-9]+]](s64) = G_SMULH %0, %1 + ; CHECK: [[ZERO:%[0-9]+]](s64) = G_CONSTANT i64 0 + ; CHECK: %3(s1) = G_ICMP intpred(ne), [[HI]](s64), [[ZERO]] + %2:_(s64), %3:_(s1) = G_SMULO %0, %1 + +... |

