Add support for floating point base register + offset register addressing mode

load and store instructions.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151611 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Akira Hatanaka 2012-02-28 02:55:02 +00:00
parent 2129a0f677
commit 44b6c715ac
8 changed files with 217 additions and 4 deletions

View File

@ -30,6 +30,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@ -91,7 +92,7 @@ private:
SDNode *Select(SDNode *N);
// Complex Pattern.
bool SelectAddr(SDValue N, SDValue &Base, SDValue &Offset);
bool SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset);
// getImm - Return a target constant with the specified value.
inline SDValue getImm(const SDNode *Node, unsigned Imm) {
@ -197,7 +198,7 @@ SDNode *MipsDAGToDAGISel::getGlobalBaseReg() {
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsDAGToDAGISel::
SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
SelectAddr(SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset) {
EVT ValTy = Addr.getValueType();
// if Address is FI, get the TargetFrameIndex.
@ -256,6 +257,12 @@ SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
return true;
}
}
// If an indexed load/store can be emitted, return false.
if (const LSBaseSDNode* LS = dyn_cast<LSBaseSDNode>(Parent))
if ((LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) &&
Subtarget.hasMips32r2Or64())
return false;
}
Base = Addr;

View File

@ -261,7 +261,18 @@ MipsTargetLowering(MipsTargetMachine &TM)
bool MipsTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const {
MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy;
return SVT == MVT::i64 || SVT == MVT::i32 || SVT == MVT::i16;
switch (SVT) {
case MVT::i64:
case MVT::i32:
case MVT::i16:
return true;
case MVT::f32:
case MVT::f64:
return Subtarget->hasMips32r2Or64();
default:
return false;
}
}
EVT MipsTargetLowering::getSetCCResultType(EVT VT) const {

View File

@ -94,6 +94,24 @@ class FPStore<bits<6> op, string opstr, RegisterClass RC, Operand MemOpnd>:
!strconcat(opstr, "\t$ft, $addr"), [(store RC:$ft, addr:$addr)],
IIStore>;
// FP indexed load.
class FPIdxLoad<bits<6> funct, string opstr, RegisterClass DRC,
RegisterClass PRC, PatFrag FOp>:
FFMemIdx<funct, (outs DRC:$fd), (ins PRC:$base, PRC:$index),
!strconcat(opstr, "\t$fd, $index($base)"),
[(set DRC:$fd, (FOp (add PRC:$base, PRC:$index)))]> {
let fs = 0;
}
// FP indexed store.
class FPIdxStore<bits<6> funct, string opstr, RegisterClass DRC,
RegisterClass PRC, PatFrag FOp>:
FFMemIdx<funct, (outs), (ins DRC:$fs, PRC:$base, PRC:$index),
!strconcat(opstr, "\t$fs, $index($base)"),
[(FOp DRC:$fs, (add PRC:$base, PRC:$index))]> {
let fd = 0;
}
// Instructions that convert an FP value to 32-bit fixed point.
multiclass FFR1_W_M<bits<6> funct, string opstr> {
def _S : FFR1<funct, 16, opstr, "w.s", FGR32, FGR32>;
@ -240,6 +258,34 @@ let Predicates = [NotN64, NotMips64] in {
def SDC1 : FPStore<0x3d, "sdc1", AFGR64, mem>;
}
// Indexed loads and stores.
let Predicates = [HasMips32r2Or64] in {
def LWXC1 : FPIdxLoad<0x0, "lwxc1", FGR32, CPURegs, load_a>;
def LUXC1 : FPIdxLoad<0x5, "luxc1", FGR32, CPURegs, load_u>;
def SWXC1 : FPIdxStore<0x8, "swxc1", FGR32, CPURegs, store_a>;
def SUXC1 : FPIdxStore<0xd, "suxc1", FGR32, CPURegs, store_u>;
}
let Predicates = [HasMips32r2, NotMips64] in {
def LDXC1 : FPIdxLoad<0x1, "ldxc1", AFGR64, CPURegs, load_a>;
def SDXC1 : FPIdxStore<0x9, "sdxc1", AFGR64, CPURegs, store_a>;
}
let Predicates = [HasMips64, NotN64] in {
def LDXC164 : FPIdxLoad<0x1, "ldxc1", FGR64, CPURegs, load_a>;
def SDXC164 : FPIdxStore<0x9, "sdxc1", FGR64, CPURegs, store_a>;
}
// n64
let Predicates = [IsN64] in {
def LWXC1_P8 : FPIdxLoad<0x0, "lwxc1", FGR32, CPU64Regs, load_a>;
def LUXC1_P8 : FPIdxLoad<0x5, "luxc1", FGR32, CPU64Regs, load_u>;
def LDXC164_P8 : FPIdxLoad<0x1, "ldxc1", FGR64, CPU64Regs, load_a>;
def SWXC1_P8 : FPIdxStore<0x8, "swxc1", FGR32, CPU64Regs, store_a>;
def SUXC1_P8 : FPIdxStore<0xd, "suxc1", FGR32, CPU64Regs, store_u>;
def SDXC164_P8 : FPIdxStore<0x9, "sdxc1", FGR64, CPU64Regs, store_a>;
}
/// Floating-point Aritmetic
defm FADD : FFR2P_M<0x00, "add", fadd, 1>;
defm FDIV : FFR2P_M<0x03, "div", fdiv>;

View File

@ -308,3 +308,23 @@ class FFMADDSUB<bits<3> funct, bits<3> fmt, dag outs, dag ins, string asmstr,
let Inst{5-3} = funct;
let Inst{2-0} = fmt;
}
// FP indexed load/store instructions.
class FFMemIdx<bits<6> _funct, dag outs, dag ins, string asmstr,
list<dag> pattern> :
MipsInst<outs, ins, asmstr, pattern, NoItinerary, FrmOther>
{
bits<5> base;
bits<5> index;
bits<5> fs;
bits<5> fd;
bits<6> funct;
let Opcode = 0x13;
let Inst{25-21} = base;
let Inst{20-16} = index;
let Inst{15-11} = fs;
let Inst{10-6} = fd;
let Inst{5-0} = funct;
}

View File

@ -128,6 +128,7 @@ def HasCondMov : Predicate<"Subtarget.hasCondMov()">;
def HasMips32 : Predicate<"Subtarget.hasMips32()">;
def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">;
def HasMips64 : Predicate<"Subtarget.hasMips64()">;
def HasMips32r2Or64 : Predicate<"Subtarget.hasMips32r2Or64()">;
def NotMips64 : Predicate<"!Subtarget.hasMips64()">;
def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">;
def IsN64 : Predicate<"Subtarget.isABI_N64()">;
@ -231,7 +232,7 @@ def immZExt5 : ImmLeaf<i32, [{return Imm == (Imm & 0x1f);}]>;
// Mips Address Mode! SDNode frameindex could possibily be a match
// since load and store instructions from stack used it.
def addr : ComplexPattern<iPTR, 2, "SelectAddr", [frameindex], []>;
def addr : ComplexPattern<iPTR, 2, "SelectAddr", [frameindex], [SDNPWantParent]>;
//===----------------------------------------------------------------------===//
// Pattern fragment for load/store

View File

@ -112,6 +112,8 @@ public:
bool hasMips64() const { return MipsArchVersion >= Mips64; }
bool hasMips64r2() const { return MipsArchVersion == Mips64r2; }
bool hasMips32r2Or64() const { return hasMips32r2() || hasMips64(); }
bool isLittle() const { return IsLittle; }
bool isFP64bit() const { return IsFP64bit; }
bool isGP64bit() const { return IsGP64bit; }

View File

@ -0,0 +1,59 @@
; RUN: llc -march=mipsel -mcpu=mips32r2 < %s | FileCheck %s
%struct.S = type <{ [4 x float] }>
@s = external global [4 x %struct.S]
@gf = external global float
@gd = external global double
define float @foo0(float* nocapture %b, i32 %o) nounwind readonly {
entry:
; CHECK: lwxc1
%arrayidx = getelementptr inbounds float* %b, i32 %o
%0 = load float* %arrayidx, align 4
ret float %0
}
define double @foo1(double* nocapture %b, i32 %o) nounwind readonly {
entry:
; CHECK: ldxc1
%arrayidx = getelementptr inbounds double* %b, i32 %o
%0 = load double* %arrayidx, align 8
ret double %0
}
define float @foo2(i32 %b, i32 %c) nounwind readonly {
entry:
; CHECK: luxc1
%arrayidx1 = getelementptr inbounds [4 x %struct.S]* @s, i32 0, i32 %b, i32 0, i32 %c
%0 = load float* %arrayidx1, align 1
ret float %0
}
define void @foo3(float* nocapture %b, i32 %o) nounwind {
entry:
; CHECK: swxc1
%0 = load float* @gf, align 4
%arrayidx = getelementptr inbounds float* %b, i32 %o
store float %0, float* %arrayidx, align 4
ret void
}
define void @foo4(double* nocapture %b, i32 %o) nounwind {
entry:
; CHECK: sdxc1
%0 = load double* @gd, align 8
%arrayidx = getelementptr inbounds double* %b, i32 %o
store double %0, double* %arrayidx, align 8
ret void
}
define void @foo5(i32 %b, i32 %c) nounwind {
entry:
; CHECK: suxc1
%0 = load float* @gf, align 4
%arrayidx1 = getelementptr inbounds [4 x %struct.S]* @s, i32 0, i32 %b, i32 0, i32 %c
store float %0, float* %arrayidx1, align 1
ret void
}

View File

@ -0,0 +1,67 @@
; RUN: llc -march=mips64el -mcpu=mips64r2 -mattr=n64 < %s | FileCheck %s
%struct.S = type <{ [4 x float] }>
@s = external global [4 x %struct.S]
@gf = external global float
@gd = external global double
define float @foo0(float* nocapture %b, i32 %o) nounwind readonly {
entry:
; CHECK: lwxc1
%idxprom = zext i32 %o to i64
%arrayidx = getelementptr inbounds float* %b, i64 %idxprom
%0 = load float* %arrayidx, align 4
ret float %0
}
define double @foo1(double* nocapture %b, i32 %o) nounwind readonly {
entry:
; CHECK: ldxc1
%idxprom = zext i32 %o to i64
%arrayidx = getelementptr inbounds double* %b, i64 %idxprom
%0 = load double* %arrayidx, align 8
ret double %0
}
define float @foo2(i32 %b, i32 %c) nounwind readonly {
entry:
; CHECK: luxc1
%idxprom = zext i32 %c to i64
%idxprom1 = zext i32 %b to i64
%arrayidx2 = getelementptr inbounds [4 x %struct.S]* @s, i64 0, i64 %idxprom1, i32 0, i64 %idxprom
%0 = load float* %arrayidx2, align 1
ret float %0
}
define void @foo3(float* nocapture %b, i32 %o) nounwind {
entry:
; CHECK: swxc1
%0 = load float* @gf, align 4
%idxprom = zext i32 %o to i64
%arrayidx = getelementptr inbounds float* %b, i64 %idxprom
store float %0, float* %arrayidx, align 4
ret void
}
define void @foo4(double* nocapture %b, i32 %o) nounwind {
entry:
; CHECK: sdxc1
%0 = load double* @gd, align 8
%idxprom = zext i32 %o to i64
%arrayidx = getelementptr inbounds double* %b, i64 %idxprom
store double %0, double* %arrayidx, align 8
ret void
}
define void @foo5(i32 %b, i32 %c) nounwind {
entry:
; CHECK: suxc1
%0 = load float* @gf, align 4
%idxprom = zext i32 %c to i64
%idxprom1 = zext i32 %b to i64
%arrayidx2 = getelementptr inbounds [4 x %struct.S]* @s, i64 0, i64 %idxprom1, i32 0, i64 %idxprom
store float %0, float* %arrayidx2, align 1
ret void
}