mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-28 22:00:30 +00:00
[MIPS GlobalISel] Register bank select for G_STORE. Select i64 store
Select gprb or fprb when stored value is defined by either: copy from physical register or instruction with only one mapping available for that def operand. Store of integer s64 is handled with narrowScalar when mapping is applied, produced artifacts are combined away. Manually set gprb to all register operands of instructions created during narrowScalar. Differential Revision: https://reviews.llvm.org/D64268 llvm-svn: 365322
This commit is contained in:
parent
ee510131f8
commit
e165bef5cc
@ -39,9 +39,13 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
|
||||
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||
{s32, p0, 16, 8},
|
||||
{s32, p0, 32, 8},
|
||||
{s64, p0, 64, 8},
|
||||
{p0, p0, 32, 8}})
|
||||
.minScalar(0, s32);
|
||||
|
||||
getActionDefinitionsBuilder(G_MERGE_VALUES)
|
||||
.legalFor({{s64, s32}});
|
||||
|
||||
getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
|
||||
.legalForTypesWithMemDesc({{s32, p0, 8, 8},
|
||||
{s32, p0, 16, 8}})
|
||||
|
@ -10,14 +10,15 @@
|
||||
/// \todo This should be generated by TableGen.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsRegisterBankInfo.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
|
||||
#define GET_TARGET_REGBANK_IMPL
|
||||
|
||||
#define DEBUG_TYPE "registerbankinfo"
|
||||
|
||||
#include "MipsGenRegisterBank.inc"
|
||||
|
||||
namespace llvm {
|
||||
@ -91,9 +92,169 @@ const RegisterBank &MipsRegisterBankInfo::getRegBankFromRegClass(
|
||||
}
|
||||
}
|
||||
|
||||
// Instructions where all register operands are floating point.
|
||||
static bool isFloatingPointOpcode(unsigned Opc) {
|
||||
switch (Opc) {
|
||||
case TargetOpcode::G_FCONSTANT:
|
||||
case TargetOpcode::G_FADD:
|
||||
case TargetOpcode::G_FSUB:
|
||||
case TargetOpcode::G_FMUL:
|
||||
case TargetOpcode::G_FDIV:
|
||||
case TargetOpcode::G_FABS:
|
||||
case TargetOpcode::G_FSQRT:
|
||||
case TargetOpcode::G_FCEIL:
|
||||
case TargetOpcode::G_FFLOOR:
|
||||
case TargetOpcode::G_FPEXT:
|
||||
case TargetOpcode::G_FPTRUNC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Instructions where def operands are floating point registers.
|
||||
// Use operands are general purpose.
|
||||
static bool isFloatingPointOpcodeDef(unsigned Opc) {
|
||||
switch (Opc) {
|
||||
case TargetOpcode::G_SITOFP:
|
||||
case TargetOpcode::G_UITOFP:
|
||||
case Mips::MTC1:
|
||||
case Mips::BuildPairF64:
|
||||
case Mips::BuildPairF64_64:
|
||||
return true;
|
||||
default:
|
||||
return isFloatingPointOpcode(Opc);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isAmbiguous(unsigned Opc) {
|
||||
switch (Opc) {
|
||||
case TargetOpcode::G_LOAD:
|
||||
case TargetOpcode::G_STORE:
|
||||
case TargetOpcode::G_PHI:
|
||||
case TargetOpcode::G_SELECT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void MipsRegisterBankInfo::AmbiguousRegDefUseContainer::addUseDef(
|
||||
Register Reg, const MachineRegisterInfo &MRI) {
|
||||
assert(!MRI.getType(Reg).isPointer() &&
|
||||
"Pointers are gprb, they should not be considered as ambiguous.\n");
|
||||
MachineInstr *DefMI = MRI.getVRegDef(Reg);
|
||||
if (DefMI->getOpcode() == TargetOpcode::COPY &&
|
||||
!TargetRegisterInfo::isPhysicalRegister(DefMI->getOperand(1).getReg()))
|
||||
// Copies from non-physical registers are not supported.
|
||||
return;
|
||||
|
||||
UseDefs.push_back(DefMI);
|
||||
}
|
||||
|
||||
MipsRegisterBankInfo::AmbiguousRegDefUseContainer::AmbiguousRegDefUseContainer(
|
||||
const MachineInstr *MI) {
|
||||
assert(isAmbiguous(MI->getOpcode()) &&
|
||||
"Not implemented for non Ambiguous opcode.\n");
|
||||
|
||||
const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo();
|
||||
|
||||
if (MI->getOpcode() == TargetOpcode::G_STORE)
|
||||
addUseDef(MI->getOperand(0).getReg(), MRI);
|
||||
}
|
||||
|
||||
bool MipsRegisterBankInfo::TypeInfoForMF::visit(const MachineInstr *MI) {
|
||||
assert(isAmbiguous(MI->getOpcode()) && "Visiting non-Ambiguous opcode.\n");
|
||||
|
||||
startVisit(MI);
|
||||
AmbiguousRegDefUseContainer DefUseContainer(MI);
|
||||
|
||||
// Visit instructions that DEFINE MI's USE operands.
|
||||
if (visitAdjacentInstrs(MI, DefUseContainer.getUseDefs()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsRegisterBankInfo::TypeInfoForMF::visitAdjacentInstrs(
|
||||
const MachineInstr *MI, SmallVectorImpl<MachineInstr *> &AdjacentInstrs) {
|
||||
while (!AdjacentInstrs.empty()) {
|
||||
MachineInstr *AdjMI = AdjacentInstrs.pop_back_val();
|
||||
|
||||
if (isFloatingPointOpcodeDef(AdjMI->getOpcode())) {
|
||||
setTypes(MI, InstType::FloatingPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine InstType from register bank of phys register that is
|
||||
// use of this copy.
|
||||
if (AdjMI->getOpcode() == TargetOpcode::COPY) {
|
||||
setTypesAccordingToPhysicalRegister(MI, AdjMI, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isAmbiguous(AdjMI->getOpcode())) {
|
||||
// Chains of ambiguous instructions are not supported.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Defaults to integer instruction. Includes G_MERGE_VALUES and
|
||||
// G_UNMERGE_VALUES.
|
||||
setTypes(MI, InstType::Integer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MipsRegisterBankInfo::TypeInfoForMF::setTypes(const MachineInstr *MI,
|
||||
InstType InstTy) {
|
||||
changeRecordedTypeForInstr(MI, InstTy);
|
||||
}
|
||||
|
||||
void MipsRegisterBankInfo::TypeInfoForMF::setTypesAccordingToPhysicalRegister(
|
||||
const MachineInstr *MI, const MachineInstr *CopyInst, unsigned Op) {
|
||||
assert((TargetRegisterInfo::isPhysicalRegister(
|
||||
CopyInst->getOperand(Op).getReg())) &&
|
||||
"Copies of non physical registers should not be considered here.\n");
|
||||
|
||||
const MachineFunction &MF = *CopyInst->getMF();
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
|
||||
const RegisterBankInfo &RBI =
|
||||
*CopyInst->getMF()->getSubtarget().getRegBankInfo();
|
||||
const RegisterBank *Bank =
|
||||
RBI.getRegBank(CopyInst->getOperand(Op).getReg(), MRI, TRI);
|
||||
|
||||
if (Bank == &Mips::FPRBRegBank)
|
||||
setTypes(MI, InstType::FloatingPoint);
|
||||
else if (Bank == &Mips::GPRBRegBank)
|
||||
setTypes(MI, InstType::Integer);
|
||||
else
|
||||
llvm_unreachable("Unsupported register bank.\n");
|
||||
}
|
||||
|
||||
MipsRegisterBankInfo::InstType
|
||||
MipsRegisterBankInfo::TypeInfoForMF::determineInstType(const MachineInstr *MI) {
|
||||
visit(MI);
|
||||
return getRecordedTypeForInstr(MI);
|
||||
}
|
||||
|
||||
void MipsRegisterBankInfo::TypeInfoForMF::cleanupIfNewFunction(
|
||||
llvm::StringRef FunctionName) {
|
||||
if (MFName != FunctionName) {
|
||||
MFName = FunctionName;
|
||||
Types.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const RegisterBankInfo::InstructionMapping &
|
||||
MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
||||
|
||||
static TypeInfoForMF TI;
|
||||
|
||||
// Reset TI internal data when MF changes.
|
||||
TI.cleanupIfNewFunction(MI.getMF()->getName());
|
||||
|
||||
unsigned Opc = MI.getOpcode();
|
||||
const MachineFunction &MF = *MI.getParent()->getParent();
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
@ -106,6 +267,8 @@ MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
||||
|
||||
unsigned NumOperands = MI.getNumOperands();
|
||||
const ValueMapping *OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx];
|
||||
unsigned MappingID = DefaultMappingID;
|
||||
const unsigned CustomMappingID = 1;
|
||||
|
||||
switch (Opc) {
|
||||
case G_TRUNC:
|
||||
@ -114,7 +277,6 @@ MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
||||
case G_MUL:
|
||||
case G_UMULH:
|
||||
case G_LOAD:
|
||||
case G_STORE:
|
||||
case G_ZEXTLOAD:
|
||||
case G_SEXTLOAD:
|
||||
case G_GEP:
|
||||
@ -130,6 +292,36 @@ MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
||||
case G_UREM:
|
||||
OperandsMapping = &Mips::ValueMappings[Mips::GPRIdx];
|
||||
break;
|
||||
case G_STORE: {
|
||||
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_MERGE_VALUES: {
|
||||
OperandsMapping = getOperandsMapping({&Mips::ValueMappings[Mips::DPRIdx],
|
||||
&Mips::ValueMappings[Mips::GPRIdx],
|
||||
&Mips::ValueMappings[Mips::GPRIdx]});
|
||||
MappingID = CustomMappingID;
|
||||
break;
|
||||
}
|
||||
case G_FADD:
|
||||
case G_FSUB:
|
||||
case G_FMUL:
|
||||
@ -218,6 +410,73 @@ MipsRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
|
||||
return getInvalidInstructionMapping();
|
||||
}
|
||||
|
||||
return getInstructionMapping(DefaultMappingID, /*Cost=*/1, OperandsMapping,
|
||||
return getInstructionMapping(MappingID, /*Cost=*/1, OperandsMapping,
|
||||
NumOperands);
|
||||
}
|
||||
|
||||
using InstListTy = GISelWorkList<4>;
|
||||
namespace {
|
||||
class InstManager : public GISelChangeObserver {
|
||||
InstListTy &InstList;
|
||||
|
||||
public:
|
||||
InstManager(InstListTy &Insts) : InstList(Insts) {}
|
||||
|
||||
void createdInstr(MachineInstr &MI) override { InstList.insert(&MI); }
|
||||
void erasingInstr(MachineInstr &MI) override {}
|
||||
void changingInstr(MachineInstr &MI) override {}
|
||||
void changedInstr(MachineInstr &MI) override {}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// Here we have to narrowScalar s64 operands to s32, combine away
|
||||
/// G_MERGE/G_UNMERGE and erase instructions that became dead in the process.
|
||||
/// We manually assign 32 bit gprb to register operands of all new instructions
|
||||
/// that got created in the process since they will not end up in RegBankSelect
|
||||
/// loop. Careful not to delete instruction after MI i.e. MI.getIterator()++.
|
||||
void MipsRegisterBankInfo::applyMappingImpl(
|
||||
const OperandsMapper &OpdMapper) const {
|
||||
MachineInstr &MI = OpdMapper.getMI();
|
||||
InstListTy NewInstrs;
|
||||
MachineIRBuilder B(MI);
|
||||
MachineFunction *MF = MI.getMF();
|
||||
MachineRegisterInfo &MRI = OpdMapper.getMRI();
|
||||
|
||||
InstManager NewInstrObserver(NewInstrs);
|
||||
GISelObserverWrapper WrapperObserver(&NewInstrObserver);
|
||||
LegalizerHelper Helper(*MF, WrapperObserver, B);
|
||||
LegalizationArtifactCombiner ArtCombiner(
|
||||
B, MF->getRegInfo(), *MF->getSubtarget().getLegalizerInfo());
|
||||
|
||||
switch (MI.getOpcode()) {
|
||||
case TargetOpcode::G_STORE: {
|
||||
Helper.narrowScalar(MI, 0, LLT::scalar(32));
|
||||
// Handle new instructions.
|
||||
while (!NewInstrs.empty()) {
|
||||
MachineInstr *NewMI = NewInstrs.pop_back_val();
|
||||
// This is new G_UNMERGE that was created during narrowScalar and will
|
||||
// not be considered for regbank selection. RegBankSelect for mips
|
||||
// visits/makes corresponding G_MERGE first. Combine them here.
|
||||
if (NewMI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
|
||||
SmallVector<MachineInstr *, 2> DeadInstrs;
|
||||
ArtCombiner.tryCombineMerges(*NewMI, DeadInstrs);
|
||||
for (MachineInstr *DeadMI : DeadInstrs)
|
||||
DeadMI->eraseFromParent();
|
||||
} else
|
||||
// Manually set register banks for all register operands to 32 bit gprb.
|
||||
for (auto Op : NewMI->operands()) {
|
||||
if (Op.isReg()) {
|
||||
assert(MRI.getType(Op.getReg()).getSizeInBits() == 32 &&
|
||||
"Only 32 bit gprb is handled here.\n");
|
||||
MRI.setRegBank(Op.getReg(), getRegBank(Mips::GPRBRegBankID));
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return applyDefaultMapping(OpdMapper);
|
||||
}
|
||||
|
@ -37,6 +37,82 @@ public:
|
||||
|
||||
const InstructionMapping &
|
||||
getInstrMapping(const MachineInstr &MI) const override;
|
||||
|
||||
void applyMappingImpl(const OperandsMapper &OpdMapper) const override;
|
||||
|
||||
private:
|
||||
/// Some instructions are used with both floating point and integer operands.
|
||||
/// We assign InstType to such instructions as it helps us to avoid cross bank
|
||||
/// copies. InstType deppends on context.
|
||||
enum InstType {
|
||||
NotDetermined,
|
||||
/// Connected with instruction that interprets 'bags of bits' as integers.
|
||||
/// Select gprb to avoid cross bank copies.
|
||||
Integer,
|
||||
/// Connected with instruction that interprets 'bags of bits' as floating
|
||||
/// point numbers. Select fprb to avoid cross bank copies.
|
||||
FloatingPoint
|
||||
};
|
||||
|
||||
/// 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:
|
||||
/// UseDefs : MachineInstrs that define MI's ambiguous use operands.
|
||||
class AmbiguousRegDefUseContainer {
|
||||
SmallVector<MachineInstr *, 2> UseDefs;
|
||||
|
||||
void addUseDef(Register Reg, const MachineRegisterInfo &MRI);
|
||||
|
||||
public:
|
||||
AmbiguousRegDefUseContainer(const MachineInstr *MI);
|
||||
SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; }
|
||||
};
|
||||
|
||||
class TypeInfoForMF {
|
||||
/// MachineFunction name is used to recognise when MF changes.
|
||||
std::string MFName = "";
|
||||
/// Recorded InstTypes for visited instructions.
|
||||
DenseMap<const MachineInstr *, InstType> Types;
|
||||
|
||||
bool visit(const MachineInstr *MI);
|
||||
|
||||
/// Visit MI's adjacent UseDefs.
|
||||
bool visitAdjacentInstrs(const MachineInstr *MI,
|
||||
SmallVectorImpl<MachineInstr *> &AdjacentInstrs);
|
||||
|
||||
void setTypes(const MachineInstr *MI, InstType ITy);
|
||||
|
||||
/// InstType for MI is determined, set it to InstType that corresponds to
|
||||
/// physical regisiter that is operand number Op in CopyInst.
|
||||
void setTypesAccordingToPhysicalRegister(const MachineInstr *MI,
|
||||
const MachineInstr *CopyInst,
|
||||
unsigned Op);
|
||||
|
||||
/// Set default values for MI in order to start visit.
|
||||
void startVisit(const MachineInstr *MI) {
|
||||
Types.try_emplace(MI, InstType::NotDetermined);
|
||||
}
|
||||
|
||||
bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); };
|
||||
|
||||
/// Returns recorded type for instruction.
|
||||
const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const {
|
||||
assert(wasVisited(MI) && "Instruction was not visited!");
|
||||
return Types.find(MI)->getSecond();
|
||||
};
|
||||
|
||||
/// Change recorded type for instruction.
|
||||
void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) {
|
||||
assert(wasVisited(MI) && "Instruction was not visited!");
|
||||
Types.find(MI)->getSecond() = InstTy;
|
||||
};
|
||||
|
||||
public:
|
||||
InstType determineInstType(const MachineInstr *MI);
|
||||
|
||||
void cleanupIfNewFunction(llvm::StringRef FunctionName);
|
||||
};
|
||||
};
|
||||
} // end namespace llvm
|
||||
#endif
|
||||
|
98
test/CodeGen/Mips/GlobalISel/legalizer/store.mir
Normal file
98
test/CodeGen/Mips/GlobalISel/legalizer/store.mir
Normal file
@ -0,0 +1,98 @@
|
||||
# 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 @store_i32(i32* %ptr) { entry: ret void }
|
||||
define void @store_i64(i64* %ptr) { entry: ret void }
|
||||
define void @store_float(float* %ptr) { entry: ret void }
|
||||
define void @store_double(double* %ptr) { entry: ret void }
|
||||
|
||||
...
|
||||
---
|
||||
name: store_i32
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a0, $a1
|
||||
|
||||
; MIPS32-LABEL: name: store_i32
|
||||
; MIPS32: liveins: $a0, $a1
|
||||
; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:_(p0) = COPY $a1
|
||||
; MIPS32: G_STORE [[COPY]](s32), [[COPY1]](p0) :: (store 4 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s32) = COPY $a0
|
||||
%1:_(p0) = COPY $a1
|
||||
G_STORE %0(s32), %1(p0) :: (store 4 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_i64
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a0, $a1, $a2
|
||||
|
||||
; MIPS32-LABEL: name: store_i64
|
||||
; MIPS32: liveins: $a0, $a1, $a2
|
||||
; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $a0
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:_(s32) = COPY $a1
|
||||
; MIPS32: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
|
||||
; MIPS32: [[COPY2:%[0-9]+]]:_(p0) = COPY $a2
|
||||
; MIPS32: G_STORE [[MV]](s64), [[COPY2]](p0) :: (store 8 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%2:_(s32) = COPY $a0
|
||||
%3:_(s32) = COPY $a1
|
||||
%0:_(s64) = G_MERGE_VALUES %2(s32), %3(s32)
|
||||
%1:_(p0) = COPY $a2
|
||||
G_STORE %0(s64), %1(p0) :: (store 8 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_float
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a1, $f12
|
||||
|
||||
; MIPS32-LABEL: name: store_float
|
||||
; MIPS32: liveins: $a1, $f12
|
||||
; MIPS32: [[COPY:%[0-9]+]]:_(s32) = COPY $f12
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:_(p0) = COPY $a1
|
||||
; MIPS32: G_STORE [[COPY]](s32), [[COPY1]](p0) :: (store 4 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s32) = COPY $f12
|
||||
%1:_(p0) = COPY $a1
|
||||
G_STORE %0(s32), %1(p0) :: (store 4 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_double
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a2, $d6
|
||||
|
||||
; MIPS32-LABEL: name: store_double
|
||||
; MIPS32: liveins: $a2, $d6
|
||||
; MIPS32: [[COPY:%[0-9]+]]:_(s64) = COPY $d6
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:_(p0) = COPY $a2
|
||||
; MIPS32: G_STORE [[COPY]](s64), [[COPY1]](p0) :: (store 8 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s64) = COPY $d6
|
||||
%1:_(p0) = COPY $a2
|
||||
G_STORE %0(s64), %1(p0) :: (store 8 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
27
test/CodeGen/Mips/GlobalISel/llvm-ir/store.ll
Normal file
27
test/CodeGen/Mips/GlobalISel/llvm-ir/store.ll
Normal file
@ -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 void @store_i32(i32 %val, i32* %ptr) {
|
||||
; MIPS32-LABEL: store_i32:
|
||||
; MIPS32: # %bb.0: # %entry
|
||||
; MIPS32-NEXT: sw $4, 0($5)
|
||||
; MIPS32-NEXT: jr $ra
|
||||
; MIPS32-NEXT: nop
|
||||
entry:
|
||||
store i32 %val, i32* %ptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @store_i64(i64 %val, i64* %ptr) {
|
||||
; MIPS32-LABEL: store_i64:
|
||||
; MIPS32: # %bb.0: # %entry
|
||||
; MIPS32-NEXT: sw $4, 0($6)
|
||||
; MIPS32-NEXT: ori $1, $zero, 4
|
||||
; MIPS32-NEXT: addu $1, $6, $1
|
||||
; MIPS32-NEXT: sw $5, 0($1)
|
||||
; MIPS32-NEXT: jr $ra
|
||||
; MIPS32-NEXT: nop
|
||||
entry:
|
||||
store i64 %val, i64* %ptr
|
||||
ret void
|
||||
}
|
100
test/CodeGen/Mips/GlobalISel/regbankselect/store.mir
Normal file
100
test/CodeGen/Mips/GlobalISel/regbankselect/store.mir
Normal file
@ -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 @store_i32(i32* %ptr) { entry: ret void }
|
||||
define void @store_i64(i64* %ptr) { entry: ret void }
|
||||
define void @store_float(float* %ptr) { entry: ret void }
|
||||
define void @store_double(double* %ptr) { entry: ret void }
|
||||
|
||||
...
|
||||
---
|
||||
name: store_i32
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a0, $a1
|
||||
|
||||
; MIPS32-LABEL: name: store_i32
|
||||
; MIPS32: liveins: $a0, $a1
|
||||
; MIPS32: [[COPY:%[0-9]+]]:gprb(s32) = COPY $a0
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:gprb(p0) = COPY $a1
|
||||
; MIPS32: G_STORE [[COPY]](s32), [[COPY1]](p0) :: (store 4 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s32) = COPY $a0
|
||||
%1:_(p0) = COPY $a1
|
||||
G_STORE %0(s32), %1(p0) :: (store 4 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_i64
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a0, $a1, $a2
|
||||
|
||||
; MIPS32-LABEL: name: store_i64
|
||||
; MIPS32: liveins: $a0, $a1, $a2
|
||||
; MIPS32: [[COPY:%[0-9]+]]:gprb(s32) = COPY $a0
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:gprb(s32) = COPY $a1
|
||||
; MIPS32: [[COPY2:%[0-9]+]]:gprb(p0) = COPY $a2
|
||||
; MIPS32: G_STORE [[COPY]](s32), [[COPY2]](p0) :: (store 4 into %ir.ptr, align 8)
|
||||
; MIPS32: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 4
|
||||
; MIPS32: [[GEP:%[0-9]+]]:gprb(p0) = G_GEP [[COPY2]], [[C]](s32)
|
||||
; MIPS32: G_STORE [[COPY1]](s32), [[GEP]](p0) :: (store 4 into %ir.ptr + 4, align 8)
|
||||
; MIPS32: RetRA
|
||||
%2:_(s32) = COPY $a0
|
||||
%3:_(s32) = COPY $a1
|
||||
%0:_(s64) = G_MERGE_VALUES %2(s32), %3(s32)
|
||||
%1:_(p0) = COPY $a2
|
||||
G_STORE %0(s64), %1(p0) :: (store 8 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_float
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a1, $f12
|
||||
|
||||
; MIPS32-LABEL: name: store_float
|
||||
; MIPS32: liveins: $a1, $f12
|
||||
; MIPS32: [[COPY:%[0-9]+]]:fprb(s32) = COPY $f12
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:gprb(p0) = COPY $a1
|
||||
; MIPS32: G_STORE [[COPY]](s32), [[COPY1]](p0) :: (store 4 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s32) = COPY $f12
|
||||
%1:_(p0) = COPY $a1
|
||||
G_STORE %0(s32), %1(p0) :: (store 4 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
||||
---
|
||||
name: store_double
|
||||
alignment: 2
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.1.entry:
|
||||
liveins: $a2, $d6
|
||||
|
||||
; MIPS32-LABEL: name: store_double
|
||||
; MIPS32: liveins: $a2, $d6
|
||||
; MIPS32: [[COPY:%[0-9]+]]:fprb(s64) = COPY $d6
|
||||
; MIPS32: [[COPY1:%[0-9]+]]:gprb(p0) = COPY $a2
|
||||
; MIPS32: G_STORE [[COPY]](s64), [[COPY1]](p0) :: (store 8 into %ir.ptr)
|
||||
; MIPS32: RetRA
|
||||
%0:_(s64) = COPY $d6
|
||||
%1:_(p0) = COPY $a2
|
||||
G_STORE %0(s64), %1(p0) :: (store 8 into %ir.ptr)
|
||||
RetRA
|
||||
|
||||
...
|
Loading…
Reference in New Issue
Block a user