| Index: src/IceAssemblerMIPS32.cpp
|
| diff --git a/src/IceAssemblerMIPS32.cpp b/src/IceAssemblerMIPS32.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b9ddff1cf3dddca2e063e13dd7fe942b85ebc64f
|
| --- /dev/null
|
| +++ b/src/IceAssemblerMIPS32.cpp
|
| @@ -0,0 +1,429 @@
|
| +//===- subzero/src/IceAssemblerMIPS32.cpp - MIPS32 Assembler --------------===//
|
| +//
|
| +// The Subzero Code Generator
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +///
|
| +/// \file
|
| +/// \brief Implements the Assembler class for MIPS32.
|
| +///
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#include "IceAssemblerMIPS32.h"
|
| +#include "IceCfgNode.h"
|
| +#include "IceRegistersMIPS32.h"
|
| +#include "IceUtils.h"
|
| +
|
| +namespace {
|
| +
|
| +using namespace Ice;
|
| +using namespace Ice::MIPS32;
|
| +
|
| +// Offset modifier to current PC for next instruction.
|
| +static constexpr IOffsetT kPCReadOffset = 4;
|
| +
|
| +// Mask to pull out PC offset from branch instruction.
|
| +static constexpr int kBranchOffsetBits = 16;
|
| +static constexpr IOffsetT kBranchOffsetMask = 0x0000ffff;
|
| +
|
| +} // end of anonymous namespace
|
| +
|
| +namespace Ice {
|
| +namespace MIPS32 {
|
| +
|
| +void AssemblerMIPS32::emitTextInst(const std::string &Text, SizeT InstSize) {
|
| + AssemblerFixup *F = createTextFixup(Text, InstSize);
|
| + emitFixup(F);
|
| + for (SizeT I = 0; I < InstSize; ++I) {
|
| + AssemblerBuffer::EnsureCapacity ensured(&Buffer);
|
| + Buffer.emit<char>(0);
|
| + }
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +// TEQ $0, $0 - Trap if equal
|
| +static constexpr uint8_t TrapBytesRaw[] = {0x00, 0x00, 0x00, 0x34};
|
| +
|
| +const auto TrapBytes =
|
| + llvm::ArrayRef<uint8_t>(TrapBytesRaw, llvm::array_lengthof(TrapBytesRaw));
|
| +
|
| +} // end of anonymous namespace
|
| +
|
| +llvm::ArrayRef<uint8_t> AssemblerMIPS32::getNonExecBundlePadding() const {
|
| + return TrapBytes;
|
| +}
|
| +
|
| +void AssemblerMIPS32::trap() {
|
| + AssemblerBuffer::EnsureCapacity ensured(&Buffer);
|
| + for (const uint8_t &Byte : reverse_range(TrapBytes))
|
| + Buffer.emit<uint8_t>(Byte);
|
| +}
|
| +
|
| +void AssemblerMIPS32::nop() { emitInst(0); }
|
| +
|
| +void AssemblerMIPS32::padWithNop(intptr_t Padding) {
|
| + constexpr intptr_t InstWidth = sizeof(IValueT);
|
| + assert(Padding % InstWidth == 0 &&
|
| + "Padding not multiple of instruction size");
|
| + for (intptr_t i = 0; i < Padding; i += InstWidth)
|
| + nop();
|
| +}
|
| +
|
| +Label *AssemblerMIPS32::getOrCreateLabel(SizeT Number, LabelVector &Labels) {
|
| + Label *L = nullptr;
|
| + if (Number == Labels.size()) {
|
| + L = new (this->allocate<Label>()) Label();
|
| + Labels.push_back(L);
|
| + return L;
|
| + }
|
| + if (Number > Labels.size()) {
|
| + Labels.resize(Number + 1);
|
| + }
|
| + L = Labels[Number];
|
| + if (L == nullptr) {
|
| + L = new (this->allocate<Label>()) Label();
|
| + Labels[Number] = L;
|
| + }
|
| + return L;
|
| +}
|
| +
|
| +void AssemblerMIPS32::bindCfgNodeLabel(const CfgNode *Node) {
|
| + if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) {
|
| + constexpr SizeT InstSize = 0;
|
| + emitTextInst(Node->getAsmName() + ":", InstSize);
|
| + }
|
| + SizeT NodeNumber = Node->getIndex();
|
| + assert(!getPreliminary());
|
| + Label *L = getOrCreateCfgNodeLabel(NodeNumber);
|
| + this->bind(L);
|
| +}
|
| +
|
| +// Checks that Offset can fit in imm16 constant of branch instruction.
|
| +void assertCanEncodeBranchOffset(IOffsetT Offset) {
|
| + (void)Offset;
|
| + (void)kBranchOffsetBits;
|
| + assert(Utils::IsAligned(Offset, 4));
|
| + assert(Utils::IsInt(kBranchOffsetBits, Offset >> 2));
|
| +}
|
| +
|
| +IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
|
| + Offset -= kPCReadOffset;
|
| + assertCanEncodeBranchOffset(Offset);
|
| + Offset >>= 2;
|
| + Offset &= kBranchOffsetMask;
|
| + return (Inst & ~kBranchOffsetMask) | Offset;
|
| +}
|
| +
|
| +IOffsetT AssemblerMIPS32::decodeBranchOffset(IValueT Inst) {
|
| + int16_t imm = (Inst & kBranchOffsetMask);
|
| + IOffsetT Offset = imm;
|
| + Offset = Offset << 2;
|
| + return (Offset + kPCReadOffset);
|
| +}
|
| +
|
| +void AssemblerMIPS32::bind(Label *L) {
|
| + IOffsetT BoundPc = Buffer.size();
|
| + assert(!L->isBound()); // Labels can only be bound once.
|
| + while (L->isLinked()) {
|
| + IOffsetT Position = L->getLinkPosition();
|
| + IOffsetT Dest = BoundPc - Position;
|
| + IValueT Inst = Buffer.load<IValueT>(Position);
|
| + Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst));
|
| + L->setPosition(decodeBranchOffset(Inst));
|
| + }
|
| + L->bindTo(BoundPc);
|
| +}
|
| +
|
| +enum RegSetWanted { WantGPRegs, WantFPRegs };
|
| +
|
| +IValueT getEncodedGPRegNum(const Variable *Var) {
|
| + assert(Var->hasReg());
|
| + const auto Reg = Var->getRegNum();
|
| + return RegMIPS32::getEncodedGPR(Reg);
|
| +}
|
| +
|
| +bool encodeOperand(const Operand *Opnd, IValueT &Value,
|
| + RegSetWanted WantedRegSet) {
|
| + Value = 0;
|
| + if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
|
| + if (Var->hasReg()) {
|
| + switch (WantedRegSet) {
|
| + case WantGPRegs:
|
| + Value = getEncodedGPRegNum(Var);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
|
| + const char *RegName, const char *InstName) {
|
| + IValueT Reg = 0;
|
| + if (encodeOperand(OpReg, Reg, WantedRegSet) != true)
|
| + llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
|
| + RegName);
|
| + return Reg;
|
| +}
|
| +
|
| +IValueT encodeGPRegister(const Operand *OpReg, const char *RegName,
|
| + const char *InstName) {
|
| + return encodeRegister(OpReg, WantGPRegs, RegName, InstName);
|
| +}
|
| +
|
| +void AssemblerMIPS32::emitRtRsImm16(IValueT Opcode, const Operand *OpRt,
|
| + const Operand *OpRs, const uint32_t Imm,
|
| + const char *InsnName) {
|
| + const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
|
| + const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
|
| +
|
| + Opcode |= Rs << 21;
|
| + Opcode |= Rt << 16;
|
| + Opcode |= Imm & 0xffff;
|
| +
|
| + emitInst(Opcode);
|
| +}
|
| +
|
| +void AssemblerMIPS32::emitRdRtSa(IValueT Opcode, const Operand *OpRd,
|
| + const Operand *OpRt, const uint32_t Sa,
|
| + const char *InsnName) {
|
| + const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName);
|
| + const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
|
| +
|
| + Opcode |= Rt << 16;
|
| + Opcode |= Rd << 11;
|
| + Opcode |= (Sa & 0x1f) << 6;
|
| +
|
| + emitInst(Opcode);
|
| +}
|
| +
|
| +void AssemblerMIPS32::emitRdRsRt(IValueT Opcode, const Operand *OpRd,
|
| + const Operand *OpRs, const Operand *OpRt,
|
| + const char *InsnName) {
|
| + const IValueT Rd = encodeGPRegister(OpRd, "Rd", InsnName);
|
| + const IValueT Rs = encodeGPRegister(OpRs, "Rs", InsnName);
|
| + const IValueT Rt = encodeGPRegister(OpRt, "Rt", InsnName);
|
| +
|
| + Opcode |= Rs << 21;
|
| + Opcode |= Rt << 16;
|
| + Opcode |= Rd << 11;
|
| +
|
| + emitInst(Opcode);
|
| +}
|
| +
|
| +void AssemblerMIPS32::addiu(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x24000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "addiu");
|
| +}
|
| +
|
| +void AssemblerMIPS32::slti(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x28000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "slti");
|
| +}
|
| +
|
| +void AssemblerMIPS32::sltiu(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x2c000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "sltiu");
|
| +}
|
| +
|
| +void AssemblerMIPS32::and_(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x00000024;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "and");
|
| +}
|
| +
|
| +void AssemblerMIPS32::andi(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x30000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "andi");
|
| +}
|
| +
|
| +void AssemblerMIPS32::or_(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x00000025;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "or");
|
| +}
|
| +
|
| +void AssemblerMIPS32::ori(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x34000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "ori");
|
| +}
|
| +
|
| +void AssemblerMIPS32::xor_(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x00000026;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "xor");
|
| +}
|
| +
|
| +void AssemblerMIPS32::xori(const Operand *OpRt, const Operand *OpRs,
|
| + const uint32_t Imm) {
|
| + static constexpr IValueT Opcode = 0x38000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpRs, Imm, "xori");
|
| +}
|
| +
|
| +void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt,
|
| + const uint32_t Sa) {
|
| + static constexpr IValueT Opcode = 0x00000000;
|
| + emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sll");
|
| +}
|
| +
|
| +void AssemblerMIPS32::srl(const Operand *OpRd, const Operand *OpRt,
|
| + const uint32_t Sa) {
|
| + static constexpr IValueT Opcode = 0x00000002;
|
| + emitRdRtSa(Opcode, OpRd, OpRt, Sa, "srl");
|
| +}
|
| +
|
| +void AssemblerMIPS32::sra(const Operand *OpRd, const Operand *OpRt,
|
| + const uint32_t Sa) {
|
| + static constexpr IValueT Opcode = 0x00000003;
|
| + emitRdRtSa(Opcode, OpRd, OpRt, Sa, "sra");
|
| +}
|
| +
|
| +void AssemblerMIPS32::move(const Operand *OpRd, const Operand *OpRs) {
|
| + IValueT Opcode = 0x00000021;
|
| + const IValueT Rd = encodeGPRegister(OpRd, "Rd", "pseudo-move");
|
| + const IValueT Rs = encodeGPRegister(OpRs, "Rs", "pseudo-move");
|
| + const IValueT Rt = 0; // $0
|
| + Opcode |= Rs << 21;
|
| + Opcode |= Rt << 16;
|
| + Opcode |= Rd << 11;
|
| + emitInst(Opcode);
|
| +}
|
| +
|
| +void AssemblerMIPS32::addu(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x00000021;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "addu");
|
| +}
|
| +
|
| +void AssemblerMIPS32::sltu(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x0000002B;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "sltu");
|
| +}
|
| +
|
| +void AssemblerMIPS32::slt(const Operand *OpRd, const Operand *OpRs,
|
| + const Operand *OpRt) {
|
| + static constexpr IValueT Opcode = 0x0000002A;
|
| + emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "slt");
|
| +}
|
| +
|
| +void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase,
|
| + const uint32_t Offset) {
|
| + static constexpr IValueT Opcode = 0xAC000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sw");
|
| +}
|
| +
|
| +void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase,
|
| + const uint32_t Offset) {
|
| + static constexpr IValueT Opcode = 0x8C000000;
|
| + emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "lw");
|
| +}
|
| +
|
| +void AssemblerMIPS32::ret(void) {
|
| + static constexpr IValueT Opcode = 0x03E00008; // JR $31
|
| + emitInst(Opcode);
|
| + nop(); // delay slot
|
| +}
|
| +
|
| +void AssemblerMIPS32::emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs,
|
| + const Operand *OpRt, IOffsetT Offset) {
|
| + IValueT Opcode = 0;
|
| +
|
| + switch (Cond) {
|
| + default:
|
| + break;
|
| + case CondMIPS32::AL:
|
| + case CondMIPS32::EQ:
|
| + case CondMIPS32::EQZ:
|
| + Opcode = 0x10000000;
|
| + break;
|
| + case CondMIPS32::NE:
|
| + case CondMIPS32::NEZ:
|
| + Opcode = 0x14000000;
|
| + break;
|
| + case CondMIPS32::LEZ:
|
| + Opcode = 0x18000000;
|
| + break;
|
| + case CondMIPS32::LTZ:
|
| + Opcode = 0x04000000;
|
| + break;
|
| + case CondMIPS32::GEZ:
|
| + Opcode = 0x04010000;
|
| + break;
|
| + case CondMIPS32::GTZ:
|
| + Opcode = 0x1C000000;
|
| + break;
|
| + }
|
| +
|
| + if (Opcode == 0) {
|
| + llvm::report_fatal_error("Branch: Invalid condition");
|
| + }
|
| +
|
| + if (OpRs != nullptr) {
|
| + IValueT Rs = encodeGPRegister(OpRs, "Rs", "branch");
|
| + Opcode |= Rs << 21;
|
| + }
|
| +
|
| + if (OpRt != nullptr) {
|
| + IValueT Rt = encodeGPRegister(OpRt, "Rt", "branch");
|
| + Opcode |= Rt << 16;
|
| + }
|
| +
|
| + Opcode = encodeBranchOffset(Offset, Opcode);
|
| + emitInst(Opcode);
|
| + nop(); // delay slot
|
| +}
|
| +
|
| +void AssemblerMIPS32::b(Label *TargetLabel) {
|
| + static constexpr Operand *OpRsNone = nullptr;
|
| + static constexpr Operand *OpRtNone = nullptr;
|
| + if (TargetLabel->isBound()) {
|
| + const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
|
| + emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, Dest);
|
| + return;
|
| + }
|
| + const IOffsetT Position = Buffer.size();
|
| + emitBr(CondMIPS32::AL, OpRsNone, OpRtNone, TargetLabel->getEncodedPosition());
|
| + TargetLabel->linkTo(*this, Position);
|
| +}
|
| +
|
| +void AssemblerMIPS32::bcc(const CondMIPS32::Cond Cond, const Operand *OpRs,
|
| + const Operand *OpRt, Label *TargetLabel) {
|
| + if (TargetLabel->isBound()) {
|
| + const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
|
| + emitBr(Cond, OpRs, OpRt, Dest);
|
| + return;
|
| + }
|
| + const IOffsetT Position = Buffer.size();
|
| + emitBr(Cond, OpRs, OpRt, TargetLabel->getEncodedPosition());
|
| + TargetLabel->linkTo(*this, Position);
|
| +}
|
| +
|
| +void AssemblerMIPS32::bzc(const CondMIPS32::Cond Cond, const Operand *OpRs,
|
| + Label *TargetLabel) {
|
| + static constexpr Operand *OpRtNone = nullptr;
|
| + if (TargetLabel->isBound()) {
|
| + const int32_t Dest = TargetLabel->getPosition() - Buffer.size();
|
| + emitBr(Cond, OpRs, OpRtNone, Dest);
|
| + return;
|
| + }
|
| + const IOffsetT Position = Buffer.size();
|
| + emitBr(Cond, OpRs, OpRtNone, TargetLabel->getEncodedPosition());
|
| + TargetLabel->linkTo(*this, Position);
|
| +}
|
| +
|
| +} // end of namespace MIPS32
|
| +} // end of namespace Ice
|
|
|