mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-14 23:29:51 +00:00
[SystemZ] Use MVC for memcpy
Use MVC for memcpy in cases where a single MVC is enough. Using MVC is a win for longer copies too, but I'll leave that for later. llvm-svn: 185802
This commit is contained in:
parent
72e9abbaf6
commit
537b8d7bec
@ -22,6 +22,7 @@ add_llvm_target(SystemZCodeGen
|
||||
SystemZLongBranch.cpp
|
||||
SystemZMCInstLower.cpp
|
||||
SystemZRegisterInfo.cpp
|
||||
SystemZSelectionDAGInfo.cpp
|
||||
SystemZSubtarget.cpp
|
||||
SystemZTargetMachine.cpp
|
||||
)
|
||||
|
@ -241,6 +241,12 @@ SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm)
|
||||
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
||||
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
|
||||
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
||||
|
||||
// We want to use MVC in preference to even a single load/store pair.
|
||||
MaxStoresPerMemcpy = 0;
|
||||
MaxStoresPerMemcpyOptSize = 0;
|
||||
MaxStoresPerMemmove = 0;
|
||||
MaxStoresPerMemmoveOptSize = 0;
|
||||
}
|
||||
|
||||
bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
|
||||
@ -1579,6 +1585,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
OPCODE(SDIVREM64);
|
||||
OPCODE(UDIVREM32);
|
||||
OPCODE(UDIVREM64);
|
||||
OPCODE(MVC);
|
||||
OPCODE(ATOMIC_SWAPW);
|
||||
OPCODE(ATOMIC_LOADW_ADD);
|
||||
OPCODE(ATOMIC_LOADW_SUB);
|
||||
@ -2143,6 +2150,26 @@ SystemZTargetLowering::emitExt128(MachineInstr *MI,
|
||||
return MBB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
SystemZTargetLowering::emitMVCWrapper(MachineInstr *MI,
|
||||
MachineBasicBlock *MBB) const {
|
||||
const SystemZInstrInfo *TII = TM.getInstrInfo();
|
||||
DebugLoc DL = MI->getDebugLoc();
|
||||
|
||||
MachineOperand DestBase = MI->getOperand(0);
|
||||
uint64_t DestDisp = MI->getOperand(1).getImm();
|
||||
MachineOperand SrcBase = MI->getOperand(2);
|
||||
uint64_t SrcDisp = MI->getOperand(3).getImm();
|
||||
uint64_t Length = MI->getOperand(4).getImm();
|
||||
|
||||
BuildMI(*MBB, MI, DL, TII->get(SystemZ::MVC))
|
||||
.addOperand(DestBase).addImm(DestDisp).addImm(Length)
|
||||
.addOperand(SrcBase).addImm(SrcDisp);
|
||||
|
||||
MI->eraseFromParent();
|
||||
return MBB;
|
||||
}
|
||||
|
||||
MachineBasicBlock *SystemZTargetLowering::
|
||||
EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
|
||||
switch (MI->getOpcode()) {
|
||||
@ -2376,6 +2403,8 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
|
||||
MI->getOperand(1).getMBB()))
|
||||
MI->eraseFromParent();
|
||||
return MBB;
|
||||
case SystemZ::MVCWrapper:
|
||||
return emitMVCWrapper(MI, MBB);
|
||||
default:
|
||||
llvm_unreachable("Unexpected instr type to insert");
|
||||
}
|
||||
|
@ -73,6 +73,13 @@ namespace SystemZISD {
|
||||
UDIVREM32,
|
||||
UDIVREM64,
|
||||
|
||||
// Use MVC to copy bytes from one memory location to another.
|
||||
// The first operand is the target address, the second operand is the
|
||||
// source address, and the third operand is the constant length.
|
||||
// This isn't a memory opcode because we'd need to attach two
|
||||
// MachineMemOperands rather than one.
|
||||
MVC,
|
||||
|
||||
// Wrappers around the inner loop of an 8- or 16-bit ATOMIC_SWAP or
|
||||
// ATOMIC_LOAD_<op>.
|
||||
//
|
||||
@ -221,6 +228,8 @@ private:
|
||||
unsigned BitSize) const;
|
||||
MachineBasicBlock *emitAtomicCmpSwapW(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
MachineBasicBlock *emitMVCWrapper(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -288,6 +288,12 @@ let mayLoad = 1, mayStore = 1 in
|
||||
bdaddr12only:$BD2),
|
||||
"mvc\t$BDL1, $BD2", []>;
|
||||
|
||||
let mayLoad = 1, mayStore = 1, usesCustomInserter = 1 in
|
||||
def MVCWrapper : Pseudo<(outs), (ins bdaddr12only:$dest, bdaddr12only:$src,
|
||||
imm32len8:$length),
|
||||
[(z_mvc bdaddr12only:$dest, bdaddr12only:$src,
|
||||
imm32len8:$length)]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Sign extensions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -219,6 +219,11 @@ def uimm8 : Immediate<i8, [{}], UIMM8, "U8Imm">;
|
||||
// i32 immediates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Immediates for 8-bit lengths.
|
||||
def imm32len8 : Immediate<i32, [{
|
||||
return isUInt<8>(N->getZExtValue() - 1);
|
||||
}], NOOP_SDNodeXForm, "U32Imm">;
|
||||
|
||||
// Immediates for the lower and upper 16 bits of an i32, with the other
|
||||
// bits of the i32 being zero.
|
||||
def imm32ll16 : Immediate<i32, [{
|
||||
|
@ -52,6 +52,10 @@ def SDT_ZAtomicCmpSwapW : SDTypeProfile<1, 6,
|
||||
SDTCisVT<4, i32>,
|
||||
SDTCisVT<5, i32>,
|
||||
SDTCisVT<6, i32>]>;
|
||||
def SDT_ZCopy : SDTypeProfile<0, 3,
|
||||
[SDTCisPtrTy<0>,
|
||||
SDTCisPtrTy<1>,
|
||||
SDTCisVT<2, i32>]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Node definitions
|
||||
@ -103,6 +107,9 @@ def z_atomic_loadw_umin : AtomicWOp<"ATOMIC_LOADW_UMIN">;
|
||||
def z_atomic_loadw_umax : AtomicWOp<"ATOMIC_LOADW_UMAX">;
|
||||
def z_atomic_cmp_swapw : AtomicWOp<"ATOMIC_CMP_SWAPW", SDT_ZAtomicCmpSwapW>;
|
||||
|
||||
def z_mvc : SDNode<"SystemZISD::MVC", SDT_ZCopy,
|
||||
[SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pattern fragments
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
46
lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
Normal file
46
lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
//===-- SystemZSelectionDAGInfo.cpp - SystemZ SelectionDAG Info -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SystemZSelectionDAGInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "systemz-selectiondag-info"
|
||||
#include "SystemZTargetMachine.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
SystemZSelectionDAGInfo::
|
||||
SystemZSelectionDAGInfo(const SystemZTargetMachine &TM)
|
||||
: TargetSelectionDAGInfo(TM) {
|
||||
}
|
||||
|
||||
SystemZSelectionDAGInfo::~SystemZSelectionDAGInfo() {
|
||||
}
|
||||
|
||||
SDValue SystemZSelectionDAGInfo::
|
||||
EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
|
||||
SDValue Dst, SDValue Src, SDValue Size, unsigned Align,
|
||||
bool IsVolatile, bool AlwaysInline,
|
||||
MachinePointerInfo DstPtrInfo,
|
||||
MachinePointerInfo SrcPtrInfo) const {
|
||||
if (IsVolatile)
|
||||
return SDValue();
|
||||
|
||||
if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
|
||||
uint64_t Bytes = CSize->getZExtValue();
|
||||
if (Bytes >= 1 && Bytes <= 0x100) {
|
||||
// A single MVC.
|
||||
return DAG.getNode(SystemZISD::MVC, DL, MVT::Other,
|
||||
Chain, Dst, Src, Size);
|
||||
}
|
||||
}
|
||||
return SDValue();
|
||||
}
|
40
lib/Target/SystemZ/SystemZSelectionDAGInfo.h
Normal file
40
lib/Target/SystemZ/SystemZSelectionDAGInfo.h
Normal file
@ -0,0 +1,40 @@
|
||||
//===-- SystemZSelectionDAGInfo.h - SystemZ SelectionDAG Info ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SystemZ subclass for TargetSelectionDAGInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SYSTEMZSELECTIONDAGINFO_H
|
||||
#define SYSTEMZSELECTIONDAGINFO_H
|
||||
|
||||
#include "llvm/Target/TargetSelectionDAGInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class SystemZTargetMachine;
|
||||
|
||||
class SystemZSelectionDAGInfo : public TargetSelectionDAGInfo {
|
||||
public:
|
||||
explicit SystemZSelectionDAGInfo(const SystemZTargetMachine &TM);
|
||||
~SystemZSelectionDAGInfo();
|
||||
|
||||
virtual
|
||||
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
|
||||
SDValue Dst, SDValue Src,
|
||||
SDValue Size, unsigned Align,
|
||||
bool IsVolatile, bool AlwaysInline,
|
||||
MachinePointerInfo DstPtrInfo,
|
||||
MachinePointerInfo SrcPtrInfo) const
|
||||
LLVM_OVERRIDE;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -20,10 +20,10 @@
|
||||
#include "SystemZInstrInfo.h"
|
||||
#include "SystemZRegisterInfo.h"
|
||||
#include "SystemZSubtarget.h"
|
||||
#include "SystemZSelectionDAGInfo.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetSelectionDAGInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -32,7 +32,7 @@ class SystemZTargetMachine : public LLVMTargetMachine {
|
||||
const DataLayout DL;
|
||||
SystemZInstrInfo InstrInfo;
|
||||
SystemZTargetLowering TLInfo;
|
||||
TargetSelectionDAGInfo TSInfo;
|
||||
SystemZSelectionDAGInfo TSInfo;
|
||||
SystemZFrameLowering FrameLowering;
|
||||
|
||||
public:
|
||||
|
82
test/CodeGen/SystemZ/memcpy-01.ll
Normal file
82
test/CodeGen/SystemZ/memcpy-01.ll
Normal file
@ -0,0 +1,82 @@
|
||||
; Test memcpy using MVC.
|
||||
;
|
||||
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
|
||||
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i32(i8 *nocapture, i8 *nocapture, i32, i32, i1) nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8 *nocapture, i8 *nocapture, i64, i32, i1) nounwind
|
||||
|
||||
define void @f1(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f1:
|
||||
; CHECK-NOT: %r2
|
||||
; CHECK-NOT: %r3
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8 *%dest, i8 *%src, i32 0, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f2(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f2:
|
||||
; CHECK-NOT: %r2
|
||||
; CHECK-NOT: %r3
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8 *%dest, i8 *%src, i64 0, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f3(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f3:
|
||||
; CHECK: mvc 0(1,%r2), 0(%r3)
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8 *%dest, i8 *%src, i32 1, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f4(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f4:
|
||||
; CHECK: mvc 0(1,%r2), 0(%r3)
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8 *%dest, i8 *%src, i64 1, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f5(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f5:
|
||||
; CHECK: mvc 0(256,%r2), 0(%r3)
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8 *%dest, i8 *%src, i32 256, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f6(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f6:
|
||||
; CHECK: mvc 0(256,%r2), 0(%r3)
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8 *%dest, i8 *%src, i64 256, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
; 257 bytes is too big for a single MVC. For now expect none, so that
|
||||
; the test fails and gets updated when large copies are implemented.
|
||||
define void @f7(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f7:
|
||||
; CHECK-NOT: mvc
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8 *%dest, i8 *%src, i32 257, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f8(i8 *%dest, i8 *%src) {
|
||||
; CHECK: f8:
|
||||
; CHECK-NOT: mvc
|
||||
; CHECK: br %r14
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8 *%dest, i8 *%src, i64 257, i32 1,
|
||||
i1 false)
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user