Index: llvm/trunk/lib/Target/Mips/MipsLegalizerInfo.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsLegalizerInfo.cpp +++ llvm/trunk/lib/Target/Mips/MipsLegalizerInfo.cpp @@ -43,6 +43,9 @@ {p0, p0, 32, 8}}) .minScalar(0, s32); + getActionDefinitionsBuilder(G_UNMERGE_VALUES) + .legalFor({{s32, s64}}); + getActionDefinitionsBuilder(G_MERGE_VALUES) .legalFor({{s64, s32}}); Index: llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.h +++ llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.h @@ -57,15 +57,19 @@ /// Some generic instructions have operands that can be mapped to either fprb /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1 /// is always gprb since it is a pointer. - /// This class provides container for MI's ambiguous: + /// This class provides containers for MI's ambiguous: + /// DefUses : MachineInstrs that use one of MI's ambiguous def operands. /// UseDefs : MachineInstrs that define MI's ambiguous use operands. class AmbiguousRegDefUseContainer { + SmallVector DefUses; SmallVector UseDefs; + void addDefUses(Register Reg, const MachineRegisterInfo &MRI); void addUseDef(Register Reg, const MachineRegisterInfo &MRI); public: AmbiguousRegDefUseContainer(const MachineInstr *MI); + SmallVectorImpl &getDefUses() { return DefUses; } SmallVectorImpl &getUseDefs() { return UseDefs; } }; @@ -77,9 +81,10 @@ bool visit(const MachineInstr *MI); - /// Visit MI's adjacent UseDefs. + /// Visit MI's adjacent UseDefs or DefUses. bool visitAdjacentInstrs(const MachineInstr *MI, - SmallVectorImpl &AdjacentInstrs); + SmallVectorImpl &AdjacentInstrs, + bool isDefUse); void setTypes(const MachineInstr *MI, InstType ITy); Index: llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.cpp +++ llvm/trunk/lib/Target/Mips/MipsRegisterBankInfo.cpp @@ -112,6 +112,22 @@ } } +// Instructions where use operands are floating point registers. +// Def operands are general purpose. +static bool isFloatingPointOpcodeUse(unsigned Opc) { + switch (Opc) { + case TargetOpcode::G_FPTOSI: + case TargetOpcode::G_FPTOUI: + case TargetOpcode::G_FCMP: + case Mips::MFC1: + case Mips::ExtractElementF64: + case Mips::ExtractElementF64_64: + return true; + default: + return isFloatingPointOpcode(Opc); + } +} + // Instructions where def operands are floating point registers. // Use operands are general purpose. static bool isFloatingPointOpcodeDef(unsigned Opc) { @@ -139,6 +155,20 @@ } } +void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addDefUses( + Register Reg, const MachineRegisterInfo &MRI) { + assert(!MRI.getType(Reg).isPointer() && + "Pointers are gprb, they should not be considered as ambiguous.\n"); + for (MachineInstr &UseMI : MRI.use_instructions(Reg)) { + if (UseMI.getOpcode() == TargetOpcode::COPY && + !TargetRegisterInfo::isPhysicalRegister(UseMI.getOperand(0).getReg())) + // Copies of non-physical registers are not supported + return; + + DefUses.push_back(&UseMI); + } +} + void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addUseDef( Register Reg, const MachineRegisterInfo &MRI) { assert(!MRI.getType(Reg).isPointer() && @@ -159,6 +189,9 @@ const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo(); + if (MI->getOpcode() == TargetOpcode::G_LOAD) + addDefUses(MI->getOperand(0).getReg(), MRI); + if (MI->getOpcode() == TargetOpcode::G_STORE) addUseDef(MI->getOperand(0).getReg(), MRI); } @@ -169,27 +202,33 @@ startVisit(MI); AmbiguousRegDefUseContainer DefUseContainer(MI); + // Visit instructions where MI's DEF operands are USED. + if (visitAdjacentInstrs(MI, DefUseContainer.getDefUses(), true)) + return true; + // Visit instructions that DEFINE MI's USE operands. - if (visitAdjacentInstrs(MI, DefUseContainer.getUseDefs())) + if (visitAdjacentInstrs(MI, DefUseContainer.getUseDefs(), false)) return true; return false; } bool MipsRegisterBankInfo::TypeInfoForMF::visitAdjacentInstrs( - const MachineInstr *MI, SmallVectorImpl &AdjacentInstrs) { + const MachineInstr *MI, SmallVectorImpl &AdjacentInstrs, + bool isDefUse) { while (!AdjacentInstrs.empty()) { MachineInstr *AdjMI = AdjacentInstrs.pop_back_val(); - if (isFloatingPointOpcodeDef(AdjMI->getOpcode())) { + if (isDefUse ? isFloatingPointOpcodeUse(AdjMI->getOpcode()) + : isFloatingPointOpcodeDef(AdjMI->getOpcode())) { setTypes(MI, InstType::FloatingPoint); return true; } // Determine InstType from register bank of phys register that is - // use of this copy. + // 'isDefUse ? def : use' of this copy. if (AdjMI->getOpcode() == TargetOpcode::COPY) { - setTypesAccordingToPhysicalRegister(MI, AdjMI, 1); + setTypesAccordingToPhysicalRegister(MI, AdjMI, isDefUse ? 0 : 1); return true; } @@ -276,7 +315,6 @@ case G_SUB: case G_MUL: case G_UMULH: - case G_LOAD: case G_ZEXTLOAD: case G_SEXTLOAD: case G_GEP: @@ -292,6 +330,30 @@ case G_UREM: OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx]; break; + case G_LOAD: { + unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); + InstType InstTy = InstType::Integer; + if (!MRI.getType(MI.getOperand(0).getReg()).isPointer()) { + InstTy = TI.determineInstType(&MI); + } + + if (InstTy == InstType::FloatingPoint) { // fprb + OperandsMapping = + getOperandsMapping({Size == 32 ? &Mips::ValueMappings[Mips::SPRIdx] + : &Mips::ValueMappings[Mips::DPRIdx], + &Mips::ValueMappings[Mips::GPRIdx]}); + break; + } else { // gprb + OperandsMapping = + getOperandsMapping({Size <= 32 ? &Mips::ValueMappings[Mips::GPRIdx] + : &Mips::ValueMappings[Mips::DPRIdx], + &Mips::ValueMappings[Mips::GPRIdx]}); + if (Size == 64) + MappingID = CustomMappingID; + } + + break; + } case G_STORE: { unsigned Size = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); InstType InstTy = InstType::Integer; @@ -315,6 +377,13 @@ } break; } + case G_UNMERGE_VALUES: { + OperandsMapping = getOperandsMapping({&Mips::ValueMappings[Mips::GPRIdx], + &Mips::ValueMappings[Mips::GPRIdx], + &Mips::ValueMappings[Mips::DPRIdx]}); + MappingID = CustomMappingID; + break; + } case G_MERGE_VALUES: { OperandsMapping = getOperandsMapping({&Mips::ValueMappings[Mips::DPRIdx], &Mips::ValueMappings[Mips::GPRIdx], @@ -449,6 +518,7 @@ B, MF->getRegInfo(), *MF->getSubtarget().getLegalizerInfo()); switch (MI.getOpcode()) { + case TargetOpcode::G_LOAD: case TargetOpcode::G_STORE: { Helper.narrowScalar(MI, 0, LLT::scalar(32)); // Handle new instructions. @@ -462,7 +532,12 @@ ArtCombiner.tryCombineMerges(*NewMI, DeadInstrs); for (MachineInstr *DeadMI : DeadInstrs) DeadMI->eraseFromParent(); - } else + } + // This G_MERGE will be combined away when its corresponding G_UNMERGE + // gets regBankSelected. + else if (NewMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) + continue; + else // Manually set register banks for all register operands to 32 bit gprb. for (auto Op : NewMI->operands()) { if (Op.isReg()) { @@ -474,6 +549,13 @@ } return; } + case TargetOpcode::G_UNMERGE_VALUES: { + SmallVector DeadInstrs; + ArtCombiner.tryCombineMerges(MI, DeadInstrs); + for (MachineInstr *DeadMI : DeadInstrs) + DeadMI->eraseFromParent(); + return; + } default: break; } Index: llvm/trunk/test/CodeGen/Mips/GlobalISel/legalizer/load.mir =================================================================== --- llvm/trunk/test/CodeGen/Mips/GlobalISel/legalizer/load.mir +++ llvm/trunk/test/CodeGen/Mips/GlobalISel/legalizer/load.mir @@ -0,0 +1,94 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @load_i32(i32* %ptr) {entry: ret void} + define void @load_i64(i64* %ptr) {entry: ret void} + define void @load_float(float* %ptr) {entry: ret void} + define void @load_double(double* %ptr) {entry: ret void} + +... +--- +name: load_i32 +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_i32 + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[COPY]](p0) :: (load 4 from %ir.ptr) + ; MIPS32: $v0 = COPY [[LOAD]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(p0) = COPY $a0 + %1:_(s32) = G_LOAD %0(p0) :: (load 4 from %ir.ptr) + $v0 = COPY %1(s32) + RetRA implicit $v0 + +... +--- +name: load_i64 +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_i64 + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8 from %ir.ptr) + ; MIPS32: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[LOAD]](s64) + ; MIPS32: $v0 = COPY [[UV]](s32) + ; MIPS32: $v1 = COPY [[UV1]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 + %0:_(p0) = COPY $a0 + %1:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr) + %2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64) + $v0 = COPY %2(s32) + $v1 = COPY %3(s32) + RetRA implicit $v0, implicit $v1 + +... +--- +name: load_float +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_float + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[COPY]](p0) :: (load 4 from %ir.ptr) + ; MIPS32: $f0 = COPY [[LOAD]](s32) + ; MIPS32: RetRA implicit $f0 + %0:_(p0) = COPY $a0 + %1:_(s32) = G_LOAD %0(p0) :: (load 4 from %ir.ptr) + $f0 = COPY %1(s32) + RetRA implicit $f0 + +... +--- +name: load_double +alignment: 2 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_double + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:_(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8 from %ir.ptr) + ; MIPS32: $d0 = COPY [[LOAD]](s64) + ; MIPS32: RetRA implicit $d0 + %0:_(p0) = COPY $a0 + %1:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr) + $d0 = COPY %1(s64) + RetRA implicit $d0 + +... Index: llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/load.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/load.ll +++ llvm/trunk/test/CodeGen/Mips/GlobalISel/llvm-ir/load.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 + +define i32 @load_i32(i32* %ptr) { +; MIPS32-LABEL: load_i32: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lw $2, 0($4) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %0 = load i32, i32* %ptr + ret i32 %0 +} + +define i64 @load_i64(i64* %ptr) { +; MIPS32-LABEL: load_i64: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lw $2, 0($4) +; MIPS32-NEXT: ori $1, $zero, 4 +; MIPS32-NEXT: addu $1, $4, $1 +; MIPS32-NEXT: lw $3, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +entry: + %0 = load i64, i64* %ptr + ret i64 %0 +} Index: llvm/trunk/test/CodeGen/Mips/GlobalISel/regbankselect/load.mir =================================================================== --- llvm/trunk/test/CodeGen/Mips/GlobalISel/regbankselect/load.mir +++ llvm/trunk/test/CodeGen/Mips/GlobalISel/regbankselect/load.mir @@ -0,0 +1,100 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -mtriple=mipsel-linux-gnu -run-pass=regbankselect -verify-machineinstrs %s -o - | FileCheck %s -check-prefixes=MIPS32 +--- | + + define void @load_i32(i32* %ptr) {entry: ret void} + define void @load_i64(i64* %ptr) {entry: ret void} + define void @load_float(float* %ptr) {entry: ret void} + define void @load_double(double* %ptr) {entry: ret void} + +... +--- +name: load_i32 +alignment: 2 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_i32 + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:gprb(s32) = G_LOAD [[COPY]](p0) :: (load 4 from %ir.ptr) + ; MIPS32: $v0 = COPY [[LOAD]](s32) + ; MIPS32: RetRA implicit $v0 + %0:_(p0) = COPY $a0 + %1:_(s32) = G_LOAD %0(p0) :: (load 4 from %ir.ptr) + $v0 = COPY %1(s32) + RetRA implicit $v0 + +... +--- +name: load_i64 +alignment: 2 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_i64 + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:gprb(s32) = G_LOAD [[COPY]](p0) :: (load 4 from %ir.ptr, align 8) + ; MIPS32: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 4 + ; MIPS32: [[GEP:%[0-9]+]]:gprb(p0) = G_GEP [[COPY]], [[C]](s32) + ; MIPS32: [[LOAD1:%[0-9]+]]:gprb(s32) = G_LOAD [[GEP]](p0) :: (load 4 from %ir.ptr + 4, align 8) + ; MIPS32: $v0 = COPY [[LOAD]](s32) + ; MIPS32: $v1 = COPY [[LOAD1]](s32) + ; MIPS32: RetRA implicit $v0, implicit $v1 + %0:_(p0) = COPY $a0 + %1:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr) + %2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64) + $v0 = COPY %2(s32) + $v1 = COPY %3(s32) + RetRA implicit $v0, implicit $v1 + +... +--- +name: load_float +alignment: 2 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_float + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:fprb(s32) = G_LOAD [[COPY]](p0) :: (load 4 from %ir.ptr) + ; MIPS32: $f0 = COPY [[LOAD]](s32) + ; MIPS32: RetRA implicit $f0 + %0:_(p0) = COPY $a0 + %1:_(s32) = G_LOAD %0(p0) :: (load 4 from %ir.ptr) + $f0 = COPY %1(s32) + RetRA implicit $f0 + +... +--- +name: load_double +alignment: 2 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $a0 + + ; MIPS32-LABEL: name: load_double + ; MIPS32: liveins: $a0 + ; MIPS32: [[COPY:%[0-9]+]]:gprb(p0) = COPY $a0 + ; MIPS32: [[LOAD:%[0-9]+]]:fprb(s64) = G_LOAD [[COPY]](p0) :: (load 8 from %ir.ptr) + ; MIPS32: $d0 = COPY [[LOAD]](s64) + ; MIPS32: RetRA implicit $d0 + %0:_(p0) = COPY $a0 + %1:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr) + $d0 = COPY %1(s64) + RetRA implicit $d0 + +...