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) {
}
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) {
// The Neg modes are only needed for Reg +/- Reg.
(void)Func;
......@@ -121,6 +121,25 @@ template <> const char *InstMIPS32Trunc_w_s::Opcode = "trunc.w.s";
template <> const char *InstMIPS32Xor::Opcode = "xor";
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 {
if (!BuildDefs::dump())
return;
......@@ -260,8 +279,11 @@ void OperandMIPS32Mem::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
ConstantInteger32 *Offset = getOffset();
Offset->emit(Func);
Operand *Offset = getOffset();
if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
CR->emitWithoutPrefix(Func->getTarget());
} else
Offset->emit(Func);
Str << "(";
getBase()->emit(Func);
Str << ")";
......
......@@ -28,6 +28,21 @@
namespace Ice {
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;
/// OperandMips32 extends the Operand hierarchy.
......@@ -72,14 +87,13 @@ public:
/// general Constant operands like ConstantRelocatable, since a relocatable
/// can potentially take up too many bits.
static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset,
AddrMode Mode = Offset) {
Operand *ImmOffset, AddrMode Mode = Offset) {
return new (Func->allocate<OperandMIPS32Mem>())
OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode);
}
Variable *getBase() const { return Base; }
ConstantInteger32 *getOffset() const { return ImmOffset; }
Operand *getOffset() const { return ImmOffset; }
AddrMode getAddrMode() const { return Mode; }
void emit(const Cfg *Func) const override;
......@@ -101,12 +115,12 @@ public:
}
private:
OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset, AddrMode Mode);
OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base, Operand *ImmOffset,
AddrMode Mode);
Variable *Base;
ConstantInteger32 *ImmOffset;
AddrMode Mode;
Operand *const ImmOffset;
const AddrMode Mode;
};
/// Base class for Mips instructions.
......@@ -254,9 +268,10 @@ class InstMIPS32UnaryopGPR : public InstMIPS32 {
InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete;
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>())
InstMIPS32UnaryopGPR(Func, Dest, Src);
InstMIPS32UnaryopGPR(Func, Dest, Src, Reloc);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
......@@ -280,13 +295,15 @@ public:
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
protected:
InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src)
: InstMIPS32(Func, K, 1, Dest) {
InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src,
RelocOp Reloc = RO_No)
: InstMIPS32(Func, K, 1, Dest), Reloc(Reloc) {
addSource(Src);
}
private:
static const char *Opcode;
const RelocOp Reloc;
};
/// Instructions of the form opcode reg, reg.
......@@ -485,9 +502,10 @@ class InstMIPS32Memory : public InstMIPS32 {
public:
static InstMIPS32Memory *create(Cfg *Func, Variable *Value,
OperandMIPS32Mem *Mem) {
OperandMIPS32Mem *Mem,
RelocOp Reloc = RO_No) {
return new (Func->allocate<InstMIPS32Memory>())
InstMIPS32Memory(Func, Value, Mem);
InstMIPS32Memory(Func, Value, Mem, Reloc);
}
void emit(const Cfg *Func) const override {
......@@ -498,7 +516,10 @@ public:
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
emitRelocOp(Str, Reloc);
Str << (Reloc ? "(" : "");
getSrc(1)->emit(Func);
Str << (Reloc ? ")" : "");
}
void emitIAS(const Cfg *Func) const override {
......@@ -511,20 +532,24 @@ public:
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << "\t" << Opcode << "\t";
Str << " ";
getSrc(1)->dump(Func);
Str << ", ";
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); }
private:
InstMIPS32Memory(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem)
: InstMIPS32(Func, K, 2, nullptr) {
InstMIPS32Memory(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem,
RelocOp Reloc = RO_No)
: InstMIPS32(Func, K, 2, nullptr), Reloc(Reloc) {
addSource(Value);
addSource(Mem);
}
static const char *Opcode;
const RelocOp Reloc;
};
// InstMIPS32Label represents an intra-block label that is the target of an
......@@ -735,7 +760,7 @@ using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>;
using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Ldc1 = InstMIPS32Memory<InstMIPS32::Ldc1>;
using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>;
using InstMIPS32Lui = InstMIPS32UnaryopGPR<InstMIPS32::Lui>;
using InstMIPS32Lw = InstMIPS32Memory<InstMIPS32::Lw>;
using InstMIPS32Lwc1 = InstMIPS32Memory<InstMIPS32::Lwc1>;
using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>;
......@@ -827,6 +852,7 @@ template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const;
template <> void InstMIPS32Mthi::emit(const Cfg *Func) const;
template <> void InstMIPS32Mult::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 Ice
......
......@@ -1021,7 +1021,7 @@ Operand *TargetMIPS32::hiOperand(Operand *Operand) {
assert(Mem->getAddrMode() == OperandMIPS32Mem::Offset);
const Type SplitType = IceType_i32;
Variable *Base = Mem->getBase();
ConstantInteger32 *Offset = Mem->getOffset();
auto *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
int32_t NextOffsetVal = Offset->getValue() + 4;
constexpr bool SignExt = false;
......@@ -2214,38 +2214,57 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
// Given the above assertion, if type of operand is not legal
// (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy
// to a register.
if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
(void)C;
// TODO(reed kotler): complete this case for proper implementation
Variable *Reg = makeReg(Ty, RegNum);
Context.insert<InstFakeDef>(Reg);
return Reg;
} else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
const uint32_t Value = C32->getValue();
// Check if the immediate will fit in a Flexible second operand,
// if a Flexible second operand is allowed. We need to know the exact
// value, so that rules out relocatable constants.
// Also try the inverse and use MVN if possible.
// Do a movw/movt to a register.
Variable *Reg;
if (RegNum.hasValue())
Reg = getPhysicalRegister(RegNum);
else
Reg = makeReg(Ty, RegNum);
if (isInt<16>(int32_t(Value))) {
Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty);
Context.insert<InstFakeDef>(Zero);
_addiu(Reg, Zero, Value);
} else {
uint32_t UpperBits = (Value >> 16) & 0xFFFF;
(void)UpperBits;
uint32_t LowerBits = Value & 0xFFFF;
Variable *TReg = makeReg(Ty, RegNum);
_lui(TReg, UpperBits);
_ori(Reg, TReg, LowerBits);
if (llvm::isa<Constant>(From)) {
if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
(void)C;
// TODO(reed kotler): complete this case for proper implementation
Variable *Reg = makeReg(Ty, RegNum);
Context.insert<InstFakeDef>(Reg);
return Reg;
} else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
const uint32_t Value = C32->getValue();
// Check if the immediate will fit in a Flexible second operand,
// if a Flexible second operand is allowed. We need to know the exact
// value, so that rules out relocatable constants.
// Also try the inverse and use MVN if possible.
// Do a movw/movt to a register.
Variable *Reg;
if (RegNum.hasValue())
Reg = getPhysicalRegister(RegNum);
else
Reg = makeReg(Ty, RegNum);
if (isInt<16>(int32_t(Value))) {
Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty);
Context.insert<InstFakeDef>(Zero);
_addiu(Reg, Zero, Value);
} else {
uint32_t UpperBits = (Value >> 16) & 0xFFFF;
(void)UpperBits;
uint32_t LowerBits = Value & 0xFFFF;
Variable *TReg = makeReg(Ty, RegNum);
_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)) {
// Check if the variable is guaranteed a physical register. This
// can happen either when the variable is pre-colored or when it is
......
......@@ -35,7 +35,11 @@ public:
static void staticInit(GlobalContext *Ctx);
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;
}
static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
......@@ -230,20 +234,20 @@ public:
Context.insert<InstMIPS32Divu>(Dest, Src0, Src1);
}
void _ldc1(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Ldc1>(Value, Mem);
void _ldc1(Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Ldc1>(Value, Mem, Reloc);
}
void _lw(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Lw>(Value, Mem);
}
void _lwc1(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Lwc1>(Value, Mem);
void _lwc1(Variable *Value, OperandMIPS32Mem *Mem, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Lwc1>(Value, Mem, Reloc);
}
void _lui(Variable *Dest, uint32_t Imm) {
Context.insert<InstMIPS32Lui>(Dest, Imm);
void _lui(Variable *Dest, Operand *Src, RelocOp Reloc = RO_No) {
Context.insert<InstMIPS32Lui>(Dest, Src, Reloc);
}
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