[ARC] Add more load/store variants.

On ARC ISA, general format of load instruction is this:

    LD<zz><.x><.aa><.di> a, [b,c]
And general format of store is this:
    ST<zz><.aa><.di> c, [b,s9]
Where:

<zz> is data size field and can be one of
  <empty> (bits 00) - Word (32-bit), default behavior
  B             (bits 01) - Byte
  H             (bits 10) - Half-word (16-bit)

 <.x> is data extend mode:
  <empty> (bit 0) - If size is not Word(32-bit), then data is zero extended
  X       (bit 1) - If size is not Word(32-bit), then data is sign extended

 <.aa> is address write-back mode:
  <empty> (bits 00) - no write-back
  .AW  (bits 01) - Preincrement, base register updated pre memory transaction
  .AB  (bits 10) - Postincrement, base register updated post memory transaction

 <.di> is cache bypass mode:
  <empty> (bit 0) - Cached memory access, default mode
  .DI     (bit 1) - Non-cached data memory access

  This patch adds these load/store instruction variants to the ARC backend.

Patch By Denis Antrushin! <denis@synopsys.com>

Differential Revision: https://reviews.llvm.org/D58980

llvm-svn: 356200
This commit is contained in:
Pete Couperus 2019-03-14 20:50:54 +00:00
parent 51fe000d8a
commit 9fd1848823
5 changed files with 224 additions and 47 deletions

View File

@ -55,6 +55,44 @@ def GPR32Reduced : Operand<iAny> {
let DecoderMethod = "DecodeGBR32ShortRegister";
}
// Helper classes for load/store instructions
class DataSizeMode<bits<2> mode, string instSfx, string asmSfx> {
bits<2> Value = mode;
string InstSuffix = instSfx;
string AsmSuffix = asmSfx;
}
class ExtMode<bit mode, string instSfx, string asmSfx> {
bit Value = mode;
string InstSuffix = instSfx;
string AsmSuffix = asmSfx;
}
class AddrMode<bits<2> mode, string instSfx, string asmSfx> {
bits<2> Value = mode;
string InstSuffix = instSfx;
string AsmSuffix = asmSfx;
}
class CacheMode<bit mode, string instSfx, string asmSfx> {
bit Value = mode;
string InstSuffix = instSfx;
string AsmSuffix = asmSfx;
}
def ByteSM : DataSizeMode<0b01, "B", "b">;
def HalfSM : DataSizeMode<0b10, "H", "h">;
def WordSM : DataSizeMode<0b00, "", "">;
def NoEM : ExtMode<0, "", "">;
def SignedEM : ExtMode<1, "_X", ".x">;
def NoAM : AddrMode<0b00, "", "">;
def PreIncAM : AddrMode<0b01, "_AW", ".aw">;
def PostIncAM : AddrMode<0b10, "_AB", ".ab">;
def NoCC : CacheMode<0b0, "", "">;
def UncachedCC : CacheMode<0b1, "_DI", ".di">;
class InstARC<int sz, dag outs, dag ins, string asmstr, list<dag> pattern>
: Instruction, Encoding64 {
@ -64,6 +102,18 @@ class InstARC<int sz, dag outs, dag ins, string asmstr, list<dag> pattern>
let AsmString = asmstr;
let Pattern = pattern;
let Size = sz;
// Load/Store instruction properties
DataSizeMode ZZ = WordSM;
ExtMode X = NoEM;
AddrMode AA = NoAM;
CacheMode DI = NoCC;
// Field used for relation models
string BaseOpcode = "";
//TSFlags
let TSFlags{1-0} = AA.Value;
}
// ARC pseudo instructions format
@ -354,6 +404,8 @@ class F32_LD_RS9<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
let Inst{8-7} = zz;
let Inst{6} = x;
let Inst{5-0} = A;
let BaseOpcode = "ld_rs9";
}
class F32_LD_ADDR<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
@ -363,6 +415,8 @@ class F32_LD_ADDR<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
let B = addr{14-9};
let S9 = addr{8-0};
let BaseOpcode = "ld_rs9";
}
@ -387,6 +441,8 @@ class F32_LD_LIMM<bit x, bit di, bits<2> zz, dag outs, dag ins,
let Inst{6} = x;
let Inst{5-0} = A;
let DecoderMethod = "DecodeLdLImmInstruction";
let BaseOpcode = "ld_limm";
}
// Register + LImm load. The 32-bit immediate address is in Inst[63-32].
@ -415,6 +471,8 @@ class F32_LD_RLIMM<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
let Inst{11-6} = LImmReg;
let Inst{5-0} = A;
let DecoderMethod = "DecodeLdRLImmInstruction";
let BaseOpcode = "ld_rlimm";
}
// Register + S9 Store. (B + S9)
@ -437,6 +495,8 @@ class F32_ST_RS9<bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
let Inst{4-3} = aa;
let Inst{2-1} = zz;
let Inst{0} = 0;
let BaseOpcode = "st_rs9";
}
class F32_ST_ADDR<bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
@ -446,6 +506,8 @@ class F32_ST_ADDR<bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
let B = addr{14-9};
let S9 = addr{8-0};
let BaseOpcode = "st_rs9";
}
// LImm Store.
@ -469,6 +531,8 @@ class F32_ST_LIMM<bit di, bits<2> zz, dag outs, dag ins,
let Inst{2-1} = zz;
let Inst{0} = 0;
let DecoderMethod = "DecodeStLImmInstruction";
let BaseOpcode = "st_limm";
}
// Compact Move/Load.

View File

@ -27,6 +27,19 @@ using namespace llvm;
#include "ARCGenInstrInfo.inc"
#define DEBUG_TYPE "arc-inst-info"
enum AddrIncType {
NoAddInc = 0,
PreInc = 1,
PostInc = 2,
Scaled = 3
};
enum TSFlagsConstants {
TSF_AddrModeOff = 0,
TSF_AddModeMask = 3
};
// Pin the vtable to this file.
void ARCInstrInfo::anchor() {}
@ -395,3 +408,35 @@ unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
}
return MI.getDesc().getSize();
}
bool ARCInstrInfo::isPostIncrement(const MachineInstr &MI) const {
const MCInstrDesc &MID = MI.getDesc();
const uint64_t F = MID.TSFlags;
return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PostInc;
}
bool ARCInstrInfo::isPreIncrement(const MachineInstr &MI) const {
const MCInstrDesc &MID = MI.getDesc();
const uint64_t F = MID.TSFlags;
return ((F >> TSF_AddrModeOff) & TSF_AddModeMask) == PreInc;
}
bool ARCInstrInfo::getBaseAndOffsetPosition(const MachineInstr &MI,
unsigned &BasePos,
unsigned &OffsetPos) const {
if (!MI.mayLoad() && !MI.mayStore())
return false;
BasePos = 1;
OffsetPos = 2;
if (isPostIncrement(MI) || isPreIncrement(MI)) {
BasePos++;
OffsetPos++;
}
if (!MI.getOperand(BasePos).isReg() || !MI.getOperand(OffsetPos).isImm())
return false;
return true;
}

View File

@ -81,6 +81,16 @@ public:
bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
bool isPostIncrement(const MachineInstr &MI) const override;
// ARC-specific
bool isPreIncrement(const MachineInstr &MI) const;
virtual bool getBaseAndOffsetPosition(const MachineInstr &MI,
unsigned &BasePos,
unsigned &OffsetPos) const override;
// Emit code before MBBI to load immediate value into physical register Reg.
// Returns an iterator to the new instruction.
MachineBasicBlock::iterator loadImmediate(MachineBasicBlock &MBB,

View File

@ -787,50 +787,47 @@ let isReturn = 1, isTerminator = 1 in {
// Load/Store instructions.
//----------------------------------------------------------------------------
// Filter class for load/store mappings
class ArcLdStRel;
// Load instruction variants:
// Control bits: x, aa, di, zz
// x - sign extend.
// aa - incrementing mode. (N/A for LIMM).
// di - uncached.
// zz - data size.
multiclass ArcLdInst<bits<2> zz, string asmop> {
let mayLoad = 1 in {
def _rs9 : F32_LD_ADDR<0, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrs9:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
multiclass ArcLdInst<DataSizeMode zz, ExtMode x, CacheMode di, string asmop> {
let mayLoad = 1, ZZ = zz, X = x, DI = di in {
def _rs9: F32_LD_ADDR<x.Value, NoAM.Value, di.Value, zz.Value,
(outs GPR32:$A), (ins MEMrs9:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel;
def _limm : F32_LD_LIMM<0, 0, zz,
(outs GPR32:$A), (ins MEMii:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
def _limm: F32_LD_LIMM<x.Value, di.Value, zz.Value,
(outs GPR32:$A), (ins MEMii:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel;
def _rlimm : F32_LD_RLIMM<0, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrlimm:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
def _rlimm: F32_LD_RLIMM<x.Value, NoAM.Value, di.Value, zz.Value,
(outs GPR32:$A), (ins MEMrlimm:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>, ArcLdStRel;
def _X_rs9 : F32_LD_ADDR<1, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrs9:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _X_limm : F32_LD_LIMM<1, 0, zz,
(outs GPR32:$A), (ins MEMii:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _X_rlimm : F32_LD_RLIMM<1, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrlimm:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _AB_rs9 : F32_LD_RS9<0, 0b10, 0, zz,
(outs GPR32:$addrout, GPR32:$A),
(ins GPR32:$B, immS<9>:$S9),
!strconcat(asmop, ".ab\t$A, [$B,$S9]"), []>
{ let Constraints = "$addrout = $B"; }
foreach aa = [PreIncAM, PostIncAM] in {
def aa.InstSuffix#_rs9: F32_LD_RS9<x.Value, aa.Value, di.Value, zz.Value,
(outs GPR32:$A, GPR32:$addrout),
(ins GPR32:$B, immS<9>:$S9),
asmop#aa.AsmSuffix#"\t$A, [$B,$S9]", []>, ArcLdStRel
{ let Constraints = "$addrout = $B"; let AA = aa; }
}
}
}
foreach di = [NoCC, UncachedCC] in {
defm LD#di.InstSuffix : ArcLdInst<WordSM, NoEM, di, "ld"#di.AsmSuffix>;
foreach zz = [ByteSM, HalfSM] in {
foreach x = [NoEM, SignedEM] in {
defm LD#zz.InstSuffix#x.InstSuffix#di.InstSuffix : ArcLdInst<zz, x, di, "ld"#zz.AsmSuffix#x.AsmSuffix#di.AsmSuffix>;
}
}
}
// Load instruction definitions.
defm LD : ArcLdInst<0b00, "ld">;
defm LDH : ArcLdInst<0b10, "ldh">;
defm LDB : ArcLdInst<0b01, "ldb">;
// Load instruction patterns.
// 32-bit loads.
@ -872,25 +869,32 @@ def : Pat<(sextloadi8 AddrModeS9:$addr),(LDB_X_rs9 AddrModeS9:$addr)>;
// aa - incrementing mode. (N/A for LIMM).
// di - uncached.
// zz - data size.
multiclass ArcStInst<bits<2> zz, string asmop> {
let mayStore = 1 in {
def _rs9 : F32_ST_ADDR<0b00, 0, zz, (outs), (ins GPR32:$C, MEMrs9:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>;
multiclass ArcStInst<DataSizeMode zz, CacheMode di, string asmop> {
let mayStore = 1, ZZ = zz, DI = di in {
def _rs9: F32_ST_ADDR<NoAM.Value, di.Value, zz.Value,
(outs), (ins GPR32:$C, MEMrs9:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>, ArcLdStRel;
def _limm : F32_ST_LIMM<0, zz, (outs), (ins GPR32:$C, MEMii:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>;
def _limm: F32_ST_LIMM<di.Value, zz.Value,
(outs), (ins GPR32:$C, MEMii:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>, ArcLdStRel;
def _AW_rs9 : F32_ST_RS9<0b01, 0, zz, (outs GPR32:$addrout),
(ins GPR32:$C, GPR32:$B, immS<9>:$S9),
!strconcat(asmop, ".aw\t$C, [$B,$S9]"), []>
{ let Constraints = "$addrout = $B"; }
foreach aa = [PreIncAM, PostIncAM] in {
def aa.InstSuffix#_rs9: F32_ST_RS9<aa.Value, di.Value, zz.Value,
(outs GPR32:$addrout),
(ins GPR32:$C, GPR32:$B, immS<9>:$S9),
asmop#aa.AsmSuffix#"\t$C, [$B,$S9]", []>, ArcLdStRel
{ let Constraints = "$addrout = $B"; let AA = aa; }
}
}
}
// Store instruction definitions.
defm ST : ArcStInst<0b00, "st">;
defm STH : ArcStInst<0b10, "sth">;
defm STB : ArcStInst<0b01, "stb">;
foreach di = [NoCC, UncachedCC] in {
foreach zz = [ByteSM, HalfSM, WordSM] in {
defm ST#zz.InstSuffix#di.InstSuffix : ArcStInst<zz, di, "st"#zz.AsmSuffix#di.AsmSuffix>;
}
}
// Store instruction patterns.
// 32-bit stores
@ -911,3 +915,10 @@ def : Pat<(truncstorei8 i32:$C, AddrModeS9:$addr),
def : Pat<(truncstorei8 i32:$C, AddrModeImm:$addr),
(STB_limm i32:$C, AddrModeImm:$addr)>;
def getPostIncOpcode : InstrMapping {
let FilterClass = "ArcLdStRel";
let RowFields = [ "BaseOpcode", "ZZ", "DI", "X"];
let ColFields = [ "AA" ];
let KeyCol = [ "NoAM" ];
let ValueCols = [["PostIncAM"]];
}

View File

@ -45,3 +45,50 @@
# CHECK: st %r7, [63920]
0x00 0x1e 0xc0 0x71 0x00 0x00 0xb0 0xf9
# CHECK: ldb.ab %r1, [%r0,1]
0x01 0x10 0x81 0x04
# CHECK: stb.ab %r2, [%r0,1]
0x01 0x18 0x92 0x00
# CHECK: ldh.ab %r3, [%r0,12]
0x0C 0x10 0x03 0x05
# CHECK: sth.ab %r4, [%r0,18]
0x12 0x18 0x14 0x01
# CHECK: ld.ab %r5, [%r2,128]
0x80 0x12 0x05 0x04
# CHECK: st.ab %r6, [%r2,64]
0x40 0x1A 0x90 0x01
# CHECK: ldb.aw %r7, [%r0,1]
0x01 0x10 0x87 0x02
# CHECK: stb.aw %r8, [%r0,1]
0x01 0x18 0x0A 0x02
# CHECK: ldh.aw %r3, [%r0,12]
0x0C 0x10 0x03 0x03
# CHECK: sth.aw %r3, [%r0,18]
0x12 0x18 0xCC 0x00
# CHECK: ld.aw %r6, [%r2,128]
0x80 0x12 0x06 0x02
# CHECK: st.aw %r6, [%r2,64]
0x40 0x1A 0x88 0x01
# CHECK: ld.aw %r6, [%r2,128]
0x80 0x12 0x06 0x02
# CHECK: st.aw %r6, [%r2,64]
0x40 0x1A 0x88 0x01
# CHECK: ldb.x.di.aw %r0, [%r8,8]
0x08 0x10 0xC0 0x1A
# CHECK: stb.di.ab %r0, [%r9,64]
0x40 0x19 0x32 0x10