Commit d1e97776 by Mohit Bhakkad Committed by Jim Stichnoth

SubZero: legalize for f32/f64 constants in MIPS32

R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2123723002 . Patch from Mohit Bhakkad <mohit.bhakkad@imgtec.com>.
parent 36847bdd
...@@ -46,7 +46,7 @@ bool OperandMIPS32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { ...@@ -46,7 +46,7 @@ bool OperandMIPS32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) {
} }
OperandMIPS32Mem::OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, OperandMIPS32Mem::OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset, AddrMode Mode) Operand *ImmOffset, AddrMode Mode)
: OperandMIPS32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Mode(Mode) { : OperandMIPS32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Mode(Mode) {
// The Neg modes are only needed for Reg +/- Reg. // The Neg modes are only needed for Reg +/- Reg.
(void)Func; (void)Func;
...@@ -121,6 +121,25 @@ template <> const char *InstMIPS32Trunc_w_s::Opcode = "trunc.w.s"; ...@@ -121,6 +121,25 @@ template <> const char *InstMIPS32Trunc_w_s::Opcode = "trunc.w.s";
template <> const char *InstMIPS32Xor::Opcode = "xor"; template <> const char *InstMIPS32Xor::Opcode = "xor";
template <> const char *InstMIPS32Xori::Opcode = "xori"; template <> const char *InstMIPS32Xori::Opcode = "xori";
template <> void InstMIPS32Lui::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
Str << "\t" << Opcode << "\t";
getDest()->emit(Func);
Str << ", ";
auto *Src0 = llvm::cast<Constant>(getSrc(0));
if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) {
emitRelocOp(Str, Reloc);
Str << "(";
CR->emitWithoutPrefix(Func->getTarget());
Str << ")";
} else {
Src0->emit(Func);
}
}
template <> void InstMIPS32Mflo::emit(const Cfg *Func) const { template <> void InstMIPS32Mflo::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -260,8 +279,11 @@ void OperandMIPS32Mem::emit(const Cfg *Func) const { ...@@ -260,8 +279,11 @@ void OperandMIPS32Mem::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
ConstantInteger32 *Offset = getOffset(); Operand *Offset = getOffset();
Offset->emit(Func); if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
CR->emitWithoutPrefix(Func->getTarget());
} else
Offset->emit(Func);
Str << "("; Str << "(";
getBase()->emit(Func); getBase()->emit(Func);
Str << ")"; Str << ")";
......
...@@ -28,6 +28,21 @@ ...@@ -28,6 +28,21 @@
namespace Ice { namespace Ice {
namespace MIPS32 { namespace MIPS32 {
enum RelocOp { RO_No, RO_Hi, RO_Lo };
inline void emitRelocOp(Ostream &Str, RelocOp Reloc) {
switch (Reloc) {
case RO_No:
break;
case RO_Hi:
Str << "%hi";
break;
case RO_Lo:
Str << "%lo";
break;
}
}
class TargetMIPS32; class TargetMIPS32;
/// OperandMips32 extends the Operand hierarchy. /// OperandMips32 extends the Operand hierarchy.
...@@ -72,14 +87,13 @@ public: ...@@ -72,14 +87,13 @@ public:
/// general Constant operands like ConstantRelocatable, since a relocatable /// general Constant operands like ConstantRelocatable, since a relocatable
/// can potentially take up too many bits. /// can potentially take up too many bits.
static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base, static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset, Operand *ImmOffset, AddrMode Mode = Offset) {
AddrMode Mode = Offset) {
return new (Func->allocate<OperandMIPS32Mem>()) return new (Func->allocate<OperandMIPS32Mem>())
OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode); OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode);
} }
Variable *getBase() const { return Base; } Variable *getBase() const { return Base; }
ConstantInteger32 *getOffset() const { return ImmOffset; } Operand *getOffset() const { return ImmOffset; }
AddrMode getAddrMode() const { return Mode; } AddrMode getAddrMode() const { return Mode; }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
...@@ -101,12 +115,12 @@ public: ...@@ -101,12 +115,12 @@ public:
} }
private: private:
OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, Operand *ImmOffset,
ConstantInteger32 *ImmOffset, AddrMode Mode); AddrMode Mode);
Variable *Base; Variable *Base;
ConstantInteger32 *ImmOffset; Operand *const ImmOffset;
AddrMode Mode; const AddrMode Mode;
}; };
/// Base class for Mips instructions. /// Base class for Mips instructions.
...@@ -254,9 +268,10 @@ class InstMIPS32UnaryopGPR : public InstMIPS32 { ...@@ -254,9 +268,10 @@ class InstMIPS32UnaryopGPR : public InstMIPS32 {
InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete; InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete;
public: public:
static InstMIPS32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) { static InstMIPS32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
RelocOp Reloc = RO_No) {
return new (Func->allocate<InstMIPS32UnaryopGPR>()) return new (Func->allocate<InstMIPS32UnaryopGPR>())
InstMIPS32UnaryopGPR(Func, Dest, Src); InstMIPS32UnaryopGPR(Func, Dest, Src, Reloc);
} }
void emit(const Cfg *Func) const override { void emit(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
...@@ -280,13 +295,15 @@ public: ...@@ -280,13 +295,15 @@ public:
static bool classof(const Inst *Inst) { return isClassof(Inst, K); } static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
protected: protected:
InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src) InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src,
: InstMIPS32(Func, K, 1, Dest) { RelocOp Reloc = RO_No)
: InstMIPS32(Func, K, 1, Dest), Reloc(Reloc) {
addSource(Src); addSource(Src);
} }
private: private:
static const char *Opcode; static const char *Opcode;
const RelocOp Reloc;
}; };
/// Instructions of the form opcode reg, reg. /// Instructions of the form opcode reg, reg.
...@@ -485,9 +502,10 @@ class InstMIPS32Memory : public InstMIPS32 { ...@@ -485,9 +502,10 @@ class InstMIPS32Memory : public InstMIPS32 {
public: public:
static InstMIPS32Memory *create(Cfg *Func, Variable *Value, static InstMIPS32Memory *create(Cfg *Func, Variable *Value,
OperandMIPS32Mem *Mem) { OperandMIPS32Mem *Mem,
RelocOp Reloc = RO_No) {
return new (Func->allocate<InstMIPS32Memory>()) return new (Func->allocate<InstMIPS32Memory>())
InstMIPS32Memory(Func, Value, Mem); InstMIPS32Memory(Func, Value, Mem, Reloc);
} }
void emit(const Cfg *Func) const override { void emit(const Cfg *Func) const override {
...@@ -498,7 +516,10 @@ public: ...@@ -498,7 +516,10 @@ public:
Str << "\t" << Opcode << "\t"; Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
Str << ", "; Str << ", ";
emitRelocOp(Str, Reloc);
Str << (Reloc ? "(" : "");
getSrc(1)->emit(Func); getSrc(1)->emit(Func);
Str << (Reloc ? ")" : "");
} }
void emitIAS(const Cfg *Func) const override { void emitIAS(const Cfg *Func) const override {
...@@ -511,20 +532,24 @@ public: ...@@ -511,20 +532,24 @@ public:
return; return;
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
Str << "\t" << Opcode << "\t"; Str << "\t" << Opcode << "\t";
Str << " ";
getSrc(1)->dump(Func);
Str << ", ";
getSrc(0)->dump(Func); getSrc(0)->dump(Func);
Str << ", ";
emitRelocOp(Str, Reloc);
Str << (Reloc ? "(" : "");
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); }
private: private:
InstMIPS32Memory(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem) InstMIPS32Memory(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem,
: InstMIPS32(Func, K, 2, nullptr) { RelocOp Reloc = RO_No)
: InstMIPS32(Func, K, 2, nullptr), Reloc(Reloc) {
addSource(Value); addSource(Value);
addSource(Mem); addSource(Mem);
} }
static const char *Opcode; static const char *Opcode;
const RelocOp Reloc;
}; };
// InstMIPS32Label represents an intra-block label that is the target of an // InstMIPS32Label represents an intra-block label that is the target of an
...@@ -735,7 +760,7 @@ using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>; ...@@ -735,7 +760,7 @@ using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>;
using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>; using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>; using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Ldc1 = InstMIPS32Memory<InstMIPS32::Ldc1>; using InstMIPS32Ldc1 = InstMIPS32Memory<InstMIPS32::Ldc1>;
using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>; using InstMIPS32Lui = InstMIPS32UnaryopGPR<InstMIPS32::Lui>;
using InstMIPS32Lw = InstMIPS32Memory<InstMIPS32::Lw>; using InstMIPS32Lw = InstMIPS32Memory<InstMIPS32::Lw>;
using InstMIPS32Lwc1 = InstMIPS32Memory<InstMIPS32::Lwc1>; using InstMIPS32Lwc1 = InstMIPS32Memory<InstMIPS32::Lwc1>;
using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>; using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>;
...@@ -827,6 +852,7 @@ template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const; ...@@ -827,6 +852,7 @@ template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const;
template <> void InstMIPS32Mthi::emit(const Cfg *Func) const; template <> void InstMIPS32Mthi::emit(const Cfg *Func) const;
template <> void InstMIPS32Mult::emit(const Cfg *Func) const; template <> void InstMIPS32Mult::emit(const Cfg *Func) const;
template <> void InstMIPS32Multu::emit(const Cfg *Func) const; template <> void InstMIPS32Multu::emit(const Cfg *Func) const;
template <> void InstMIPS32Lui::emit(const Cfg *Func) const;
} // end of namespace MIPS32 } // end of namespace MIPS32
} // end of namespace Ice } // end of namespace Ice
......
...@@ -1021,7 +1021,7 @@ Operand *TargetMIPS32::hiOperand(Operand *Operand) { ...@@ -1021,7 +1021,7 @@ Operand *TargetMIPS32::hiOperand(Operand *Operand) {
assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset); assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
const Type SplitType = IceType_i32; const Type SplitType = IceType_i32;
Variable *Base = Mem->getBase(); Variable *Base = Mem->getBase();
ConstantInteger32 *Offset = Mem->getOffset(); auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4)); assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
int32_t NextOffsetVal = Offset->getValue() + 4; int32_t NextOffsetVal = Offset->getValue() + 4;
constexpr bool SignExt = false; constexpr bool SignExt = false;
...@@ -2214,38 +2214,57 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, ...@@ -2214,38 +2214,57 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
// 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 *C = llvm::dyn_cast<ConstantRelocatable>(From)) { if (llvm::isa<Constant>(From)) {
(void)C; if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
// TODO(reed kotler): complete this case for proper implementation (void)C;
Variable *Reg = makeReg(Ty, RegNum); // TODO(reed kotler): complete this case for proper implementation
Context.insert<InstFakeDef>(Reg); Variable *Reg = makeReg(Ty, RegNum);
return Reg; Context.insert<InstFakeDef>(Reg);
} else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) { return Reg;
const uint32_t Value = C32->getValue(); } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
// Check if the immediate will fit in a Flexible second operand, const uint32_t Value = C32->getValue();
// if a Flexible second operand is allowed. We need to know the exact // Check if the immediate will fit in a Flexible second operand,
// value, so that rules out relocatable constants. // if a Flexible second operand is allowed. We need to know the exact
// Also try the inverse and use MVN if possible. // value, so that rules out relocatable constants.
// Do a movw/movt to a register. // Also try the inverse and use MVN if possible.
Variable *Reg; // Do a movw/movt to a register.
if (RegNum.hasValue()) Variable *Reg;
Reg = getPhysicalRegister(RegNum); if (RegNum.hasValue())
else Reg = getPhysicalRegister(RegNum);
Reg = makeReg(Ty, RegNum); else
if (isInt<16>(int32_t(Value))) { Reg = makeReg(Ty, RegNum);
Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty); if (isInt<16>(int32_t(Value))) {
Context.insert<InstFakeDef>(Zero); Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty);
_addiu(Reg, Zero, Value); Context.insert<InstFakeDef>(Zero);
} else { _addiu(Reg, Zero, Value);
uint32_t UpperBits = (Value >> 16) & 0xFFFF; } else {
(void)UpperBits; uint32_t UpperBits = (Value >> 16) & 0xFFFF;
uint32_t LowerBits = Value & 0xFFFF; (void)UpperBits;
Variable *TReg = makeReg(Ty, RegNum); uint32_t LowerBits = Value & 0xFFFF;
_lui(TReg, UpperBits); Variable *TReg = makeReg(Ty, RegNum);
_ori(Reg, TReg, LowerBits); _lui(TReg, Ctx->getConstantInt32(UpperBits));
_ori(Reg, TReg, LowerBits);
}
return Reg;
} else if (isScalarFloatingType(Ty)) {
// Load floats/doubles from literal pool.
auto *CFrom = llvm::cast<Constant>(From);
assert(CFrom->getShouldBePooled());
Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
Variable *TReg1 = makeReg(getPointerType());
Variable *TReg2 = makeReg(Ty);
Context.insert<InstFakeDef>(TReg2);
_lui(TReg1, Offset, RO_Hi);
OperandMIPS32Mem *Addr =
OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
if (Ty == IceType_f32)
_lwc1(TReg2, Addr, RO_Lo);
else
_ldc1(TReg2, Addr, RO_Lo);
return copyToReg(TReg2, RegNum);
} }
return Reg;
} }
if (auto *Var = llvm::dyn_cast<Variable>(From)) { if (auto *Var = llvm::dyn_cast<Variable>(From)) {
// 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
......
...@@ -35,7 +35,11 @@ public: ...@@ -35,7 +35,11 @@ public:
static void staticInit(GlobalContext *Ctx); static void staticInit(GlobalContext *Ctx);
static bool shouldBePooled(const Constant *C) { static bool shouldBePooled(const Constant *C) {
(void)C; if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
return !Utils::isPositiveZero(ConstDouble->getValue());
}
if (llvm::isa<ConstantFloat>(C))
return true;
return false; return false;
} }
static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) { static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
...@@ -230,20 +234,20 @@ public: ...@@ -230,20 +234,20 @@ public:
Context.insert<InstMIPS32Divu>(Dest, Src0, Src1); Context.insert<InstMIPS32Divu>(Dest, Src0, Src1);
} }
void _ldc1(Variable *Value, OperandMIPS32Mem *Mem) { void _ldc1(Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Ldc1>(Value, Mem); Context.insert<InstMIPS32Ldc1>(Value, Mem, Reloc);
} }
void _lw(Variable *Value, OperandMIPS32Mem *Mem) { void _lw(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Lw>(Value, Mem); Context.insert<InstMIPS32Lw>(Value, Mem);
} }
void _lwc1(Variable *Value, OperandMIPS32Mem *Mem) { void _lwc1(Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Lwc1>(Value, Mem); Context.insert<InstMIPS32Lwc1>(Value, Mem, Reloc);
} }
void _lui(Variable *Dest, uint32_t Imm) { void _lui(Variable *Dest, Operand *Src, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Lui>(Dest, Imm); Context.insert<InstMIPS32Lui>(Dest, Src, Reloc);
} }
void _mov(Variable *Dest, Operand *Src0) { void _mov(Variable *Dest, Operand *Src0) {
......
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