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:
Anton Korobeynikov 2009-07-16 13:43:18 +00:00
parent a51752cbea
commit 9e4816e09f
7 changed files with 366 additions and 3 deletions

View File

@ -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 << ')';
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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.
//===----------------------------------------------------------------------===//

View File

@ -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]>;

View 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
}