[mips] Correct the definitions of the unaligned word memory operation instructions
authorSimon Dardis <simon.dardis@mips.com>
Thu, 19 Apr 2018 13:33:51 +0000 (13:33 +0000)
committerSimon Dardis <simon.dardis@mips.com>
Thu, 19 Apr 2018 13:33:51 +0000 (13:33 +0000)
These instructions lacked the correct predicates, were not marked
as loads and stores and lacked the proper instruction mapping information.

In the case of microMIPS sw(l|r)e (EVA) these instructions were using the load
EVA description.

Reviewers: abeserminji, smaksimovic, atanasyan

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

llvm-svn: 330326

llvm/lib/Target/Mips/MicroMipsInstrFormats.td
llvm/lib/Target/Mips/MicroMipsInstrInfo.td
llvm/lib/Target/Mips/MipsEVAInstrInfo.td
llvm/lib/Target/Mips/MipsInstrInfo.td
llvm/test/CodeGen/Mips/unaligned-memops-mapping.mir [new file with mode: 0644]
llvm/test/CodeGen/Mips/unaligned-memops.ll [new file with mode: 0644]

index 0b2b117..d948176 100644 (file)
@@ -406,7 +406,7 @@ class POOL32C_LHUE_FM_MM<bits<6> op, bits<4> fmt, bits<3> funct> : MMArch {
   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;
 
@@ -419,7 +419,7 @@ class LWL_FM_MM<bits<4> funct> {
   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};
index 150af02..1730d74 100644 (file)
@@ -201,6 +201,9 @@ class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
          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,
@@ -209,6 +212,9 @@ 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.
@@ -820,19 +826,25 @@ let DecoderNamespace = "MicroMips" in {
                   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>;
index 59254f2..ff54b1f 100644 (file)
@@ -99,10 +99,12 @@ class LOAD_LEFT_RIGHT_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
   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> {
@@ -113,10 +115,12 @@ class STORE_LEFT_RIGHT_EVA_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
   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,
index 451cbcc..7b4aaea 100644 (file)
@@ -1429,6 +1429,7 @@ class LoadLeftRight<string opstr, SDNode OpNode, RegisterOperand RO,
          [(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,
@@ -1436,6 +1437,7 @@ 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
@@ -2015,19 +2017,16 @@ def SW  : Store<"sw", GPR32Opnd, store, II_SW>, MMRel, LW_FM<0x2b>;
 }
 
 /// 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;
diff --git a/llvm/test/CodeGen/Mips/unaligned-memops-mapping.mir b/llvm/test/CodeGen/Mips/unaligned-memops-mapping.mir
new file mode 100644 (file)
index 0000000..438a7e1
--- /dev/null
@@ -0,0 +1,124 @@
+# 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)
diff --git a/llvm/test/CodeGen/Mips/unaligned-memops.ll b/llvm/test/CodeGen/Mips/unaligned-memops.ll
new file mode 100644 (file)
index 0000000..af290a7
--- /dev/null
@@ -0,0 +1,35 @@
+; 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
+}