[PATCH] SelectionDAG: Share ISD::MUL lowering code between the SelectionDAGLegalize and DAGTypeLegalizer
Tom Stellard
tom at stellard.net
Tue Apr 8 13:00:26 PDT 2014
Ping.
On Mon, Mar 31, 2014 at 07:25:30AM -0700, Tom Stellard wrote:
> On Fri, Feb 07, 2014 at 02:54:39PM -0800, Owen Anderson wrote:
> >
> > On Feb 7, 2014, at 2:20 PM, Hal Finkel <hfinkel at anl.gov> wrote:
> >
> > > ----- Original Message -----
> > >> From: "Tom Stellard" <tom at stellard.net>
> > >> To: llvm-commits at cs.uiuc.edu
> > >> Sent: Friday, February 7, 2014 4:12:13 PM
> > >> Subject: [PATCH] SelectionDAG: Share ISD::MUL lowering code between the SelectionDAGLegalize and DAGTypeLegalizer
> > >>
> > >> Hi,
> > >>
> > >> The attached patches allow the SelectionDAGLegalizer to reuse ISD:MUL
> > >> lowering code from the DAGTypeLegalizer.
> > >>
> > >> The first patch moves the DAGTypeLegalizer ISD:MUL lowering code into
> > >> a public
> > >> SelectionDAG function called expandMUL() and the second patch
> > >> modifies
> > >> the SelectionDAGLegalizer to use this code.
> > >>
> > >> I think there may be other opportunities to share code between these
> > >> two classes,
> > >> so I'm wondering if the approach I've taken would work for other
> > >> operations too.
> > >> I'm interested in hearing what other people think.
> > >
> > > I've not yet looked at the patch, but I'll add: There is also expansion logic hidden away in the legalization code that could be used by *ISelLowering in the various targets, and I think that moving things into utility functions in SelectionDAG will help with reuse there as well (GatherAllAliases comes to mind, for example). So, generally speaking, I think this kind of refactoring is a good idea.
> >
> > I agree with Hal, and the general sentiment that it would be great to share more of these expansions between type and operation legalization. That said, I’d like to find a cleaner way to factor them out than just moving them all into methods on SelectionDAG.
> >
>
> I wasn't sure where else to put these functions, so I moved them into
> the TargetLowering class. What do you think?
>
> -Tom
> From ce43dc06f3274eca0b2bac2e1032d90c58a0d3be Mon Sep 17 00:00:00 2001
> From: Tom Stellard <thomas.stellard at amd.com>
> Date: Fri, 7 Feb 2014 14:06:04 -0500
> Subject: [PATCH 1/2] SelectionDAG: Factor ISD::MUL lowering code out of
> DAGTypeLegalizer
>
> This code has been moved to a new function in the TargetLowering
> class called expandMUL(). The purpose of this is to be able
> to share lowering code between the SelectionDAGLegalize and
> DAGTypeLegalizer classes.
>
> No functionality changed intended.
> ---
> include/llvm/Target/TargetLowering.h | 18 ++++
> lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 73 ++-------------
> lib/CodeGen/SelectionDAG/TargetLowering.cpp | 107 ++++++++++++++++++++++
> 3 files changed, 131 insertions(+), 67 deletions(-)
>
> diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h
> index 8f00ac8f..c0c2c74 100644
> --- a/include/llvm/Target/TargetLowering.h
> +++ b/include/llvm/Target/TargetLowering.h
> @@ -2326,6 +2326,24 @@ public:
> std::vector<SDNode*> *Created) const;
>
> //===--------------------------------------------------------------------===//
> + // Legalization utility functions
> + //
> +
> + /// Expand a MUL into two nodes. One that computes the high bits of
> + /// the result and one that computes the low bits.
> + /// \param VT The value type to use for the Lo and Hi nodes.
> + /// \param LL Low bits of the LHS of the MUL. You can use this parameter
> + /// if you want to control how low bits are extracted from the LHS.
> + /// \param LH High bits of the LHS of the MUL. See LL for meaning.
> + /// \param RL Low bits of the RHS of the MUL. See LL for meaning
> + /// \param RH High bits of the RHS of the MUL. See LL for meaning.
> + /// \returns true if the node has been expanded. false if it has not
> + bool expandMUL(SDNode *N, SDValue &Lo, SDValue &Hi, EVT HiLoVT,
> + SelectionDAG &DAG, SDValue LL = SDValue(),
> + SDValue LH = SDValue(), SDValue RL = SDValue(),
> + SDValue RH = SDValue()) const;
> +
> + //===--------------------------------------------------------------------===//
> // Instruction Emitting Hooks
> //
>
> diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> index 18b2376..630cd79 100644
> --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
> @@ -1923,73 +1923,12 @@ void DAGTypeLegalizer::ExpandIntRes_MUL(SDNode *N,
> EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
> SDLoc dl(N);
>
> - bool HasMULHS = TLI.isOperationLegalOrCustom(ISD::MULHS, NVT);
> - bool HasMULHU = TLI.isOperationLegalOrCustom(ISD::MULHU, NVT);
> - bool HasSMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::SMUL_LOHI, NVT);
> - bool HasUMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::UMUL_LOHI, NVT);
> - if (HasMULHU || HasMULHS || HasUMUL_LOHI || HasSMUL_LOHI) {
> - SDValue LL, LH, RL, RH;
> - GetExpandedInteger(N->getOperand(0), LL, LH);
> - GetExpandedInteger(N->getOperand(1), RL, RH);
> - unsigned OuterBitSize = VT.getSizeInBits();
> - unsigned InnerBitSize = NVT.getSizeInBits();
> - unsigned LHSSB = DAG.ComputeNumSignBits(N->getOperand(0));
> - unsigned RHSSB = DAG.ComputeNumSignBits(N->getOperand(1));
> -
> - APInt HighMask = APInt::getHighBitsSet(OuterBitSize, InnerBitSize);
> - if (DAG.MaskedValueIsZero(N->getOperand(0), HighMask) &&
> - DAG.MaskedValueIsZero(N->getOperand(1), HighMask)) {
> - // The inputs are both zero-extended.
> - if (HasUMUL_LOHI) {
> - // We can emit a umul_lohi.
> - Lo = DAG.getNode(ISD::UMUL_LOHI, dl, DAG.getVTList(NVT, NVT), LL, RL);
> - Hi = SDValue(Lo.getNode(), 1);
> - return;
> - }
> - if (HasMULHU) {
> - // We can emit a mulhu+mul.
> - Lo = DAG.getNode(ISD::MUL, dl, NVT, LL, RL);
> - Hi = DAG.getNode(ISD::MULHU, dl, NVT, LL, RL);
> - return;
> - }
> - }
> - if (LHSSB > InnerBitSize && RHSSB > InnerBitSize) {
> - // The input values are both sign-extended.
> - if (HasSMUL_LOHI) {
> - // We can emit a smul_lohi.
> - Lo = DAG.getNode(ISD::SMUL_LOHI, dl, DAG.getVTList(NVT, NVT), LL, RL);
> - Hi = SDValue(Lo.getNode(), 1);
> - return;
> - }
> - if (HasMULHS) {
> - // We can emit a mulhs+mul.
> - Lo = DAG.getNode(ISD::MUL, dl, NVT, LL, RL);
> - Hi = DAG.getNode(ISD::MULHS, dl, NVT, LL, RL);
> - return;
> - }
> - }
> - if (HasUMUL_LOHI) {
> - // Lo,Hi = umul LHS, RHS.
> - SDValue UMulLOHI = DAG.getNode(ISD::UMUL_LOHI, dl,
> - DAG.getVTList(NVT, NVT), LL, RL);
> - Lo = UMulLOHI;
> - Hi = UMulLOHI.getValue(1);
> - RH = DAG.getNode(ISD::MUL, dl, NVT, LL, RH);
> - LH = DAG.getNode(ISD::MUL, dl, NVT, LH, RL);
> - Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, RH);
> - Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, LH);
> - return;
> - }
> - if (HasMULHU) {
> - Lo = DAG.getNode(ISD::MUL, dl, NVT, LL, RL);
> - Hi = DAG.getNode(ISD::MULHU, dl, NVT, LL, RL);
> - RH = DAG.getNode(ISD::MUL, dl, NVT, LL, RH);
> - LH = DAG.getNode(ISD::MUL, dl, NVT, LH, RL);
> - Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, RH);
> - Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, LH);
> - return;
> - }
> - }
> + SDValue LL, LH, RL, RH;
> + GetExpandedInteger(N->getOperand(0), LL, LH);
> + GetExpandedInteger(N->getOperand(1), RL, RH);
> +
> + if (TLI.expandMUL(N, Lo, Hi, NVT, DAG, LL, LH, RL, RH))
> + return;
>
> // If nothing else, we can make a libcall.
> RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL;
> diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp
> index 82e5ae8..dc4a219 100644
> --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp
> +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp
> @@ -2682,3 +2682,110 @@ verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const {
>
> return false;
> }
> +
> +//===----------------------------------------------------------------------===//
> +// Legalization Utilities
> +//===----------------------------------------------------------------------===//
> +
> +bool TargetLowering::expandMUL(SDNode *N, SDValue &Lo, SDValue &Hi, EVT HiLoVT,
> + SelectionDAG &DAG, SDValue LL, SDValue LH,
> + SDValue RL, SDValue RH) const {
> + EVT VT = N->getValueType(0);
> + SDLoc dl(N);
> +
> + bool HasMULHS = isOperationLegalOrCustom(ISD::MULHS, HiLoVT);
> + bool HasMULHU = isOperationLegalOrCustom(ISD::MULHU, HiLoVT);
> + bool HasSMUL_LOHI = isOperationLegalOrCustom(ISD::SMUL_LOHI, HiLoVT);
> + bool HasUMUL_LOHI = isOperationLegalOrCustom(ISD::UMUL_LOHI, HiLoVT);
> + if (HasMULHU || HasMULHS || HasUMUL_LOHI || HasSMUL_LOHI) {
> + unsigned OuterBitSize = VT.getSizeInBits();
> + unsigned InnerBitSize = HiLoVT.getSizeInBits();
> + unsigned LHSSB = DAG.ComputeNumSignBits(N->getOperand(0));
> + unsigned RHSSB = DAG.ComputeNumSignBits(N->getOperand(1));
> +
> + // LL, LH, RL, and RH must be either all NULL or all set to a value.
> + assert((LL.getNode() && LH.getNode() && RL.getNode() && RH.getNode()) ||
> + (!LL.getNode() && !LH.getNode() && !RL.getNode() && !RH.getNode()));
> +
> + if (!LL.getNode() && !RL.getNode() &&
> + isOperationLegalOrCustom(ISD::TRUNCATE, HiLoVT)) {
> + LL = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, N->getOperand(0));
> + RL = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, N->getOperand(1));
> + }
> +
> + if (!LL.getNode())
> + return false;
> +
> + APInt HighMask = APInt::getHighBitsSet(OuterBitSize, InnerBitSize);
> + if (DAG.MaskedValueIsZero(N->getOperand(0), HighMask) &&
> + DAG.MaskedValueIsZero(N->getOperand(1), HighMask)) {
> + // The inputs are both zero-extended.
> + if (HasUMUL_LOHI) {
> + // We can emit a umul_lohi.
> + Lo = DAG.getNode(ISD::UMUL_LOHI, dl,
> + DAG.getVTList(HiLoVT, HiLoVT), LL, RL);
> + Hi = SDValue(Lo.getNode(), 1);
> + return true;
> + }
> + if (HasMULHU) {
> + // We can emit a mulhu+mul.
> + Lo = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RL);
> + Hi = DAG.getNode(ISD::MULHU, dl, HiLoVT, LL, RL);
> + return true;
> + }
> + }
> + if (LHSSB > InnerBitSize && RHSSB > InnerBitSize) {
> + // The input values are both sign-extended.
> + if (HasSMUL_LOHI) {
> + // We can emit a smul_lohi.
> + Lo = DAG.getNode(ISD::SMUL_LOHI, dl,
> + DAG.getVTList(HiLoVT, HiLoVT), LL, RL);
> + Hi = SDValue(Lo.getNode(), 1);
> + return true;
> + }
> + if (HasMULHS) {
> + // We can emit a mulhs+mul.
> + Lo = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RL);
> + Hi = DAG.getNode(ISD::MULHS, dl, HiLoVT, LL, RL);
> + return true;
> + }
> + }
> +
> + if (!LH.getNode() && !RH.getNode() &&
> + isOperationLegalOrCustom(ISD::SRL, VT) &&
> + isOperationLegalOrCustom(ISD::TRUNCATE, HiLoVT)) {
> + unsigned ShiftAmt = VT.getSizeInBits() - HiLoVT.getSizeInBits();
> + SDValue Shift = DAG.getConstant(ShiftAmt, getShiftAmountTy(VT));
> + LH = DAG.getNode(ISD::SRL, dl, VT, N->getOperand(0), Shift);
> + LH = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, LH);
> + RH = DAG.getNode(ISD::SRL, dl, VT, N->getOperand(1), Shift);
> + RH = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, RH);
> + }
> +
> + if (!LH.getNode())
> + return false;
> +
> + if (HasUMUL_LOHI) {
> + // Lo,Hi = umul LHS, RHS.
> + SDValue UMulLOHI = DAG.getNode(ISD::UMUL_LOHI, dl,
> + DAG.getVTList(HiLoVT, HiLoVT), LL, RL);
> + Lo = UMulLOHI;
> + Hi = UMulLOHI.getValue(1);
> + RH = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RH);
> + LH = DAG.getNode(ISD::MUL, dl, HiLoVT, LH, RL);
> + Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, RH);
> + Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, LH);
> + return true;
> + }
> + if (HasMULHU) {
> + Lo = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RL);
> + Hi = DAG.getNode(ISD::MULHU, dl, HiLoVT, LL, RL);
> + RH = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RH);
> + LH = DAG.getNode(ISD::MUL, dl, HiLoVT, LH, RL);
> + Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, RH);
> + Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, LH);
> + return true;
> + }
> + }
> + return false;
> +}
> --
> 1.8.1.5
>
> From 6d0c42f9efad75990293d3955d068b64f5edd857 Mon Sep 17 00:00:00 2001
> From: Tom Stellard <thomas.stellard at amd.com>
> Date: Fri, 7 Feb 2014 14:59:37 -0500
> Subject: [PATCH 2/2] SelectionDAG: Use helper function to improve legalization
> of ISD::MUL
>
> The TargetLowering::expandMUL() helper contains lowering code extracted
> from the DAGTypeLegalizer and allows the SelectionDAGLegalizer to expand more
> ISD::MUL patterns without having to use a library call.
> ---
> lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 17 +++++++++
> test/CodeGen/R600/mul.ll | 63 +++++++++++++++++++++++---------
> 2 files changed, 62 insertions(+), 18 deletions(-)
>
> diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
> index 74c01ca..667ad0f 100644
> --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
> +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
> @@ -3490,6 +3490,23 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node) {
> Node->getOperand(1)));
> break;
> }
> +
> + SDValue Lo, Hi;
> + EVT HalfType = VT.getHalfSizedIntegerVT(*DAG.getContext());
> + if (TLI.isOperationLegalOrCustom(ISD::ZERO_EXTEND, VT) &&
> + TLI.isOperationLegalOrCustom(ISD::ANY_EXTEND, VT) &&
> + TLI.isOperationLegalOrCustom(ISD::SHL, VT) &&
> + TLI.isOperationLegalOrCustom(ISD::OR, VT) &&
> + TLI.expandMUL(Node, Lo, Hi, HalfType, DAG)) {
> + Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Lo);
> + Hi = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Hi);
> + SDValue Shift = DAG.getConstant(HalfType.getSizeInBits(),
> + TLI.getShiftAmountTy(HalfType));
> + Hi = DAG.getNode(ISD::SHL, dl, VT, Hi, Shift);
> + Results.push_back(DAG.getNode(ISD::OR, dl, VT, Lo, Hi));
> + break;
> + }
> +
> Tmp1 = ExpandIntLibCall(Node, false,
> RTLIB::MUL_I8,
> RTLIB::MUL_I16, RTLIB::MUL_I32,
> diff --git a/test/CodeGen/R600/mul.ll b/test/CodeGen/R600/mul.ll
> index 8c27e28..5926700 100644
> --- a/test/CodeGen/R600/mul.ll
> +++ b/test/CodeGen/R600/mul.ll
> @@ -1,15 +1,14 @@
> -; RUN: llc < %s -march=r600 -mcpu=redwood | FileCheck --check-prefix=EG-CHECK %s
> -; RUN: llc < %s -march=r600 -mcpu=verde -verify-machineinstrs | FileCheck --check-prefix=SI-CHECK %s
> +; RUN: llc < %s -march=r600 -mcpu=redwood | FileCheck --check-prefix=EG %s --check-prefix=FUNC
> +; RUN: llc < %s -march=r600 -mcpu=verde -verify-machineinstrs | FileCheck --check-prefix=SI --check-prefix=FUNC %s
>
> ; mul24 and mad24 are affected
>
> -;EG-CHECK: @test2
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;FUNC-LABEL: @test2
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
>
> -;SI-CHECK: @test2
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
>
> define void @test2(<2 x i32> addrspace(1)* %out, <2 x i32> addrspace(1)* %in) {
> %b_ptr = getelementptr <2 x i32> addrspace(1)* %in, i32 1
> @@ -20,17 +19,16 @@ define void @test2(<2 x i32> addrspace(1)* %out, <2 x i32> addrspace(1)* %in) {
> ret void
> }
>
> -;EG-CHECK: @test4
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> -;EG-CHECK: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;FUNC-LABEL: @test4
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
> +;EG: MULLO_INT {{\*? *}}T{{[0-9]+\.[XYZW], T[0-9]+\.[XYZW], T[0-9]+\.[XYZW]}}
>
> -;SI-CHECK: @test4
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> -;SI-CHECK: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
> +;SI: V_MUL_LO_I32 v{{[0-9]+, v[0-9]+, v[0-9]+}}
>
> define void @test4(<4 x i32> addrspace(1)* %out, <4 x i32> addrspace(1)* %in) {
> %b_ptr = getelementptr <4 x i32> addrspace(1)* %in, i32 1
> @@ -40,3 +38,32 @@ define void @test4(<4 x i32> addrspace(1)* %out, <4 x i32> addrspace(1)* %in) {
> store <4 x i32> %result, <4 x i32> addrspace(1)* %out
> ret void
> }
> +
> +; This 64-bit multiply should just use MUL_HI and MUL_LO, since the top
> +; 32-bits of both arguments are sign bits.
> +; FUNC-LABEL: @mul64_sext_c
> +; EG-DAG: MULLO_INT
> +; EG-DAG: MULHI_INT
> +; SI-DAG: V_MUL_LO_I32
> +; SI-DAG: V_MUL_HI_I32
> +define void @mul64_sext_c(i64 addrspace(1)* %out, i32 %in) {
> +entry:
> + %0 = sext i32 %in to i64
> + %1 = mul i64 %0, 80
> + store i64 %1, i64 addrspace(1)* %out
> + ret void
> +}
> +
> +; A standard 64-bit multiply. The expansion should be around 6 instructions.
> +; It would be difficult to match the expansion correctly without writing
> +; a really complicated list of FileCheck expressions. I don't want
> +; to confuse people who may 'break' this test with a correct optimization,
> +; so this test just uses FUNC-LABEL to make sure the compiler does not
> +; crash with a 'failed to select' error.
> +; FUNC-LABEL: @mul64
> +define void @mul64(i64 addrspace(1)* %out, i64 %a, i64 %b) {
> +entry:
> + %0 = mul i64 %a, %b
> + store i64 %0, i64 addrspace(1)* %out
> + ret void
> +}
> --
> 1.8.1.5
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list