{p0, p0, 32, 8}})
.minScalar(0, s32);
+ getActionDefinitionsBuilder(G_UNMERGE_VALUES)
+ .legalFor({{s32, s64}});
+
getActionDefinitionsBuilder(G_MERGE_VALUES)
.legalFor({{s64, s32}});
}
}
+// 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) {
}
}
+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() &&
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);
}
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<MachineInstr *> &AdjacentInstrs) {
+ const MachineInstr *MI, SmallVectorImpl<MachineInstr *> &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;
}
case G_SUB:
case G_MUL:
case G_UMULH:
- case G_LOAD:
case G_ZEXTLOAD:
case G_SEXTLOAD:
case G_GEP:
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;
}
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],
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.
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()) {
}
return;
}
+ case TargetOpcode::G_UNMERGE_VALUES: {
+ SmallVector<MachineInstr *, 2> DeadInstrs;
+ ArtCombiner.tryCombineMerges(MI, DeadInstrs);
+ for (MachineInstr *DeadMI : DeadInstrs)
+ DeadMI->eraseFromParent();
+ return;
+ }
default:
break;
}
/// 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<MachineInstr *, 2> DefUses;
SmallVector<MachineInstr *, 2> UseDefs;
+ void addDefUses(Register Reg, const MachineRegisterInfo &MRI);
void addUseDef(Register Reg, const MachineRegisterInfo &MRI);
public:
AmbiguousRegDefUseContainer(const MachineInstr *MI);
+ SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; }
SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; }
};
bool visit(const MachineInstr *MI);
- /// Visit MI's adjacent UseDefs.
+ /// Visit MI's adjacent UseDefs or DefUses.
bool visitAdjacentInstrs(const MachineInstr *MI,
- SmallVectorImpl<MachineInstr *> &AdjacentInstrs);
+ SmallVectorImpl<MachineInstr *> &AdjacentInstrs,
+ bool isDefUse);
void setTypes(const MachineInstr *MI, InstType ITy);
--- /dev/null
+# 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
+
+...
--- /dev/null
+; 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
+}
--- /dev/null
+# 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
+
+...