[llvm] r294519 - GlobalISel: expand mul-with-overflow into mul-hi on AArch64.

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 8 13:22:15 PST 2017


Author: tnorthover
Date: Wed Feb  8 15:22:15 2017
New Revision: 294519

URL: http://llvm.org/viewvc/llvm-project?rev=294519&view=rev
Log:
GlobalISel: expand mul-with-overflow into mul-hi on AArch64.

AArch64 has specific instructions to multiply two numbers at double the width
and produce the high part of the result. These can be used to implement LLVM's
mul.with.overflow instructions fairly simply. Helps with C++ operator new[].

Modified:
    llvm/trunk/include/llvm/Target/GenericOpcodes.td
    llvm/trunk/include/llvm/Target/TargetOpcodes.def
    llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
    llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir

Modified: llvm/trunk/include/llvm/Target/GenericOpcodes.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/GenericOpcodes.td?rev=294519&r1=294518&r2=294519&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/GenericOpcodes.td (original)
+++ llvm/trunk/include/llvm/Target/GenericOpcodes.td Wed Feb  8 15:22:15 2017
@@ -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.
 //------------------------------------------------------------------------------

Modified: llvm/trunk/include/llvm/Target/TargetOpcodes.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetOpcodes.def?rev=294519&r1=294518&r2=294519&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetOpcodes.def (original)
+++ llvm/trunk/include/llvm/Target/TargetOpcodes.def Wed Feb  8 15:22:15 2017
@@ -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)
 

Modified: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp?rev=294519&r1=294518&r2=294519&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (original)
+++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp Wed Feb  8 15:22:15 2017
@@ -519,6 +519,33 @@ LegalizerHelper::lower(MachineInstr &MI,
     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;
+  }
   }
 }
 

Modified: llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp?rev=294519&r1=294518&r2=294519&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64LegalizerInfo.cpp Wed Feb  8 15:22:15 2017
@@ -64,7 +64,10 @@ AArch64LegalizerInfo::AArch64LegalizerIn
     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);
 

Modified: llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir?rev=294519&r1=294518&r2=294519&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir (original)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/legalize-mul.mir Wed Feb  8 15:22:15 2017
@@ -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
+
+...




More information about the llvm-commits mailing list