mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
MIPS DSP: add support for extract-word instructions.
llvm-svn: 164749
This commit is contained in:
parent
74880b0bd8
commit
b2ac1bfabe
@ -23,3 +23,19 @@ def REGIMM_OPCODE : Field6<0b000001>;
|
||||
class DSPInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> {
|
||||
let Predicates = [HasDSP];
|
||||
}
|
||||
|
||||
// EXTR.W sub-class format (type 1).
|
||||
class EXTR_W_TY1_FMT<bits<5> op> : DSPInst {
|
||||
bits<5> rt;
|
||||
bits<2> ac;
|
||||
bits<5> shift_rs;
|
||||
|
||||
let Opcode = SPECIAL3_OPCODE.V;
|
||||
|
||||
let Inst{25-21} = shift_rs;
|
||||
let Inst{20-16} = rt;
|
||||
let Inst{15-13} = 0;
|
||||
let Inst{12-11} = ac;
|
||||
let Inst{10-6} = op;
|
||||
let Inst{5-0} = 0b111000;
|
||||
}
|
||||
|
@ -19,6 +19,105 @@ def immZExt8 : ImmLeaf<i32, [{return isUInt<8>(Imm);}]>;
|
||||
def immZExt10 : ImmLeaf<i32, [{return isUInt<10>(Imm);}]>;
|
||||
def immSExt6 : ImmLeaf<i32, [{return isInt<6>(Imm);}]>;
|
||||
|
||||
// Mips-specific dsp nodes
|
||||
def SDT_MipsExtr : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>]>;
|
||||
|
||||
class MipsDSPSideEffectBase<string Opc, SDTypeProfile Prof> :
|
||||
SDNode<!strconcat("MipsISD::", Opc), Prof,
|
||||
[SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPSideEffect]>;
|
||||
|
||||
def MipsEXTP : MipsDSPSideEffectBase<"EXTP", SDT_MipsExtr>;
|
||||
def MipsEXTPDP : MipsDSPSideEffectBase<"EXTPDP", SDT_MipsExtr>;
|
||||
def MipsEXTR_S_H : MipsDSPSideEffectBase<"EXTR_S_H", SDT_MipsExtr>;
|
||||
def MipsEXTR_W : MipsDSPSideEffectBase<"EXTR_W", SDT_MipsExtr>;
|
||||
def MipsEXTR_R_W : MipsDSPSideEffectBase<"EXTR_R_W", SDT_MipsExtr>;
|
||||
def MipsEXTR_RS_W : MipsDSPSideEffectBase<"EXTR_RS_W", SDT_MipsExtr>;
|
||||
|
||||
// Instruction encoding.
|
||||
class EXTP_ENC : EXTR_W_TY1_FMT<0b00010>;
|
||||
class EXTPV_ENC : EXTR_W_TY1_FMT<0b00011>;
|
||||
class EXTPDP_ENC : EXTR_W_TY1_FMT<0b01010>;
|
||||
class EXTPDPV_ENC : EXTR_W_TY1_FMT<0b01011>;
|
||||
class EXTR_W_ENC : EXTR_W_TY1_FMT<0b00000>;
|
||||
class EXTRV_W_ENC : EXTR_W_TY1_FMT<0b00001>;
|
||||
class EXTR_R_W_ENC : EXTR_W_TY1_FMT<0b00100>;
|
||||
class EXTRV_R_W_ENC : EXTR_W_TY1_FMT<0b00101>;
|
||||
class EXTR_RS_W_ENC : EXTR_W_TY1_FMT<0b00110>;
|
||||
class EXTRV_RS_W_ENC : EXTR_W_TY1_FMT<0b00111>;
|
||||
class EXTR_S_H_ENC : EXTR_W_TY1_FMT<0b01110>;
|
||||
class EXTRV_S_H_ENC : EXTR_W_TY1_FMT<0b01111>;
|
||||
|
||||
// Instruction desc.
|
||||
class EXTR_W_TY1_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
|
||||
InstrItinClass itin> {
|
||||
dag OutOperandList = (outs CPURegs:$rt);
|
||||
dag InOperandList = (ins ACRegs:$ac, CPURegs:$shift_rs);
|
||||
string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs");
|
||||
InstrItinClass Itinerary = itin;
|
||||
list<Register> Defs = [DSPCtrl];
|
||||
}
|
||||
|
||||
class EXTR_W_TY1_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
|
||||
InstrItinClass itin> {
|
||||
dag OutOperandList = (outs CPURegs:$rt);
|
||||
dag InOperandList = (ins ACRegs:$ac, uimm16:$shift_rs);
|
||||
string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs");
|
||||
InstrItinClass Itinerary = itin;
|
||||
list<Register> Defs = [DSPCtrl];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MIPS DSP Rev 1
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Extr
|
||||
class EXTP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extp", MipsEXTP, NoItinerary>;
|
||||
|
||||
class EXTPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpv", MipsEXTP, NoItinerary>;
|
||||
|
||||
class EXTPDP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extpdp", MipsEXTPDP, NoItinerary>;
|
||||
|
||||
class EXTPDPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpdpv", MipsEXTPDP,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTR_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr.w", MipsEXTR_W, NoItinerary>;
|
||||
|
||||
class EXTRV_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv.w", MipsEXTR_W,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTR_R_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_r.w", MipsEXTR_R_W,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTRV_R_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_r.w", MipsEXTR_R_W,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTR_RS_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_rs.w", MipsEXTR_RS_W,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTRV_RS_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_rs.w", MipsEXTR_RS_W,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTR_S_H_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_s.h", MipsEXTR_S_H,
|
||||
NoItinerary>;
|
||||
|
||||
class EXTRV_S_H_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_s.h", MipsEXTR_S_H,
|
||||
NoItinerary>;
|
||||
|
||||
// Instruction defs.
|
||||
// MIPS DSP Rev 1
|
||||
def EXTP : EXTP_ENC, EXTP_DESC;
|
||||
def EXTPV : EXTPV_ENC, EXTPV_DESC;
|
||||
def EXTPDP : EXTPDP_ENC, EXTPDP_DESC;
|
||||
def EXTPDPV : EXTPDPV_ENC, EXTPDPV_DESC;
|
||||
def EXTR_W : EXTR_W_ENC, EXTR_W_DESC;
|
||||
def EXTRV_W : EXTRV_W_ENC, EXTRV_W_DESC;
|
||||
def EXTR_R_W : EXTR_R_W_ENC, EXTR_R_W_DESC;
|
||||
def EXTRV_R_W : EXTRV_R_W_ENC, EXTRV_R_W_DESC;
|
||||
def EXTR_RS_W : EXTR_RS_W_ENC, EXTR_RS_W_DESC;
|
||||
def EXTRV_RS_W : EXTRV_RS_W_ENC, EXTRV_RS_W_DESC;
|
||||
def EXTR_S_H : EXTR_S_H_ENC, EXTR_S_H_DESC;
|
||||
def EXTRV_S_H : EXTRV_S_H_ENC, EXTRV_S_H_DESC;
|
||||
|
||||
// Patterns.
|
||||
class DSPPat<dag pattern, dag result, Predicate pred = HasDSP> :
|
||||
Pat<pattern, result>, Requires<[pred]>;
|
||||
@ -41,3 +140,23 @@ def : DSPPat<(store (v2i16 DSPRegs:$val), addr:$a),
|
||||
(SW (COPY_TO_REGCLASS DSPRegs:$val, CPURegs), addr:$a)>;
|
||||
def : DSPPat<(store (v4i8 DSPRegs:$val), addr:$a),
|
||||
(SW (COPY_TO_REGCLASS DSPRegs:$val, CPURegs), addr:$a)>;
|
||||
|
||||
// Extr patterns.
|
||||
class EXTR_W_TY1_R2_Pat<SDPatternOperator OpNode, Instruction Instr> :
|
||||
DSPPat<(i32 (OpNode CPURegs:$rs)), (Instr AC0, CPURegs:$rs)>;
|
||||
|
||||
class EXTR_W_TY1_R1_Pat<SDPatternOperator OpNode, Instruction Instr> :
|
||||
DSPPat<(i32 (OpNode immZExt5:$shift)), (Instr AC0, immZExt5:$shift)>;
|
||||
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTP, EXTP>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTP, EXTPV>;
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTPDP, EXTPDP>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTPDP, EXTPDPV>;
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTR_W, EXTR_W>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTR_W, EXTRV_W>;
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTR_R_W, EXTR_R_W>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTR_R_W, EXTRV_R_W>;
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTR_RS_W, EXTR_RS_W>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTR_RS_W, EXTRV_RS_W>;
|
||||
def : EXTR_W_TY1_R1_Pat<MipsEXTR_S_H, EXTR_S_H>;
|
||||
def : EXTR_W_TY1_R2_Pat<MipsEXTR_S_H, EXTRV_S_H>;
|
||||
|
@ -868,6 +868,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
|
||||
case ISD::SRL_PARTS: return LowerShiftRightParts(Op, DAG, false);
|
||||
case ISD::LOAD: return LowerLOAD(Op, DAG);
|
||||
case ISD::STORE: return LowerSTORE(Op, DAG);
|
||||
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
||||
case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, DAG);
|
||||
}
|
||||
return SDValue();
|
||||
}
|
||||
@ -2282,6 +2284,91 @@ SDValue MipsTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
|
||||
return CreateStoreLR(MipsISD::SDR, DAG, SD, SDL, IsLittle ? 0 : 7);
|
||||
}
|
||||
|
||||
// This function expands mips intrinsic nodes which have 64-bit input operands
|
||||
// or output values.
|
||||
//
|
||||
// out64 = intrinsic-node in64
|
||||
// =>
|
||||
// lo = copy (extract-element (in64, 0))
|
||||
// hi = copy (extract-element (in64, 1))
|
||||
// mips-specific-node
|
||||
// v0 = copy lo
|
||||
// v1 = copy hi
|
||||
// out64 = merge-values (v0, v1)
|
||||
//
|
||||
static SDValue LowerDSPIntr(SDValue Op, SelectionDAG &DAG,
|
||||
unsigned Opc, bool HasI64In, bool HasI64Out) {
|
||||
DebugLoc DL = Op.getDebugLoc();
|
||||
bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other;
|
||||
SDValue Chain = HasChainIn ? Op->getOperand(0) : DAG.getEntryNode();
|
||||
SmallVector<SDValue, 3> Ops;
|
||||
|
||||
if (HasI64In) {
|
||||
SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32,
|
||||
Op->getOperand(1 + HasChainIn),
|
||||
DAG.getConstant(0, MVT::i32));
|
||||
SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32,
|
||||
Op->getOperand(1 + HasChainIn),
|
||||
DAG.getConstant(1, MVT::i32));
|
||||
|
||||
Chain = DAG.getCopyToReg(Chain, DL, Mips::LO, InLo, SDValue());
|
||||
Chain = DAG.getCopyToReg(Chain, DL, Mips::HI, InHi, Chain.getValue(1));
|
||||
|
||||
Ops.push_back(Chain);
|
||||
Ops.append(Op->op_begin() + HasChainIn + 2, Op->op_end());
|
||||
Ops.push_back(Chain.getValue(1));
|
||||
} else {
|
||||
Ops.push_back(Chain);
|
||||
Ops.append(Op->op_begin() + HasChainIn + 1, Op->op_end());
|
||||
}
|
||||
|
||||
if (!HasI64Out)
|
||||
return DAG.getNode(Opc, DL, Op->value_begin(), Op->getNumValues(),
|
||||
Ops.begin(), Ops.size());
|
||||
|
||||
SDValue Intr = DAG.getNode(Opc, DL, DAG.getVTList(MVT::Other, MVT::Glue),
|
||||
Ops.begin(), Ops.size());
|
||||
SDValue OutLo = DAG.getCopyFromReg(Intr.getValue(0), DL, Mips::LO, MVT::i32,
|
||||
Intr.getValue(1));
|
||||
SDValue OutHi = DAG.getCopyFromReg(OutLo.getValue(1), DL, Mips::HI, MVT::i32,
|
||||
OutLo.getValue(2));
|
||||
SDValue Out = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, OutLo, OutHi);
|
||||
|
||||
if (!HasChainIn)
|
||||
return Out;
|
||||
|
||||
SDValue Vals[] = { Out, OutHi.getValue(1) };
|
||||
return DAG.getMergeValues(Vals, 2, DL);
|
||||
}
|
||||
|
||||
SDValue MipsTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) {
|
||||
default:
|
||||
return SDValue();
|
||||
}
|
||||
}
|
||||
|
||||
SDValue MipsTargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
switch (cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue()) {
|
||||
default:
|
||||
return SDValue();
|
||||
case Intrinsic::mips_extp:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTP, true, false);
|
||||
case Intrinsic::mips_extpdp:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTPDP, true, false);
|
||||
case Intrinsic::mips_extr_w:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTR_W, true, false);
|
||||
case Intrinsic::mips_extr_r_w:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W, true, false);
|
||||
case Intrinsic::mips_extr_rs_w:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W, true, false);
|
||||
case Intrinsic::mips_extr_s_h:
|
||||
return LowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Calling Convention Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -202,6 +202,8 @@ namespace llvm {
|
||||
bool IsSRA) const;
|
||||
SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
||||
virtual SDValue
|
||||
LowerFormalArguments(SDValue Chain,
|
||||
|
110
test/CodeGen/Mips/dsp-r1.ll
Normal file
110
test/CodeGen/Mips/dsp-r1.ll
Normal file
@ -0,0 +1,110 @@
|
||||
; RUN: llc -march=mipsel -mattr=+dsp < %s | FileCheck %s
|
||||
|
||||
define i32 @test__builtin_mips_extr_w1(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extr.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.w(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extr.w(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extr_w2(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extrv.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.w(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @test__builtin_mips_extr_r_w1(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extr_r.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.r.w(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extr.r.w(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extr_s_h1(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extrv_s.h
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.s.h(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extr.s.h(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extr_rs_w1(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extr_rs.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.rs.w(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extr.rs.w(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extr_rs_w2(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extrv_rs.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.rs.w(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @test__builtin_mips_extr_s_h2(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extr_s.h
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.s.h(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @test__builtin_mips_extr_r_w2(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extrv_r.w
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extr.r.w(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @test__builtin_mips_extp1(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extp
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extp(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extp(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extp2(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extpv
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extp(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @test__builtin_mips_extpdp1(i32 %i0, i32, i64 %a0) nounwind {
|
||||
entry:
|
||||
; CHECK: extpdp
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extpdp(i64 %a0, i32 15)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
declare i32 @llvm.mips.extpdp(i64, i32) nounwind
|
||||
|
||||
define i32 @test__builtin_mips_extpdp2(i32 %i0, i32, i64 %a0, i32 %a1) nounwind {
|
||||
entry:
|
||||
; CHECK: extpdpv
|
||||
|
||||
%1 = tail call i32 @llvm.mips.extpdp(i64 %a0, i32 %a1)
|
||||
ret i32 %1
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user