Commit 1d0690bc by Jaydeep Patil Committed by Jim Stichnoth

[SubZero] Implement load and store for MIPS

This patch implements lowerLoad and extends existing lowerStore for byte, short and floating-point types. The patch also modifies PostLoweringLegalizer for conversion of mov to load or store. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2301303003 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent a0b720de
...@@ -649,10 +649,8 @@ void InstMIPS32Mov::dump(const Cfg *Func) const { ...@@ -649,10 +649,8 @@ void InstMIPS32Mov::dump(const Cfg *Func) const {
Str << ", "; Str << ", ";
DestHi->dump(Func); DestHi->dump(Func);
} }
dumpOpcode(Str, " = mov", getDest()->getType()); dumpOpcode(Str, " = mov", getDest()->getType());
Str << " "; Str << " ";
dumpSources(Func); dumpSources(Func);
} }
...@@ -711,9 +709,7 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -711,9 +709,7 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
const char *ActualOpcode = nullptr; const char *ActualOpcode = nullptr;
const bool DestIsReg = Dest->hasReg(); const bool DestIsReg = Dest->hasReg();
const bool DestIsMem = !Dest->hasReg();
const bool SrcIsReg = (SrcV && SrcV->hasReg()); const bool SrcIsReg = (SrcV && SrcV->hasReg());
const bool SrcIsMem = !(SrcV && SrcV->hasReg());
// reg to reg // reg to reg
if (DestIsReg && SrcIsReg) { if (DestIsReg && SrcIsReg) {
...@@ -729,8 +725,8 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -729,8 +725,8 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
case IceType_i16: case IceType_i16:
case IceType_i32: case IceType_i32:
Str << "\t" Str << "\t"
"move" << "move"
"\t"; << "\t";
getDest()->emit(Func); getDest()->emit(Func);
Str << ", "; Str << ", ";
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
...@@ -748,64 +744,7 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -748,64 +744,7 @@ void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
return; return;
} }
// reg to stack llvm::report_fatal_error("Invalid mov instruction. Dest or Src is memory.");
if (DestIsMem && SrcIsReg) {
switch (Dest->getType()) {
case IceType_f32:
ActualOpcode = "swc1";
break;
case IceType_f64:
ActualOpcode = "sdc1";
break;
case IceType_i1:
case IceType_i8:
case IceType_i16:
case IceType_i32:
ActualOpcode = "sw";
break;
default:
UnimplementedError(getFlags());
return;
}
assert(ActualOpcode);
Str << "\t" << ActualOpcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
return;
}
// stack to reg
if (DestIsReg && SrcIsMem) {
switch (Dest->getType()) {
case IceType_f32:
ActualOpcode = "lwc1";
break;
case IceType_f64:
ActualOpcode = "ldc1";
break;
case IceType_i1:
case IceType_i8:
case IceType_i16:
case IceType_i32:
ActualOpcode = "lw";
break;
default:
UnimplementedError(getFlags());
return;
}
assert(ActualOpcode);
Str << "\t" << ActualOpcode << "\t";
getDest()->emit(Func);
Str << ", ";
getSrc(0)->emit(Func);
return;
}
// stack to stack
llvm::report_fatal_error("mov cant copy stack to stack.");
} }
template <> void InstMIPS32Addiu::emitIAS(const Cfg *Func) const { template <> void InstMIPS32Addiu::emitIAS(const Cfg *Func) const {
......
...@@ -110,8 +110,21 @@ public: ...@@ -110,8 +110,21 @@ public:
static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset); static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset);
void dump(const Cfg *Func, Ostream &Str) const override { void dump(const Cfg *Func, Ostream &Str) const override {
(void)Func; if (!BuildDefs::dump())
(void)Str; return;
Str << "[";
if (Func)
getBase()->dump(Func);
else
getBase()->dump(Str);
Str << ", ";
getOffset()->dump(Func, Str);
Str << "] AddrMode==";
if (getAddrMode() == Offset) {
Str << "Offset";
} else {
Str << "Unknown";
}
} }
private: private:
...@@ -515,8 +528,37 @@ public: ...@@ -515,8 +528,37 @@ public:
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1); const Type Ty = getDest()->getType();
Str << "\t" << Opcode << "\t"; switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
<< "lb"
<< "\t";
break;
case IceType_i16:
Str << "\t"
<< "lh"
<< "\t";
break;
case IceType_i32:
Str << "\t"
<< "lw"
<< "\t";
break;
case IceType_f32:
Str << "\t"
<< "lwc1"
<< "\t";
break;
case IceType_f64:
Str << "\t"
<< "ldc1"
<< "\t";
break;
default:
llvm_unreachable("InstMIPS32Load unknown type");
}
getDest()->emit(Func); getDest()->emit(Func);
Str << ", "; Str << ", ";
emitRelocOp(Str, Reloc); emitRelocOp(Str, Reloc);
...@@ -532,13 +574,12 @@ public: ...@@ -532,13 +574,12 @@ public:
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Str << "\t" << Opcode << "\t"; dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
getDest()->dump(Func); getDest()->dump(Func);
Str << ", "; Str << ", ";
emitRelocOp(Str, Reloc); emitRelocOp(Str, Reloc);
Str << (Reloc ? "(" : "");
getSrc(0)->dump(Func); getSrc(0)->dump(Func);
Str << (Reloc ? ")" : "");
} }
static bool classof(const Inst *Inst) { return isClassof(Inst, K); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
...@@ -572,7 +613,37 @@ public: ...@@ -572,7 +613,37 @@ public:
return; return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 2); assert(getSrcSize() == 2);
Str << "\t" << Opcode << "\t"; const Type Ty = getSrc(0)->getType();
switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
<< "sb"
<< "\t";
break;
case IceType_i16:
Str << "\t"
<< "sh"
<< "\t";
break;
case IceType_i32:
Str << "\t"
<< "sw"
<< "\t";
break;
case IceType_f32:
Str << "\t"
<< "swc1"
<< "\t";
break;
case IceType_f64:
Str << "\t"
<< "sdc1"
<< "\t";
break;
default:
llvm_unreachable("InstMIPS32Store unknown type");
}
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
Str << ", "; Str << ", ";
emitRelocOp(Str, Reloc); emitRelocOp(Str, Reloc);
...@@ -581,20 +652,19 @@ public: ...@@ -581,20 +652,19 @@ public:
void emitIAS(const Cfg *Func) const override { void emitIAS(const Cfg *Func) const override {
(void)Func; (void)Func;
llvm_unreachable("Not yet implemented"); llvm_unreachable("InstMIPS32Store: Not yet implemented");
} }
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Str << "\t" << Opcode << "\t"; dumpOpcode(Str, Opcode, getSrc(0)->getType());
Str << " ";
getSrc(0)->dump(Func); getSrc(0)->dump(Func);
Str << ", "; Str << ", ";
emitRelocOp(Str, Reloc); emitRelocOp(Str, Reloc);
Str << (Reloc ? "(" : "");
getSrc(1)->dump(Func); getSrc(1)->dump(Func);
Str << (Reloc ? ")" : "");
} }
static bool classof(const Inst *Inst) { return isClassof(Inst, K); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
...@@ -775,11 +845,12 @@ public: ...@@ -775,11 +845,12 @@ public:
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " "; Str << " ";
Str << "\t" << Opcode << "\t";
dumpDest(Func); dumpDest(Func);
Str << ", "; Str << ", ";
dumpSources(Func); dumpSources(Func);
Str << ", ";
if (Signed) if (Signed)
Str << (int32_t)Imm; Str << (int32_t)Imm;
else else
......
...@@ -389,6 +389,11 @@ void TargetMIPS32::translateOm1() { ...@@ -389,6 +389,11 @@ void TargetMIPS32::translateOm1() {
return; return;
Func->dump("After stack frame mapping"); Func->dump("After stack frame mapping");
postLowerLegalization();
if (Func->hasError())
return;
Func->dump("After postLowerLegalization");
// Nop insertion // Nop insertion
if (getFlags().getShouldDoNopInsertion()) { if (getFlags().getShouldDoNopInsertion()) {
Func->doNopInsertion(); Func->doNopInsertion();
...@@ -496,13 +501,14 @@ OperandMIPS32Mem *TargetMIPS32::formMemoryOperand(Operand *Operand, Type Ty) { ...@@ -496,13 +501,14 @@ OperandMIPS32Mem *TargetMIPS32::formMemoryOperand(Operand *Operand, Type Ty) {
// OperandMIPS32Mem, so in that case it wouldn't need another level of // OperandMIPS32Mem, so in that case it wouldn't need another level of
// transformation. // transformation.
if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) { if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Operand)) {
return Mem; return llvm::cast<OperandMIPS32Mem>(legalize(Mem));
} }
// If we didn't do address mode optimization, then we only have a base/offset // If we didn't do address mode optimization, then we only have a base/offset
// to work with. MIPS always requires a base register, so just use that to // to work with. MIPS always requires a base register, so just use that to
// hold the operand. // hold the operand.
auto *Base = llvm::cast<Variable>(legalize(Operand, Legal_Reg)); auto *Base = llvm::cast<Variable>(
legalize(Operand, Legal_Reg | Legal_Rematerializable));
const int32_t Offset = Base->hasStackOffset() ? Base->getStackOffset() : 0; const int32_t Offset = Base->hasStackOffset() ? Base->getStackOffset() : 0;
return OperandMIPS32Mem::create( return OperandMIPS32Mem::create(
Func, Ty, Base, Func, Ty, Base,
...@@ -516,12 +522,17 @@ void TargetMIPS32::emitVariable(const Variable *Var) const { ...@@ -516,12 +522,17 @@ void TargetMIPS32::emitVariable(const Variable *Var) const {
const Type FrameSPTy = IceType_i32; const Type FrameSPTy = IceType_i32;
if (Var->hasReg()) { if (Var->hasReg()) {
Str << '$' << getRegName(Var->getRegNum(), Var->getType()); Str << '$' << getRegName(Var->getRegNum(), Var->getType());
} else { return;
int32_t Offset = Var->getStackOffset(); }
Str << Offset; if (Var->mustHaveReg()) {
Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
Str << ")"; ") has no register assigned - function " +
Func->getFunctionName());
} }
const int32_t Offset = Var->getStackOffset();
Str << Offset;
Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy);
Str << ")";
} }
TargetMIPS32::CallingConv::CallingConv() TargetMIPS32::CallingConv::CallingConv()
...@@ -1041,8 +1052,8 @@ Variable *TargetMIPS32::PostLoweringLegalizer::newBaseRegister( ...@@ -1041,8 +1052,8 @@ Variable *TargetMIPS32::PostLoweringLegalizer::newBaseRegister(
const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0; const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0;
Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum); Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum);
if (ShouldSub) { if (ShouldSub) {
Variable *OffsetVal = Variable *OffsetVal = Target->legalizeToReg(
Target->legalizeToReg(Target->Ctx->getConstantInt32(-Offset)); Target->Ctx->getConstantInt32(-Offset), ScratchRegNum);
Target->_sub(ScratchReg, Base, OffsetVal); Target->_sub(ScratchReg, Base, OffsetVal);
} else { } else {
Target->_addiu(ScratchReg, Base, Offset); Target->_addiu(ScratchReg, Base, Offset);
...@@ -1055,7 +1066,6 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) { ...@@ -1055,7 +1066,6 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
Variable *Dest = MovInstr->getDest(); Variable *Dest = MovInstr->getDest();
assert(Dest != nullptr); assert(Dest != nullptr);
const Type DestTy = Dest->getType(); const Type DestTy = Dest->getType();
(void)DestTy;
assert(DestTy != IceType_i64); assert(DestTy != IceType_i64);
Operand *Src = MovInstr->getSrc(0); Operand *Src = MovInstr->getSrc(0);
...@@ -1067,30 +1077,80 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) { ...@@ -1067,30 +1077,80 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
return; return;
bool Legalized = false; bool Legalized = false;
if (Dest->hasReg()) { if (!Dest->hasReg()) {
if (auto *Var = llvm::dyn_cast<Variable>(Src)) { auto *SrcR = llvm::cast<Variable>(Src);
if (Var->isRematerializable()) { assert(SrcR->hasReg());
// This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable). assert(!SrcR->isRematerializable());
const int32_t Offset = Dest->getStackOffset();
// ExtraOffset is only needed for frame-pointer based frames as we have
// to account for spill storage. // This is a _mov(Mem(), Variable), i.e., a store.
const int32_t ExtraOffset = (Var->getRegNum() == Target->getFrameReg()) auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
? Target->getFrameFixedAllocaOffset()
: 0; OperandMIPS32Mem *Addr = OperandMIPS32Mem::create(
Target->Func, DestTy, Base,
const int32_t Offset = Var->getStackOffset() + ExtraOffset; llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum()); // FP arguments are passed in GP reg if first argument is in GP. In this
Target->_mov(Dest, T); // case type of the SrcR is still FP thus we need to explicitly generate sw
// instead of swc1.
const RegNumT RegNum = SrcR->getRegNum();
const bool isSrcGPReg = ((unsigned)RegNum >= RegMIPS32::Reg_A0 &&
(unsigned)RegNum <= RegMIPS32::Reg_A3) ||
((unsigned)RegNum >= RegMIPS32::Reg_A0A1 &&
(unsigned)RegNum <= RegMIPS32::Reg_A2A3);
if (SrcTy == IceType_f32 && isSrcGPReg == true) {
Variable *SrcGPR = Target->makeReg(IceType_i32, RegNum);
Target->_sw(SrcGPR, Addr);
} else if (SrcTy == IceType_f64 && isSrcGPReg == true) {
Variable *SrcGPRHi, *SrcGPRLo;
if (RegNum == RegMIPS32::Reg_A0A1) {
SrcGPRLo = Target->makeReg(IceType_i32, RegMIPS32::Reg_A0);
SrcGPRHi = Target->makeReg(IceType_i32, RegMIPS32::Reg_A1);
} else {
SrcGPRLo = Target->makeReg(IceType_i32, RegMIPS32::Reg_A2);
SrcGPRHi = Target->makeReg(IceType_i32, RegMIPS32::Reg_A3);
}
OperandMIPS32Mem *AddrHi = OperandMIPS32Mem::create(
Target->Func, DestTy, Base,
llvm::cast<ConstantInteger32>(
Target->Ctx->getConstantInt32(Offset + 4)));
Target->_sw(SrcGPRLo, Addr);
Target->_sw(SrcGPRHi, AddrHi);
} else {
Target->_sw(SrcR, Addr);
}
Target->Context.insert<InstFakeDef>(Dest);
Legalized = true;
} else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
if (Var->isRematerializable()) {
// This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable).
// ExtraOffset is only needed for frame-pointer based frames as we have
// to account for spill storage.
const int32_t ExtraOffset = (Var->getRegNum() == Target->getFrameReg())
? Target->getFrameFixedAllocaOffset()
: 0;
const int32_t Offset = Var->getStackOffset() + ExtraOffset;
Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum());
Target->_mov(Dest, T);
Legalized = true;
} else {
if (!Var->hasReg()) {
// This is a _mov(Variable, Mem()), i.e., a load.
const int32_t Offset = Var->getStackOffset();
auto *Base = Target->getPhysicalRegister(Target->getFrameOrStackReg());
OperandMIPS32Mem *Addr;
Addr = OperandMIPS32Mem::create(
Target->Func, DestTy, Base,
llvm::cast<ConstantInteger32>(
Target->Ctx->getConstantInt32(Offset)));
Target->_lw(Dest, Addr);
Legalized = true; Legalized = true;
} else if (!Var->hasReg()) {
UnimplementedError(getFlags());
return;
} }
} }
} else {
UnimplementedError(getFlags());
return;
} }
if (Legalized) { if (Legalized) {
...@@ -1562,7 +1622,6 @@ void TargetMIPS32::lowerAssign(const InstAssign *Instr) { ...@@ -1562,7 +1622,6 @@ void TargetMIPS32::lowerAssign(const InstAssign *Instr) {
Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg); Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg);
auto *DestLo = llvm::cast<Variable>(loOperand(Dest)); auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
auto *DestHi = llvm::cast<Variable>(hiOperand(Dest)); auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
// Variable *T_Lo = nullptr, *T_Hi = nullptr;
auto *T_Lo = I32Reg(), *T_Hi = I32Reg(); auto *T_Lo = I32Reg(), *T_Hi = I32Reg();
_mov(T_Lo, Src0Lo); _mov(T_Lo, Src0Lo);
_mov(DestLo, T_Lo); _mov(DestLo, T_Lo);
...@@ -2242,7 +2301,13 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2242,7 +2301,13 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
} }
void TargetMIPS32::lowerLoad(const InstLoad *Instr) { void TargetMIPS32::lowerLoad(const InstLoad *Instr) {
UnimplementedLoweringError(this, Instr); // A Load instruction can be treated the same as an Assign instruction, after
// the source operand is transformed into an OperandARM32Mem operand.
Type Ty = Instr->getDest()->getType();
Operand *Src0 = formMemoryOperand(Instr->getSourceAddress(), Ty);
Variable *DestLoad = Instr->getDest();
auto *Assign = InstAssign::create(Func, DestLoad, Src0);
lowerAssign(Assign);
} }
void TargetMIPS32::doAddressOptLoad() { UnimplementedError(getFlags()); } void TargetMIPS32::doAddressOptLoad() { UnimplementedError(getFlags()); }
...@@ -2436,9 +2501,11 @@ Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) { ...@@ -2436,9 +2501,11 @@ Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) {
if (isVectorType(Ty)) { if (isVectorType(Ty)) {
UnimplementedError(getFlags()); UnimplementedError(getFlags());
} else { } else {
// Mov's Src operand can really only be the flexible second operand type if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(Src)) {
// or a register. Users should guarantee that. _lw(Reg, Mem);
_mov(Reg, Src); } else {
_mov(Reg, Src);
}
} }
return Reg; return Reg;
} }
...@@ -2450,11 +2517,59 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, ...@@ -2450,11 +2517,59 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
// to legalize() allow a physical register. Legal_Flex converts // to legalize() allow a physical register. Legal_Flex converts
// registers to the right type OperandMIPS32FlexReg as needed. // registers to the right type OperandMIPS32FlexReg as needed.
assert(Allowed & Legal_Reg); assert(Allowed & Legal_Reg);
if (RegNum.hasNoValue()) {
if (Variable *Subst = getContext().availabilityGet(From)) {
// At this point we know there is a potential substitution available.
if (!Subst->isRematerializable() && Subst->mustHaveReg() &&
!Subst->hasReg()) {
// At this point we know the substitution will have a register.
if (From->getType() == Subst->getType()) {
// At this point we know the substitution's register is compatible.
return Subst;
}
}
}
}
// Go through the various types of operands: // Go through the various types of operands:
// OperandMIPS32Mem, Constant, and Variable. // OperandMIPS32Mem, Constant, and Variable.
// Given the above assertion, if type of operand is not legal // Given the above assertion, if type of operand is not legal
// (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy // (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy
// to a register. // to a register.
if (auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(From)) {
// Base must be in a physical register.
Variable *Base = Mem->getBase();
ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
Variable *RegBase = nullptr;
assert(Base);
RegBase = llvm::cast<Variable>(
legalize(Base, Legal_Reg | Legal_Rematerializable));
if (Offset != nullptr && Offset->getValue() != 0) {
static constexpr bool ZeroExt = false;
if (!OperandMIPS32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) {
llvm::report_fatal_error("Invalid memory offset.");
}
}
// Create a new operand if there was a change.
if (Base != RegBase) {
Mem = OperandMIPS32Mem::create(Func, Ty, RegBase, Offset,
Mem->getAddrMode());
}
if (Allowed & Legal_Mem) {
From = Mem;
} else {
Variable *Reg = makeReg(Ty, RegNum);
_lw(Reg, Mem);
From = Reg;
}
return From;
}
if (llvm::isa<Constant>(From)) { if (llvm::isa<Constant>(From)) {
if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) { if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
(void)C; (void)C;
...@@ -2511,6 +2626,15 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, ...@@ -2511,6 +2626,15 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
} }
if (auto *Var = llvm::dyn_cast<Variable>(From)) { if (auto *Var = llvm::dyn_cast<Variable>(From)) {
if (Var->isRematerializable()) {
if (Allowed & Legal_Rematerializable) {
return From;
}
Variable *T = makeReg(Var->getType(), RegNum);
_mov(T, Var);
return T;
}
// Check if the variable is guaranteed a physical register. This // Check if the variable is guaranteed a physical register. This
// can happen either when the variable is pre-colored or when it is // can happen either when the variable is pre-colored or when it is
// assigned infinite weight. // assigned infinite weight.
......
...@@ -101,9 +101,7 @@ public: ...@@ -101,9 +101,7 @@ public:
PrologEmitsFixedAllocas = true; PrologEmitsFixedAllocas = true;
} }
int32_t getFrameFixedAllocaOffset() const override { int32_t getFrameFixedAllocaOffset() const override {
// TODO(sehr): Implement fixed stack layout. return FixedAllocaSizeBytes - (SpillAreaSizeBytes - MaxOutArgsSizeBytes);
llvm::report_fatal_error("Not yet implemented");
return 0;
} }
uint32_t maxOutArgsSizeBytes() const override { return MaxOutArgsSizeBytes; } uint32_t maxOutArgsSizeBytes() const override { return MaxOutArgsSizeBytes; }
...@@ -448,6 +446,7 @@ public: ...@@ -448,6 +446,7 @@ public:
Legal_Reg = 1 << 0, // physical register, not stack location Legal_Reg = 1 << 0, // physical register, not stack location
Legal_Imm = 1 << 1, Legal_Imm = 1 << 1,
Legal_Mem = 1 << 2, Legal_Mem = 1 << 2,
Legal_Rematerializable = 1 << 3,
Legal_Default = ~Legal_None Legal_Default = ~Legal_None
}; };
typedef uint32_t LegalMask; typedef uint32_t LegalMask;
......
...@@ -6,6 +6,13 @@ ...@@ -6,6 +6,13 @@
; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s
; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target mips32 -i %s --args -Om1 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
define internal float @loadFloat(i32 %a) { define internal float @loadFloat(i32 %a) {
entry: entry:
%__1 = inttoptr i32 %a to float* %__1 = inttoptr i32 %a to float*
...@@ -16,6 +23,9 @@ entry: ...@@ -16,6 +23,9 @@ entry:
; CHECK: movss ; CHECK: movss
; CHECK: fld ; CHECK: fld
; MIPS32-LABEL: loadFloat
; MIPS32: lwc1 $f{{.*}},0{{.*}}
define internal double @loadDouble(i32 %a) { define internal double @loadDouble(i32 %a) {
entry: entry:
%__1 = inttoptr i32 %a to double* %__1 = inttoptr i32 %a to double*
...@@ -26,6 +36,9 @@ entry: ...@@ -26,6 +36,9 @@ entry:
; CHECK: movsd ; CHECK: movsd
; CHECK: fld ; CHECK: fld
; MIPS32-LABEL: loadDouble
; MIPS32: ldc1 $f{{.*}},0{{.*}}
define internal void @storeFloat(i32 %a, float %value) { define internal void @storeFloat(i32 %a, float %value) {
entry: entry:
%__2 = inttoptr i32 %a to float* %__2 = inttoptr i32 %a to float*
...@@ -36,6 +49,9 @@ entry: ...@@ -36,6 +49,9 @@ entry:
; CHECK: movss ; CHECK: movss
; CHECK: movss ; CHECK: movss
; MIPS32-LABEL: storeFloat
; MIPS32: swc1 $f{{.*}},0{{.*}}
define internal void @storeDouble(i32 %a, double %value) { define internal void @storeDouble(i32 %a, double %value) {
entry: entry:
%__2 = inttoptr i32 %a to double* %__2 = inttoptr i32 %a to double*
...@@ -46,6 +62,10 @@ entry: ...@@ -46,6 +62,10 @@ entry:
; CHECK: movsd ; CHECK: movsd
; CHECK: movsd ; CHECK: movsd
; MIPS32-LABEL: storeDouble
; MIPS32: ldc1 $f{{.*}},4{{.*}}
; MIPS32: sdc1 $f{{.*}},0{{.*}}
define internal void @storeFloatConst(i32 %a) { define internal void @storeFloatConst(i32 %a) {
entry: entry:
%a.asptr = inttoptr i32 %a to float* %a.asptr = inttoptr i32 %a to float*
...@@ -56,6 +76,11 @@ entry: ...@@ -56,6 +76,11 @@ entry:
; CHECK: movss ; CHECK: movss
; CHECK: movss ; CHECK: movss
; MIPS32-LABEL: storeFloatConst
; MIPS32: lui {{.*}},{{.*}}
; MIPS32: lwc1 $f{{.*}},{{.*}}
; MIPS32: swc1 $f{{.*}},0{{.*}}
define internal void @storeDoubleConst(i32 %a) { define internal void @storeDoubleConst(i32 %a) {
entry: entry:
%a.asptr = inttoptr i32 %a to double* %a.asptr = inttoptr i32 %a to double*
...@@ -65,3 +90,8 @@ entry: ...@@ -65,3 +90,8 @@ entry:
; CHECK-LABEL: storeDoubleConst ; CHECK-LABEL: storeDoubleConst
; CHECK: movsd ; CHECK: movsd
; CHECK: movsd ; CHECK: movsd
; MIPS32-LABEL: storeDoubleConst
; MIPS32: lui {{.*}},{{.*}}
; MIPS32: ldc1 $f{{.*}},{{.*}}
; MIPS32: sdc1 $f{{.*}},0{{.*}}
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
; RUN: %p2i -i %s --args --verbose inst -threads=0 | FileCheck %s ; RUN: %p2i -i %s --args --verbose inst -threads=0 | FileCheck %s
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target mips32 -i %s --args -Om1 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
define internal void @load_i64(i32 %addr_arg) { define internal void @load_i64(i32 %addr_arg) {
entry: entry:
%__1 = inttoptr i32 %addr_arg to i64* %__1 = inttoptr i32 %addr_arg to i64*
...@@ -16,6 +23,10 @@ entry: ...@@ -16,6 +23,10 @@ entry:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
} }
; MIPS32-LABEL: load_i64
; MIPS32: lw {{.*}},0({{.*}})
; MIPS32-NEXT: lw {{.*}},4({{.*}})
define internal void @load_i32(i32 %addr_arg) { define internal void @load_i32(i32 %addr_arg) {
entry: entry:
%__1 = inttoptr i32 %addr_arg to i32* %__1 = inttoptr i32 %addr_arg to i32*
...@@ -28,6 +39,9 @@ entry: ...@@ -28,6 +39,9 @@ entry:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
} }
; MIPS32-LABEL: load_i32
; MIPS32: lw {{.*}},0({{.*}})
define internal void @load_i16(i32 %addr_arg) { define internal void @load_i16(i32 %addr_arg) {
entry: entry:
%__1 = inttoptr i32 %addr_arg to i16* %__1 = inttoptr i32 %addr_arg to i16*
...@@ -40,6 +54,9 @@ entry: ...@@ -40,6 +54,9 @@ entry:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
} }
; MIPS32-LABEL: load_i16
; MIPS32: lh {{.*}},0({{.*}})
define internal void @load_i8(i32 %addr_arg) { define internal void @load_i8(i32 %addr_arg) {
entry: entry:
%__1 = inttoptr i32 %addr_arg to i8* %__1 = inttoptr i32 %addr_arg to i8*
...@@ -51,3 +68,6 @@ entry: ...@@ -51,3 +68,6 @@ entry:
; CHECK-NEXT: %iv = load i8, i8* %addr_arg, align 1 ; CHECK-NEXT: %iv = load i8, i8* %addr_arg, align 1
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
} }
; MIPS32-LABEL: load_i8
; MIPS32: lb {{.*}},0({{.*}})
...@@ -56,7 +56,7 @@ entry: ...@@ -56,7 +56,7 @@ entry:
} }
; MIPS32-LABEL: store_i16 ; MIPS32-LABEL: store_i16
; MIPS32: li ; MIPS32: li
; MIPS32: sw ; MIPS32: sh
define internal void @store_i8(i32 %addr_arg) { define internal void @store_i8(i32 %addr_arg) {
entry: entry:
...@@ -71,4 +71,34 @@ entry: ...@@ -71,4 +71,34 @@ entry:
} }
; MIPS32-LABEL: store_i8 ; MIPS32-LABEL: store_i8
; MIPS32: li ; MIPS32: li
; MIPS32: sw ; MIPS32: sb
\ No newline at end of file
define internal void @store_f32(float* %faddr_arg) {
entry:
store float 1.000000e+00, float* %faddr_arg, align 4
ret void
; CHECK: Initial CFG
; CHECK: entry:
; CHECK-NEXT: store float 1.000000e+00, float* %faddr_arg, align 4
; CHECK-NEXT: ret void
}
; MIPS32-LABEL: store_f32
; MIPS32: lui
; MIPS32: lwc1
; MIPS32: swc1
define internal void @store_f64(double* %daddr_arg) {
entry:
store double 1.000000e+00, double* %daddr_arg, align 8
ret void
; CHECK: Initial CFG
; CHECK: entry:
; CHECK-NEXT: store double 1.000000e+00, double* %daddr_arg, align 8
; CHECK-NEXT: ret void
}
; MIPS32-LABEL: store_f64
; MIPS32: lui
; MIPS32: ldc1
; MIPS32: sdc1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment