mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-17 08:57:34 +00:00
Add shifts and reg-imm address matching
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75927 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a51752cbea
commit
9e4816e09f
@ -50,6 +50,8 @@ namespace {
|
||||
|
||||
void printOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
void printRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier = 0);
|
||||
bool printInstruction(const MachineInstr *MI); // autogenerated.
|
||||
void printMachineInstruction(const MachineInstr * MI);
|
||||
|
||||
@ -167,7 +169,7 @@ void SystemZAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
|
||||
}
|
||||
|
||||
void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier) {
|
||||
const char* Modifier) {
|
||||
const MachineOperand &MO = MI->getOperand(OpNum);
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
@ -185,3 +187,19 @@ void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
|
||||
assert(0 && "Not implemented yet!");
|
||||
}
|
||||
}
|
||||
|
||||
void SystemZAsmPrinter::printRIAddrOperand(const MachineInstr *MI, int OpNum,
|
||||
const char* Modifier) {
|
||||
const MachineOperand &Base = MI->getOperand(OpNum);
|
||||
|
||||
// Print displacement operand.
|
||||
printOperand(MI, OpNum+1);
|
||||
|
||||
// Print base operand (if any)
|
||||
if (!(Base.isReg() && Base.getReg() == SystemZ::R0D)) {
|
||||
O << '(';
|
||||
printOperand(MI, OpNum);
|
||||
O << ')';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,8 @@ namespace {
|
||||
|
||||
private:
|
||||
SDNode *Select(SDValue Op);
|
||||
bool SelectAddrRI(const SDValue& Op, SDValue& Addr,
|
||||
SDValue &Base, SDValue &Disp);
|
||||
|
||||
#ifndef NDEBUG
|
||||
unsigned Indent;
|
||||
@ -82,6 +84,91 @@ FunctionPass *llvm::createSystemZISelDag(SystemZTargetMachine &TM,
|
||||
return new SystemZDAGToDAGISel(TM, OptLevel);
|
||||
}
|
||||
|
||||
/// isImmSExt20 - This method tests to see if the node is either a 32-bit
|
||||
/// or 64-bit immediate, and if the value can be accurately represented as a
|
||||
/// sign extension from a 20-bit value. If so, this returns true and the
|
||||
/// immediate.
|
||||
static bool isImmSExt20(SDNode *N, int32_t &Imm) {
|
||||
if (N->getOpcode() != ISD::Constant)
|
||||
return false;
|
||||
|
||||
Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
|
||||
if (Imm >= -524288 && Imm <= 524287) {
|
||||
if (N->getValueType(0) == MVT::i32)
|
||||
return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
else
|
||||
return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isImmSExt20(SDValue Op, int32_t &Imm) {
|
||||
return isImmSExt20(Op.getNode(), Imm);
|
||||
}
|
||||
|
||||
/// Returns true if the address can be represented by a base register plus
|
||||
/// a signed 20-bit displacement [r+imm].
|
||||
bool SystemZDAGToDAGISel::SelectAddrRI(const SDValue& Op, SDValue& Addr,
|
||||
SDValue &Base, SDValue &Disp) {
|
||||
// FIXME dl should come from parent load or store, not from address
|
||||
DebugLoc dl = Addr.getDebugLoc();
|
||||
MVT VT = Addr.getValueType();
|
||||
|
||||
if (Addr.getOpcode() == ISD::ADD) {
|
||||
int32_t Imm = 0;
|
||||
if (isImmSExt20(Addr.getOperand(1), Imm)) {
|
||||
Disp = CurDAG->getTargetConstant(Imm, MVT::i32);
|
||||
if (FrameIndexSDNode *FI =
|
||||
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
|
||||
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), VT);
|
||||
} else {
|
||||
Base = Addr.getOperand(0);
|
||||
}
|
||||
return true; // [r+i]
|
||||
}
|
||||
} else if (Addr.getOpcode() == ISD::OR) {
|
||||
int32_t Imm = 0;
|
||||
if (isImmSExt20(Addr.getOperand(1), Imm)) {
|
||||
// If this is an or of disjoint bitfields, we can codegen this as an add
|
||||
// (for better address arithmetic) if the LHS and RHS of the OR are
|
||||
// provably disjoint.
|
||||
APInt LHSKnownZero, LHSKnownOne;
|
||||
CurDAG->ComputeMaskedBits(Addr.getOperand(0),
|
||||
APInt::getAllOnesValue(Addr.getOperand(0)
|
||||
.getValueSizeInBits()),
|
||||
LHSKnownZero, LHSKnownOne);
|
||||
|
||||
if ((LHSKnownZero.getZExtValue()|~(uint64_t)Imm) == ~0ULL) {
|
||||
// If all of the bits are known zero on the LHS or RHS, the add won't
|
||||
// carry.
|
||||
Base = Addr.getOperand(0);
|
||||
Disp = CurDAG->getTargetConstant(Imm, MVT::i32);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
|
||||
// Loading from a constant address.
|
||||
|
||||
// If this address fits entirely in a 20-bit sext immediate field, codegen
|
||||
// this as "d(r0)"
|
||||
int32_t Imm;
|
||||
if (isImmSExt20(CN, Imm)) {
|
||||
Disp = CurDAG->getTargetConstant(Imm, MVT::i32);
|
||||
Base = CurDAG->getRegister(SystemZ::R0D, MVT::i64);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Disp = CurDAG->getTargetConstant(0, MVT::i32);
|
||||
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Addr))
|
||||
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), VT);
|
||||
else
|
||||
Base = Addr;
|
||||
return true; // [r+0]
|
||||
}
|
||||
|
||||
|
||||
/// InstructionSelect - This callback is invoked by
|
||||
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
||||
|
@ -45,6 +45,10 @@ SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) :
|
||||
// Compute derived properties from the register classes
|
||||
computeRegisterProperties();
|
||||
|
||||
// Set shifts properties
|
||||
setShiftAmountFlavor(Extend);
|
||||
setShiftAmountType(MVT::i32);
|
||||
|
||||
// Provide all sorts of operation actions
|
||||
|
||||
setStackPointerRegisterToSaveRestore(SystemZ::R15D);
|
||||
|
@ -61,9 +61,11 @@ bool SystemZInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
|
||||
|
||||
if (CommonRC) {
|
||||
unsigned Opc;
|
||||
if (CommonRC == &SystemZ::GR64RegClass) {
|
||||
if (CommonRC == &SystemZ::GR64RegClass ||
|
||||
CommonRC == &SystemZ::ADDR64RegClass) {
|
||||
Opc = SystemZ::MOV64rr;
|
||||
} else if (CommonRC == &SystemZ::GR32RegClass) {
|
||||
} else if (CommonRC == &SystemZ::GR32RegClass ||
|
||||
CommonRC == &SystemZ::ADDR32RegClass) {
|
||||
Opc = SystemZ::MOV32rr;
|
||||
} else {
|
||||
return false;
|
||||
@ -73,6 +75,20 @@ bool SystemZInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SrcRC == &SystemZ::GR64RegClass &&
|
||||
DestRC == &SystemZ::ADDR64RegClass) ||
|
||||
(DestRC == &SystemZ::GR64RegClass &&
|
||||
SrcRC == &SystemZ::ADDR64RegClass)) {
|
||||
BuildMI(MBB, I, DL, get(SystemZ::MOV64rr), DestReg).addReg(SrcReg);
|
||||
return true;
|
||||
} else if ((SrcRC == &SystemZ::GR32RegClass &&
|
||||
DestRC == &SystemZ::ADDR32RegClass) ||
|
||||
(DestRC == &SystemZ::GR32RegClass &&
|
||||
SrcRC == &SystemZ::ADDR32RegClass)) {
|
||||
BuildMI(MBB, I, DL, get(SystemZ::MOV32rr), DestReg).addReg(SrcReg);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,27 @@ def i64hi32 : PatLeaf<(i64 imm), [{
|
||||
return ((N->getZExtValue() & 0xFFFFFFFF00000000ULL) == N->getZExtValue());
|
||||
}], HI32>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SystemZ Operand Definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Address operands
|
||||
|
||||
// riaddr := reg + imm
|
||||
def riaddr32 : Operand<i32>,
|
||||
ComplexPattern<i32, 2, "SelectAddrRI", []> {
|
||||
let PrintMethod = "printRIAddrOperand";
|
||||
let MIOperandInfo = (ops ADDR32:$base, i32imm:$disp);
|
||||
}
|
||||
|
||||
def riaddr : Operand<i64>,
|
||||
ComplexPattern<i64, 2, "SelectAddrRI", []> {
|
||||
let PrintMethod = "printRIAddrOperand";
|
||||
let MIOperandInfo = (ops ADDR64:$base, i32imm:$disp);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Control Flow Instructions...
|
||||
//
|
||||
@ -312,6 +333,48 @@ def XOR64rihi32 : Pseudo<(outs GR64:$dst), (ins GR64:$src1, i64imm:$src2),
|
||||
} // Defs = [PSW]
|
||||
} // isTwoAddress = 1
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Shifts
|
||||
|
||||
let isTwoAddress = 1 in
|
||||
def SRL32rri : Pseudo<(outs GR32:$dst), (ins GR32:$src, riaddr32:$amt),
|
||||
"srl\t{$src, $amt}",
|
||||
[(set GR32:$dst, (srl GR32:$src, riaddr32:$amt))]>;
|
||||
def SRL64rri : Pseudo<(outs GR64:$dst), (ins GR64:$src, riaddr:$amt),
|
||||
"srlg\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (srl GR64:$src, (i32 (trunc riaddr:$amt))))]>;
|
||||
def SRLA64ri : Pseudo<(outs GR64:$dst), (ins GR64:$src, i32imm:$amt),
|
||||
"srlg\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (srl GR64:$src, (i32 imm:$amt)))]>;
|
||||
|
||||
let isTwoAddress = 1 in
|
||||
def SHL32rri : Pseudo<(outs GR32:$dst), (ins GR32:$src, riaddr32:$amt),
|
||||
"sll\t{$src, $amt}",
|
||||
[(set GR32:$dst, (shl GR32:$src, riaddr32:$amt))]>;
|
||||
def SHL64rri : Pseudo<(outs GR64:$dst), (ins GR64:$src, riaddr:$amt),
|
||||
"sllg\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (shl GR64:$src, (i32 (trunc riaddr:$amt))))]>;
|
||||
def SHL64ri : Pseudo<(outs GR64:$dst), (ins GR64:$src, i32imm:$amt),
|
||||
"sllg\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (shl GR64:$src, (i32 imm:$amt)))]>;
|
||||
|
||||
|
||||
let Defs = [PSW] in {
|
||||
let isTwoAddress = 1 in
|
||||
def SRA32rri : Pseudo<(outs GR32:$dst), (ins GR32:$src, riaddr32:$amt),
|
||||
"sra\t{$src, $amt}",
|
||||
[(set GR32:$dst, (sra GR32:$src, riaddr32:$amt)),
|
||||
(implicit PSW)]>;
|
||||
def SRA64rri : Pseudo<(outs GR64:$dst), (ins GR64:$src, riaddr:$amt),
|
||||
"srag\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (sra GR64:$src, (i32 (trunc riaddr:$amt)))),
|
||||
(implicit PSW)]>;
|
||||
def SRA64ri : Pseudo<(outs GR64:$dst), (ins GR64:$src, i32imm:$amt),
|
||||
"srag\t{$dst, $src, $amt}",
|
||||
[(set GR64:$dst, (sra GR64:$src, (i32 imm:$amt))),
|
||||
(implicit PSW)]>;
|
||||
} // Defs = [PSW]
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-Instruction Patterns.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -127,6 +127,33 @@ def GR32 : RegisterClass<"SystemZ", [i32], 32,
|
||||
}];
|
||||
}
|
||||
|
||||
/// Registers used to generate address. Everything except R0.
|
||||
def ADDR32 : RegisterClass<"SystemZ", [i32], 32,
|
||||
// Volatile registers
|
||||
[R1W, R2W, R3W, R4W, R5W, R6W, R7W, R8W, R9W, R10W, R12W, R13W,
|
||||
// Frame pointer, sometimes allocable
|
||||
R11W,
|
||||
// Volatile, but not allocable
|
||||
R14W, R15W]>
|
||||
{
|
||||
let MethodProtos = [{
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
ADDR32Class::iterator
|
||||
ADDR32Class::allocation_order_end(const MachineFunction &MF) const {
|
||||
const TargetMachine &TM = MF.getTarget();
|
||||
const TargetRegisterInfo *RI = TM.getRegisterInfo();
|
||||
// Depending on whether the function uses frame pointer or not, last 2 or 3
|
||||
// registers on the list above are reserved
|
||||
if (RI->hasFP(MF))
|
||||
return end()-3;
|
||||
else
|
||||
return end()-2;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def GR64 : RegisterClass<"SystemZ", [i64], 64,
|
||||
// Volatile registers
|
||||
[R0D, R1D, R2D, R3D, R4D, R5D, R6D, R7D, R8D, R9D, R10D, R12D, R13D,
|
||||
@ -154,6 +181,33 @@ def GR64 : RegisterClass<"SystemZ", [i64], 64,
|
||||
}];
|
||||
}
|
||||
|
||||
def ADDR64 : RegisterClass<"SystemZ", [i64], 64,
|
||||
// Volatile registers
|
||||
[R1D, R2D, R3D, R4D, R5D, R6D, R7D, R8D, R9D, R10D, R12D, R13D,
|
||||
// Frame pointer, sometimes allocable
|
||||
R11D,
|
||||
// Volatile, but not allocable
|
||||
R14D, R15D]>
|
||||
{
|
||||
let SubRegClassList = [ADDR32];
|
||||
let MethodProtos = [{
|
||||
iterator allocation_order_end(const MachineFunction &MF) const;
|
||||
}];
|
||||
let MethodBodies = [{
|
||||
ADDR64Class::iterator
|
||||
ADDR64Class::allocation_order_end(const MachineFunction &MF) const {
|
||||
const TargetMachine &TM = MF.getTarget();
|
||||
const TargetRegisterInfo *RI = TM.getRegisterInfo();
|
||||
// Depending on whether the function uses frame pointer or not, last 2 or 3
|
||||
// registers on the list above are reserved
|
||||
if (RI->hasFP(MF))
|
||||
return end()-3;
|
||||
else
|
||||
return end()-2;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def FP64 : RegisterClass<"SystemZ", [f64], 64,
|
||||
[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>;
|
||||
|
||||
|
121
test/CodeGen/SystemZ/04-RetShifts.ll
Normal file
121
test/CodeGen/SystemZ/04-RetShifts.ll
Normal file
@ -0,0 +1,121 @@
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep sra | count 6
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep srag | count 3
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep srl | count 6
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep srlg | count 3
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep sll | count 6
|
||||
; RUN: llvm-as < %s | llc -march=systemz | grep sllg | count 3
|
||||
|
||||
define signext i32 @foo1(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i32 %idx, 1 ; <i32> [#uses=1]
|
||||
%shr = ashr i32 %a, %add ; <i32> [#uses=1]
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo2(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i32 %idx, 1 ; <i32> [#uses=1]
|
||||
%shr = shl i32 %a, %add ; <i32> [#uses=1]
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo3(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i32 %idx, 1 ; <i32> [#uses=1]
|
||||
%shr = lshr i32 %a, %add ; <i32> [#uses=1]
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo4(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i64 %idx, 1 ; <i64> [#uses=1]
|
||||
%shr = ashr i64 %a, %add ; <i64> [#uses=1]
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo5(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i64 %idx, 1 ; <i64> [#uses=1]
|
||||
%shr = shl i64 %a, %add ; <i64> [#uses=1]
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo6(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%add = add i64 %idx, 1 ; <i64> [#uses=1]
|
||||
%shr = lshr i64 %a, %add ; <i64> [#uses=1]
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo7(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = ashr i32 %a, 1
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo8(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = shl i32 %a, 1
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo9(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = lshr i32 %a, 1
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo10(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = ashr i32 %a, %idx
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo11(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = shl i32 %a, %idx
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i32 @foo12(i32 %a, i32 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = lshr i32 %a, %idx
|
||||
ret i32 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo13(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = ashr i64 %a, 1
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo14(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = shl i64 %a, 1
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo15(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = lshr i64 %a, 1
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo16(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = ashr i64 %a, %idx
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo17(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = shl i64 %a, %idx
|
||||
ret i64 %shr
|
||||
}
|
||||
|
||||
define signext i64 @foo18(i64 %a, i64 %idx) nounwind readnone {
|
||||
entry:
|
||||
%shr = lshr i64 %a, %idx
|
||||
ret i64 %shr
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user