let Inst{8-0} = offset;
}
-class LWL_FM_MM<bits<4> funct> {
+class LWL_FM_MM<bits<4> funct> : MMArch {
bits<5> rt;
bits<21> addr;
let Inst{11-0} = addr{11-0};
}
-class POOL32C_STEVA_LDEVA_FM_MM<bits<4> type, bits<3> funct> {
+class POOL32C_STEVA_LDEVA_FM_MM<bits<4> type, bits<3> funct> : MMArch {
bits<5> rt;
bits<21> addr;
bits<5> base = addr{20-16};
Itin, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
string Constraints = "$src = $rt";
+ let BaseOpcode = opstr;
+ bit mayLoad = 1;
+ bit mayStore = 0;
}
class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
!strconcat(opstr, "\t$rt, $addr"),
[(OpNode RO:$rt, addrimm12:$addr)], Itin, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
+ let BaseOpcode = opstr;
+ bit mayLoad = 0;
+ bit mayStore = 1;
}
/// A register pair used by movep instruction.
ISA_MICROMIPS32_NOT_MIPS32R6, ASE_EVA;
}
}
-let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
- def LWXS_MM : LoadWordIndexedScaledMM<"lwxs", GPR32Opnd>, LWXS_FM_MM<0x118>;
+let DecoderNamespace = "MicroMips" in {
+ let Predicates = [InMicroMips] in
+ def LWXS_MM : LoadWordIndexedScaledMM<"lwxs", GPR32Opnd>, LWXS_FM_MM<0x118>;
/// Load and Store Instructions - unaligned
- def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12, II_LWL>,
- LWL_FM_MM<0x0>;
- def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12, II_LWR>,
- LWL_FM_MM<0x1>;
- def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12, II_SWL>,
- LWL_FM_MM<0x8>;
- def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12, II_SWR>,
- LWL_FM_MM<0x9>;
-
+ def LWL_MM : MMRel, LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12,
+ II_LWL>, LWL_FM_MM<0x0>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+ def LWR_MM : MMRel, LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12,
+ II_LWR>, LWL_FM_MM<0x1>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+ def SWL_MM : MMRel, StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12,
+ II_SWL>, LWL_FM_MM<0x8>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+ def SWR_MM : MMRel, StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12,
+ II_SWR>, LWL_FM_MM<0x9>,
+ ISA_MICROMIPS32_NOT_MIPS32R6;
+}
+let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
/// Load and Store Instructions - multiple
def SWM32_MM : StoreMultMM<"swm32", II_SWM>, LWM_FM_MM<0xd>;
def LWM32_MM : LoadMultMM<"lwm32", II_LWM>, LWM_FM_MM<0x5>;
string Constraints = "$src = $rt";
bit canFoldAsLoad = 1;
InstrItinClass Itinerary = itin;
+ bit mayLoad = 1;
+ bit mayStore = 0;
}
-class LWLE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwle", GPR32Opnd, II_LWLE>;
-class LWRE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwre", GPR32Opnd, II_LWRE>;
+class LWLE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwle", GPR32Opnd, II_LWLE>;
+class LWRE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"lwre", GPR32Opnd, II_LWRE>;
class STORE_LEFT_RIGHT_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass itin = NoItinerary> {
string DecoderMethod = "DecodeMemEVA";
string BaseOpcode = instr_asm;
InstrItinClass Itinerary = itin;
+ bit mayLoad = 0;
+ bit mayStore = 1;
}
-class SWLE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"swle", GPR32Opnd, II_SWLE>;
-class SWRE_DESC : LOAD_LEFT_RIGHT_EVA_DESC_BASE<"swre", GPR32Opnd, II_SWRE>;
+class SWLE_DESC : STORE_LEFT_RIGHT_EVA_DESC_BASE<"swle", GPR32Opnd, II_SWLE>;
+class SWRE_DESC : STORE_LEFT_RIGHT_EVA_DESC_BASE<"swre", GPR32Opnd, II_SWRE>;
// Load-linked EVA, Store-conditional EVA descriptions
class LLE_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
[(set RO:$rt, (OpNode addr:$addr, RO:$src))], Itin, FrmI> {
let DecoderMethod = "DecodeMem";
string Constraints = "$src = $rt";
+ let BaseOpcode = opstr;
}
class StoreLeftRight<string opstr, SDNode OpNode, RegisterOperand RO,
InstSE<(outs), (ins RO:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"),
[(OpNode RO:$rt, addr:$addr)], Itin, FrmI> {
let DecoderMethod = "DecodeMem";
+ let BaseOpcode = opstr;
}
// COP2 Load/Store
}
/// load/store left/right
-let EncodingPredicates = []<Predicate>, // FIXME: Lack of HasStdEnc is probably a bug
- AdditionalPredicates = [NotInMicroMips] in {
-def LWL : LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, II_LWL>, LW_FM<0x22>,
+let AdditionalPredicates = [NotInMicroMips] in {
+def LWL : MMRel, LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, II_LWL>, LW_FM<0x22>,
ISA_MIPS1_NOT_32R6_64R6;
-def LWR : LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, II_LWR>, LW_FM<0x26>,
+def LWR : MMRel, LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, II_LWR>, LW_FM<0x26>,
ISA_MIPS1_NOT_32R6_64R6;
-def SWL : StoreLeftRight<"swl", MipsSWL, GPR32Opnd, II_SWL>, LW_FM<0x2a>,
+def SWL : MMRel, StoreLeftRight<"swl", MipsSWL, GPR32Opnd, II_SWL>, LW_FM<0x2a>,
ISA_MIPS1_NOT_32R6_64R6;
-def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>,
+def SWR : MMRel, StoreLeftRight<"swr", MipsSWR, GPR32Opnd, II_SWR>, LW_FM<0x2e>,
ISA_MIPS1_NOT_32R6_64R6;
-}
-let AdditionalPredicates = [NotInMicroMips] in {
// COP2 Memory Instructions
def LWC2 : StdMMR6Rel, LW_FT2<"lwc2", COP2Opnd, II_LWC2, load>, LW_FM<0x32>,
ISA_MIPS1_NOT_32R6_64R6;
--- /dev/null
+# RUN: llc -O0 -march=mips -mcpu=mips32r3 -mattr=+micromips,+eva -start-after=expand-isel-pseudos \
+# RUN: -filetype obj %s -o - | llvm-objdump -mattr=+eva -d - | FileCheck %s
+
+# Test that MIPS unaligned load/store instructions can be mapped to their
+# corresponding microMIPS instructions.
+--- |
+ define void @g(i32* %a, i32* %b) {
+ entry:
+ %0 = load i32, i32* %a, align 1
+ store i32 %0, i32* %b, align 1
+ ret void
+ }
+
+ define void @g2(i32* %a, i32* %b) {
+ entry:
+ %0 = load i32, i32* %a, align 1
+ store i32 %0, i32* %b, align 1
+ ret void
+ }
+...
+---
+name: g
+alignment: 2
+exposesReturnsTwice: false
+legalized: false
+regBankSelected: false
+selected: false
+failedISel: false
+tracksRegLiveness: true
+liveins:
+ - { reg: '$a0', virtual-reg: '%0' }
+ - { reg: '$a1', virtual-reg: '%1' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 1
+ adjustsStack: false
+ hasCalls: false
+ stackProtector: ''
+ maxCallFrameSize: 4294967295
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+ savePoint: ''
+ restorePoint: ''
+fixedStack:
+stack:
+constants:
+body: |
+ bb.0.entry:
+ liveins: $a0, $a1
+
+ %1:gpr32 = COPY $a1
+ %0:gpr32 = COPY $a0
+ %3:gpr32 = IMPLICIT_DEF
+ %2:gpr32 = LWL %0, 0, %3 :: (load 4 from %ir.a, align 1)
+ %4:gpr32 = LWR %0, 3, %2 :: (load 4 from %ir.a, align 1)
+ SWL %4, %1, 0 :: (store 4 into %ir.b, align 1)
+ SWR %4, %1, 3 :: (store 4 into %ir.b, align 1)
+ RetRA
+
+...
+---
+name: g2
+alignment: 2
+exposesReturnsTwice: false
+legalized: false
+regBankSelected: false
+selected: false
+failedISel: false
+tracksRegLiveness: true
+liveins:
+ - { reg: '$a0', virtual-reg: '%0' }
+ - { reg: '$a1', virtual-reg: '%1' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 1
+ adjustsStack: false
+ hasCalls: false
+ stackProtector: ''
+ maxCallFrameSize: 4294967295
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+ savePoint: ''
+ restorePoint: ''
+fixedStack:
+stack:
+constants:
+body: |
+ bb.0.entry:
+ liveins: $a0, $a1
+
+ %1:gpr32 = COPY $a1
+ %0:gpr32 = COPY $a0
+ %3:gpr32 = IMPLICIT_DEF
+ %2:gpr32 = LWLE %0, 0, %3 :: (load 4 from %ir.a, align 1)
+ %4:gpr32 = LWRE %0, 3, %2 :: (load 4 from %ir.a, align 1)
+ SWLE %4, %1, 0 :: (store 4 into %ir.b, align 1)
+ SWRE %4, %1, 3 :: (store 4 into %ir.b, align 1)
+ RetRA
+
+...
+
+# CHECK-LABEL: g:
+# CHECK: 0: 60 24 00 00 lwl $1, 0($4)
+# CHECK: 4: 60 24 10 03 lwr $1, 3($4)
+# CHECK: 8: 60 25 80 00 swl $1, 0($5)
+# CHECK: c: 60 25 90 03 swr $1, 3($5)
+
+# CHECK-LABEL: g2:
+# CHECK: 14: 60 24 64 00 lwle $1, 0($4)
+# CHECK: 18: 60 24 66 03 lwre $1, 3($4)
+# CHECK: 1c: 60 25 a0 00 swle $1, 0($5)
+# CHECK: 20: 60 25 a2 03 swre $1, 3($5)
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -march=mips -mcpu=mips32r2 -stop-before=expand-isel-pseudos < %s | FileCheck %s --check-prefix=MIPS
+; RUN: llc -march=mips -mcpu=mips32r2 -mattr=+micromips -stop-before=expand-isel-pseudos < %s | FileCheck %s --check-prefix=MICROMIPS
+
+; Test that the correct ISA version of the unaligned memory operations is
+; selected up front.
+
+define void @g2(i32* %a, i32* %b) {
+ ; MIPS-LABEL: name: g2
+ ; MIPS: bb.0.entry:
+ ; MIPS: liveins: $a0, $a1
+ ; MIPS: [[COPY:%[0-9]+]]:gpr32 = COPY $a1
+ ; MIPS: [[COPY1:%[0-9]+]]:gpr32 = COPY $a0
+ ; MIPS: [[DEF:%[0-9]+]]:gpr32 = IMPLICIT_DEF
+ ; MIPS: [[LWL:%[0-9]+]]:gpr32 = LWL [[COPY1]], 0, [[DEF]] :: (load 4 from %ir.a, align 1)
+ ; MIPS: [[LWR:%[0-9]+]]:gpr32 = LWR [[COPY1]], 3, [[LWL]] :: (load 4 from %ir.a, align 1)
+ ; MIPS: SWL [[LWR]], [[COPY]], 0 :: (store 4 into %ir.b, align 1)
+ ; MIPS: SWR [[LWR]], [[COPY]], 3 :: (store 4 into %ir.b, align 1)
+ ; MIPS: RetRA
+ ; MICROMIPS-LABEL: name: g2
+ ; MICROMIPS: bb.0.entry:
+ ; MICROMIPS: liveins: $a0, $a1
+ ; MICROMIPS: [[COPY:%[0-9]+]]:gpr32 = COPY $a1
+ ; MICROMIPS: [[COPY1:%[0-9]+]]:gpr32 = COPY $a0
+ ; MICROMIPS: [[DEF:%[0-9]+]]:gpr32 = IMPLICIT_DEF
+ ; MICROMIPS: [[LWL_MM:%[0-9]+]]:gpr32 = LWL_MM [[COPY1]], 0, [[DEF]] :: (load 4 from %ir.a, align 1)
+ ; MICROMIPS: [[LWR_MM:%[0-9]+]]:gpr32 = LWR_MM [[COPY1]], 3, [[LWL_MM]] :: (load 4 from %ir.a, align 1)
+ ; MICROMIPS: SWL_MM [[LWR_MM]], [[COPY]], 0 :: (store 4 into %ir.b, align 1)
+ ; MICROMIPS: SWR_MM [[LWR_MM]], [[COPY]], 3 :: (store 4 into %ir.b, align 1)
+ ; MICROMIPS: RetRA
+entry:
+ %0 = load i32, i32* %a, align 1
+ store i32 %0, i32* %b, align 1
+ ret void
+}