mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-23 20:29:30 +00:00
r188163 used CLC to implement memcmp. Code that compares the result directly against zero can test the CC value produced by CLC, but code that needs an integer result must use IPM. The sequence I'd used was: ipm <reg> sll <reg>, 2 sra <reg>, 30 but I'd forgotten that this inverts the order, so that CC==1 ("less") becomes an integer greater than zero, and CC==2 ("greater") becomes an integer less than zero. This sequence should only be used if the CLC arguments are reversed to compensate. The problem then is that the branch condition must also be reversed when testing the CLC result directly. Rather than do that, I went for a different sequence that works with the natural CLC order: ipm <reg> srl <reg>, 28 rll <reg>, <reg>, 31 One advantage of this is that it doesn't clobber CC. A disadvantage is that any sign extension to 64 bits must be done separately, rather than being folded into the shifts. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188538 91177308-0d34-0410-b5e6-96231b3b80d8
156 lines
6.4 KiB
C++
156 lines
6.4 KiB
C++
//===-- 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();
|
|
}
|
|
|
|
// Handle a memset of 1, 2, 4 or 8 bytes with the operands given by
|
|
// Chain, Dst, ByteVal and Size. These cases are expected to use
|
|
// MVI, MVHHI, MVHI and MVGHI respectively.
|
|
static SDValue memsetStore(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
|
|
SDValue Dst, uint64_t ByteVal, uint64_t Size,
|
|
unsigned Align,
|
|
MachinePointerInfo DstPtrInfo) {
|
|
uint64_t StoreVal = ByteVal;
|
|
for (unsigned I = 1; I < Size; ++I)
|
|
StoreVal |= ByteVal << (I * 8);
|
|
return DAG.getStore(Chain, DL,
|
|
DAG.getConstant(StoreVal, MVT::getIntegerVT(Size * 8)),
|
|
Dst, DstPtrInfo, false, false, Align);
|
|
}
|
|
|
|
SDValue SystemZSelectionDAGInfo::
|
|
EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
|
|
SDValue Dst, SDValue Byte, SDValue Size,
|
|
unsigned Align, bool IsVolatile,
|
|
MachinePointerInfo DstPtrInfo) const {
|
|
EVT DstVT = Dst.getValueType();
|
|
|
|
if (IsVolatile)
|
|
return SDValue();
|
|
|
|
if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
|
|
uint64_t Bytes = CSize->getZExtValue();
|
|
if (Bytes == 0)
|
|
return SDValue();
|
|
if (ConstantSDNode *CByte = dyn_cast<ConstantSDNode>(Byte)) {
|
|
// Handle cases that can be done using at most two of
|
|
// MVI, MVHI, MVHHI and MVGHI. The latter two can only be
|
|
// used if ByteVal is all zeros or all ones; in other casees,
|
|
// we can move at most 2 halfwords.
|
|
uint64_t ByteVal = CByte->getZExtValue();
|
|
if (ByteVal == 0 || ByteVal == 255 ?
|
|
Bytes <= 16 && CountPopulation_64(Bytes) <= 2 :
|
|
Bytes <= 4) {
|
|
unsigned Size1 = Bytes == 16 ? 8 : 1 << findLastSet(Bytes);
|
|
unsigned Size2 = Bytes - Size1;
|
|
SDValue Chain1 = memsetStore(DAG, DL, Chain, Dst, ByteVal, Size1,
|
|
Align, DstPtrInfo);
|
|
if (Size2 == 0)
|
|
return Chain1;
|
|
Dst = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
|
|
DAG.getConstant(Size1, DstVT));
|
|
DstPtrInfo = DstPtrInfo.getWithOffset(Size1);
|
|
SDValue Chain2 = memsetStore(DAG, DL, Chain, Dst, ByteVal, Size2,
|
|
std::min(Align, Size1), DstPtrInfo);
|
|
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chain1, Chain2);
|
|
}
|
|
} else {
|
|
// Handle one and two bytes using STC.
|
|
if (Bytes <= 2) {
|
|
SDValue Chain1 = DAG.getStore(Chain, DL, Byte, Dst, DstPtrInfo,
|
|
false, false, Align);
|
|
if (Bytes == 1)
|
|
return Chain1;
|
|
SDValue Dst2 = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
|
|
DAG.getConstant(1, DstVT));
|
|
SDValue Chain2 = DAG.getStore(Chain, DL, Byte, Dst2,
|
|
DstPtrInfo.getWithOffset(1),
|
|
false, false, 1);
|
|
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chain1, Chain2);
|
|
}
|
|
}
|
|
assert(Bytes >= 2 && "Should have dealt with 0- and 1-byte cases already");
|
|
if (Bytes <= 0x101) {
|
|
// Copy the byte to the first location and then use MVC to copy
|
|
// it to the rest.
|
|
Chain = DAG.getStore(Chain, DL, Byte, Dst, DstPtrInfo,
|
|
false, false, Align);
|
|
SDValue Dst2 = DAG.getNode(ISD::ADD, DL, DstVT, Dst,
|
|
DAG.getConstant(1, DstVT));
|
|
return DAG.getNode(SystemZISD::MVC, DL, MVT::Other, Chain, Dst2, Dst,
|
|
DAG.getConstant(Bytes - 1, MVT::i32));
|
|
}
|
|
}
|
|
return SDValue();
|
|
}
|
|
|
|
std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::
|
|
EmitTargetCodeForMemcmp(SelectionDAG &DAG, SDLoc DL, SDValue Chain,
|
|
SDValue Src1, SDValue Src2, SDValue Size,
|
|
MachinePointerInfo Op1PtrInfo,
|
|
MachinePointerInfo Op2PtrInfo) const {
|
|
if (ConstantSDNode *CSize = dyn_cast<ConstantSDNode>(Size)) {
|
|
uint64_t Bytes = CSize->getZExtValue();
|
|
if (Bytes >= 1 && Bytes <= 0x100) {
|
|
// A single CLC.
|
|
SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
Chain = DAG.getNode(SystemZISD::CLC, DL, VTs, Chain,
|
|
Src1, Src2, Size);
|
|
SDValue Glue = Chain.getValue(1);
|
|
// IPM inserts the CC value into bits 29 and 28, with 0 meaning "equal",
|
|
// 1 meaning "less" and 2 meaning "greater". Bits 30 and 31 are zero.
|
|
// Convert this into an integer that is respectively equal, less
|
|
// or greater than 0.
|
|
SDValue IPM = DAG.getNode(SystemZISD::IPM, DL, MVT::i32, Glue);
|
|
SDValue SRL = DAG.getNode(ISD::SRL, DL, MVT::i32, IPM,
|
|
DAG.getConstant(28, MVT::i32));
|
|
SDValue ROTL = DAG.getNode(ISD::ROTL, DL, MVT::i32, SRL,
|
|
DAG.getConstant(31, MVT::i32));
|
|
return std::make_pair(ROTL, Chain);
|
|
}
|
|
}
|
|
return std::make_pair(SDValue(), SDValue());
|
|
}
|