Fix signed multiplication with overflow fallback.
authorRanjeet Singh <Ranjeet.Singh@arm.com>
Wed, 26 Apr 2017 13:41:43 +0000 (13:41 +0000)
committerRanjeet Singh <Ranjeet.Singh@arm.com>
Wed, 26 Apr 2017 13:41:43 +0000 (13:41 +0000)
For targets that don't have ISD::MULHS or ISD::SMUL_LOHI for the type
and the double width type is illegal, then the two operands are
sign extended to twice their size then multiplied to check for overflow.
The extended upper halves were mismatched causing an incorrect result.
This fixes the mismatch.

A test was added for ARM V6-M where the bug was detected.

Patch by James Duley.

Differential Revision: https://reviews.llvm.org/D31807

llvm-svn: 301404

llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
llvm/test/CodeGen/ARM/v6m-smul-with-overflow.ll [new file with mode: 0644]

index 3bae3bf..fdebb8b 100644 (file)
@@ -3497,11 +3497,11 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
       // part.
       unsigned LoSize = VT.getSizeInBits();
       SDValue HiLHS =
-          DAG.getNode(ISD::SRA, dl, VT, RHS,
+          DAG.getNode(ISD::SRA, dl, VT, LHS,
                       DAG.getConstant(LoSize - 1, dl,
                                       TLI.getPointerTy(DAG.getDataLayout())));
       SDValue HiRHS =
-          DAG.getNode(ISD::SRA, dl, VT, LHS,
+          DAG.getNode(ISD::SRA, dl, VT, RHS,
                       DAG.getConstant(LoSize - 1, dl,
                                       TLI.getPointerTy(DAG.getDataLayout())));
 
diff --git a/llvm/test/CodeGen/ARM/v6m-smul-with-overflow.ll b/llvm/test/CodeGen/ARM/v6m-smul-with-overflow.ll
new file mode 100644 (file)
index 0000000..6e8a704
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llc < %s -mtriple=thumbv6m-none-eabi | FileCheck %s
+
+define i1 @signed_multiplication_did_overflow(i32, i32) {
+; CHECK-LABEL: signed_multiplication_did_overflow:
+entry-block:
+  %2 = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %0, i32 %1)
+  %3 = extractvalue { i32, i1 } %2, 1
+  ret i1 %3
+
+; CHECK: mov    r2, r1
+; CHECK: asrs   r1, r0, #31
+; CHECK: asrs   r3, r2, #31
+; CHECK: bl     __aeabi_lmul
+}
+
+declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32)