Index: lib/Target/Mips/MicroMipsInstrFormats.td =================================================================== --- lib/Target/Mips/MicroMipsInstrFormats.td +++ lib/Target/Mips/MicroMipsInstrFormats.td @@ -406,7 +406,7 @@ let Inst{8-0} = offset; } -class LWL_FM_MM funct> { +class LWL_FM_MM funct> : MMArch { bits<5> rt; bits<21> addr; @@ -419,7 +419,7 @@ let Inst{11-0} = addr{11-0}; } -class POOL32C_STEVA_LDEVA_FM_MM type, bits<3> funct> { +class POOL32C_STEVA_LDEVA_FM_MM type, bits<3> funct> : MMArch { bits<5> rt; bits<21> addr; bits<5> base = addr{20-16}; Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -201,6 +201,9 @@ Itin, FrmI> { let DecoderMethod = "DecodeMemMMImm12"; string Constraints = "$src = $rt"; + let BaseOpcode = opstr; + bit mayLoad = 1; + bit mayStore = 0; } class StoreLeftRightMM { let DecoderMethod = "DecodeMemMMImm12"; + let BaseOpcode = opstr; + bit mayLoad = 0; + bit mayStore = 1; } /// A register pair used by movep instruction. @@ -820,19 +826,25 @@ 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: lib/Target/Mips/MipsEVAInstrInfo.td =================================================================== --- lib/Target/Mips/MipsEVAInstrInfo.td +++ lib/Target/Mips/MipsEVAInstrInfo.td @@ -99,10 +99,12 @@ 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 { @@ -113,10 +115,12 @@ 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 { let DecoderMethod = "DecodeMem"; string Constraints = "$src = $rt"; + let BaseOpcode = opstr; } class StoreLeftRight { let DecoderMethod = "DecodeMem"; + let BaseOpcode = opstr; } // COP2 Load/Store @@ -2015,19 +2017,16 @@ } /// load/store left/right -let EncodingPredicates = [], // 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; Index: test/CodeGen/Mips/unaligned-memops-mapping.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/unaligned-memops-mapping.mir @@ -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) Index: test/CodeGen/Mips/unaligned-memops.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/unaligned-memops.ll @@ -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 +}