Skip to content

Commit

Permalink
[SelectionDAG] Fix return calling convention in expansion of ?MULO
Browse files Browse the repository at this point in the history
Summary:
The SMULO/UMULO DAG nodes, when not directly supported by the target,
expand to a multiplication twice as wide. In case that the resulting
type is not legal, the legalizer cannot directly call the intrinsic
with the wide arguments; instead, it "pre-lowers" them by splitting
them in halves.

rL283203 made sure that on big endian targets, the legalizer passes
the argument halves in the correct order. It did not do the same
for the return value halves because the existing code used a hack;
it put an illegal type into DAG and hoped that nothing would break
and it would be correctly lowered elsewhere.

rL307207 fixed this, handling return value halves similar to how
argument handles are handled, but did not take big-endian targets
into account.

This commit fixes the expansion on big-endian targets, such as
the out-of-tree OR1K target.

Reviewers: eli.friedman, vadimcn

Subscribers: george-hopkins, efriedma, llvm-commits

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

llvm-svn: 353854
  • Loading branch information
whitequark committed Feb 12, 2019
1 parent f9fe483 commit 77ccc2e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
12 changes: 9 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Expand Up @@ -3423,7 +3423,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
// being a legal type for the architecture and thus has to be split to
// two arguments.
SDValue Ret;
if(DAG.getDataLayout().isLittleEndian()) {
if (DAG.getDataLayout().isLittleEndian()) {
// Halves of WideVT are packed into registers in different order
// depending on platform endianness. This is usually handled by
// the C calling convention, but we can't defer to it in
Expand All @@ -3436,8 +3436,14 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
}
assert(Ret.getOpcode() == ISD::MERGE_VALUES &&
"Ret value is a collection of constituent nodes holding result.");
BottomHalf = Ret.getOperand(0);
TopHalf = Ret.getOperand(1);
if (DAG.getDataLayout().isLittleEndian()) {
// Same as above.
BottomHalf = Ret.getOperand(0);
TopHalf = Ret.getOperand(1);
} else {
BottomHalf = Ret.getOperand(1);
TopHalf = Ret.getOperand(0);
}
}

if (isSigned) {
Expand Down
43 changes: 43 additions & 0 deletions llvm/test/CodeGen/Thumb/umulo-32-legalisation-lowering.ll
@@ -0,0 +1,43 @@
; RUN: llc < %s -mtriple=thumb-eabi | FileCheck %s --check-prefixes CHECK,CHECK-LITTLE
; RUN: llc < %s -mtriple=thumbeb-eabi | FileCheck %s --check-prefixes CHECK,CHECK-BIG

define i1 @umulo32(i32 %l, i32 %r) unnamed_addr #0 {
; CHECK-LABEL: umulo32:
; CHECK: @ %bb.0: @ %start
; CHECK-NEXT: .save {r7, lr}
; CHECK-NEXT: push {r7, lr}
; CHECK-LITTLE-NEXT: movs r2, r1
; CHECK-LITTLE-NEXT: movs r1, #0
; CHECK-NEXT: movs r3, r1
; CHECK-BIG-NEXT: movs r1, r0
; CHECK-BIG-NEXT: movs r0, #0
; CHECK-BIG-NEXT: movs r2, r0
; CHECK-NEXT: bl __aeabi_lmul
; CHECK-LITTLE-NEXT: cmp r1, #0
; CHECK-LITTLE-NEXT: bne .LBB0_2
; CHECK-LITTLE-NEXT: @ %bb.1:
; CHECK-LITTLE-NEXT: movs r0, r1
; CHECK-LITTLE-NEXT: b .LBB0_3
; CHECK-LITTLE-NEXT: .LBB0_2:
; CHECK-LITTLE-NEXT: movs r0, #1
; CHECK-LITTLE-NEXT: .LBB0_3:
; CHECK-BIG-NEXT: cmp r0, #0
; CHECK-BIG-NEXT: beq .LBB0_2
; CHECK-BIG-NEXT: @ %bb.1:
; CHECK-BIG-NEXT: movs r0, #1
; CHECK-BIG-NEXT: .LBB0_2:
; CHECK-NEXT: pop {r7}
; CHECK-NEXT: pop {r1}
; CHECK-NEXT: bx r1
start:
%0 = tail call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %l, i32 %r) #2
%1 = extractvalue { i32, i1 } %0, 1
ret i1 %1
}

; Function Attrs: nounwind readnone speculatable
declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) #1

attributes #0 = { nounwind readnone uwtable }
attributes #1 = { nounwind readnone speculatable }
attributes #2 = { nounwind }

0 comments on commit 77ccc2e

Please sign in to comment.