// nullptr, which indicates that no function is currently
// selected. This usually happens after an '.end func'
// directive.
+ bool IsLittleEndian;
// Print a warning along with its fix-it message at the given range.
void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg,
bool expandCondBranches(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
+ bool expandUlhu(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
void createNop(bool hasShortDelaySlot, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
void createAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg,
- SmallVectorImpl<MCInst> &Instructions);
+ bool Is64Bit, SmallVectorImpl<MCInst> &Instructions);
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
report_fatal_error("-mno-odd-spreg requires the O32 ABI");
CurrentFn = nullptr;
+
+ Triple TheTriple(sti.getTargetTriple());
+ if ((TheTriple.getArch() == Triple::mips) ||
+ (TheTriple.getArch() == Triple::mips64))
+ IsLittleEndian = false;
+ else
+ IsLittleEndian = true;
}
/// True if all of $fcc0 - $fcc7 exist for the current ISA.
void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc);
void warnIfNoMacro(SMLoc Loc);
+
+ bool isLittle() const { return IsLittleEndian; }
};
}
case Mips::BLEU:
case Mips::BGEU:
case Mips::BGTU:
+ case Mips::Ulhu:
return true;
default:
return false;
case Mips::BGEU:
case Mips::BGTU:
return expandCondBranches(Inst, IDLoc, Instructions);
+ case Mips::Ulhu:
+ return expandUlhu(Inst, IDLoc, Instructions);
}
}
MCInst tmpInst;
+ unsigned TmpReg = DstReg;
+ if (UseSrcReg && (DstReg == SrcReg)) {
+ // At this point we need AT to perform the expansions and we exit if it is
+ // not available.
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+ TmpReg = ATReg;
+ }
+
tmpInst.setLoc(IDLoc);
// FIXME: gas has a special case for values that are 000...1111, which
// becomes a li -1 and then a dsrl
// For DLI, expand to an ORi instead of a LUi to avoid sign-extending the
// upper 32 bits.
tmpInst.setOpcode(Mips::ORi);
- tmpInst.addOperand(MCOperand::createReg(DstReg));
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
tmpInst.addOperand(MCOperand::createReg(Mips::ZERO));
tmpInst.addOperand(MCOperand::createImm(Bits31To16));
tmpInst.setLoc(IDLoc);
Instructions.push_back(tmpInst);
// Move the value to the upper 16 bits by doing a 16-bit left shift.
- createLShiftOri<16>(0, DstReg, IDLoc, Instructions);
+ createLShiftOri<16>(0, TmpReg, IDLoc, Instructions);
} else {
tmpInst.setOpcode(Mips::LUi);
- tmpInst.addOperand(MCOperand::createReg(DstReg));
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
tmpInst.addOperand(MCOperand::createImm(Bits31To16));
Instructions.push_back(tmpInst);
}
- createLShiftOri<0>(Bits15To0, DstReg, IDLoc, Instructions);
+ createLShiftOri<0>(Bits15To0, TmpReg, IDLoc, Instructions);
if (UseSrcReg)
- createAddu(DstReg, DstReg, SrcReg, Instructions);
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, Instructions);
} else if ((ImmValue & (0xffffLL << 48)) == 0) {
if (Is32BitImm) {
uint16_t Bits15To0 = ImmValue & 0xffff;
tmpInst.setOpcode(Mips::LUi);
- tmpInst.addOperand(MCOperand::createReg(DstReg));
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
tmpInst.addOperand(MCOperand::createImm(Bits47To32));
Instructions.push_back(tmpInst);
- createLShiftOri<0>(Bits31To16, DstReg, IDLoc, Instructions);
- createLShiftOri<16>(Bits15To0, DstReg, IDLoc, Instructions);
+ createLShiftOri<0>(Bits31To16, TmpReg, IDLoc, Instructions);
+ createLShiftOri<16>(Bits15To0, TmpReg, IDLoc, Instructions);
if (UseSrcReg)
- createAddu(DstReg, DstReg, SrcReg, Instructions);
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, Instructions);
} else {
if (Is32BitImm) {
uint16_t Bits15To0 = ImmValue & 0xffff;
tmpInst.setOpcode(Mips::LUi);
- tmpInst.addOperand(MCOperand::createReg(DstReg));
+ tmpInst.addOperand(MCOperand::createReg(TmpReg));
tmpInst.addOperand(MCOperand::createImm(Bits63To48));
Instructions.push_back(tmpInst);
- createLShiftOri<0>(Bits47To32, DstReg, IDLoc, Instructions);
+ createLShiftOri<0>(Bits47To32, TmpReg, IDLoc, Instructions);
// When Bits31To16 is 0, do a left shift of 32 bits instead of doing
// two left shifts of 16 bits.
if (Bits31To16 == 0) {
- createLShiftOri<32>(Bits15To0, DstReg, IDLoc, Instructions);
+ createLShiftOri<32>(Bits15To0, TmpReg, IDLoc, Instructions);
} else {
- createLShiftOri<16>(Bits31To16, DstReg, IDLoc, Instructions);
- createLShiftOri<16>(Bits15To0, DstReg, IDLoc, Instructions);
+ createLShiftOri<16>(Bits31To16, TmpReg, IDLoc, Instructions);
+ createLShiftOri<16>(Bits15To0, TmpReg, IDLoc, Instructions);
}
if (UseSrcReg)
- createAddu(DstReg, DstReg, SrcReg, Instructions);
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitImm, Instructions);
}
return false;
}
}
if (UseSrcReg)
- createAddu(DstReg, TmpReg, SrcReg, Instructions);
+ createAddu(DstReg, TmpReg, SrcReg, !Is32BitSym, Instructions);
return false;
}
return false;
}
+bool MipsAsmParser::expandUlhu(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ if (hasMips32r6() || hasMips64r6()) {
+ Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
+ return false;
+ }
+
+ warnIfNoMacro(IDLoc);
+
+ const MCOperand &DstRegOp = Inst.getOperand(0);
+ assert(DstRegOp.isReg() && "expected register operand kind");
+
+ const MCOperand &SrcRegOp = Inst.getOperand(1);
+ assert(SrcRegOp.isReg() && "expected register operand kind");
+
+ const MCOperand &OffsetImmOp = Inst.getOperand(2);
+ assert(OffsetImmOp.isImm() && "expected immediate operand kind");
+
+ unsigned DstReg = DstRegOp.getReg();
+ unsigned SrcReg = SrcRegOp.getReg();
+ int64_t OffsetValue = OffsetImmOp.getImm();
+
+ // NOTE: We always need AT for ULHU, as it is always used as the source
+ // register for one of the LBu's.
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+
+ // When the value of offset+1 does not fit in 16 bits, we have to load the
+ // offset in AT, (D)ADDu the original source register (if there was one), and
+ // then use AT as the source register for the 2 generated LBu's.
+ bool LoadedOffsetInAT = false;
+ if (!isInt<16>(OffsetValue + 1) || !isInt<16>(OffsetValue)) {
+ LoadedOffsetInAT = true;
+
+ if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(),
+ IDLoc, Instructions))
+ return true;
+
+ // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate()
+ // because it will make our output more similar to GAS'. For example,
+ // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9",
+ // instead of just an "ori $1, $9, 32768".
+ // NOTE: If there is no source register specified in the ULHU, the parser
+ // will interpret it as $0.
+ if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64)
+ createAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), Instructions);
+ }
+
+ unsigned FirstLbuDstReg = LoadedOffsetInAT ? DstReg : ATReg;
+ unsigned SecondLbuDstReg = LoadedOffsetInAT ? ATReg : DstReg;
+ unsigned LbuSrcReg = LoadedOffsetInAT ? ATReg : SrcReg;
+
+ int64_t FirstLbuOffset = 0, SecondLbuOffset = 0;
+ if (isLittle()) {
+ FirstLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1);
+ SecondLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue;
+ } else {
+ FirstLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue;
+ SecondLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1);
+ }
+
+ unsigned SllReg = LoadedOffsetInAT ? DstReg : ATReg;
+
+ MCInst TmpInst;
+ TmpInst.setOpcode(Mips::LBu);
+ TmpInst.addOperand(MCOperand::createReg(FirstLbuDstReg));
+ TmpInst.addOperand(MCOperand::createReg(LbuSrcReg));
+ TmpInst.addOperand(MCOperand::createImm(FirstLbuOffset));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::LBu);
+ TmpInst.addOperand(MCOperand::createReg(SecondLbuDstReg));
+ TmpInst.addOperand(MCOperand::createReg(LbuSrcReg));
+ TmpInst.addOperand(MCOperand::createImm(SecondLbuOffset));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::SLL);
+ TmpInst.addOperand(MCOperand::createReg(SllReg));
+ TmpInst.addOperand(MCOperand::createReg(SllReg));
+ TmpInst.addOperand(MCOperand::createImm(8));
+ Instructions.push_back(TmpInst);
+
+ TmpInst.clear();
+ TmpInst.setOpcode(Mips::OR);
+ TmpInst.addOperand(MCOperand::createReg(DstReg));
+ TmpInst.addOperand(MCOperand::createReg(DstReg));
+ TmpInst.addOperand(MCOperand::createReg(ATReg));
+ Instructions.push_back(TmpInst);
+
+ return false;
+}
+
void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
MCInst NopInst;
}
void MipsAsmParser::createAddu(unsigned DstReg, unsigned SrcReg,
- unsigned TrgReg,
+ unsigned TrgReg, bool Is64Bit,
SmallVectorImpl<MCInst> &Instructions) {
MCInst AdduInst;
- AdduInst.setOpcode(Mips::ADDu);
+ AdduInst.setOpcode(Is64Bit ? Mips::DADDu : Mips::ADDu);
AdduInst.addOperand(MCOperand::createReg(DstReg));
AdduInst.addOperand(MCOperand::createReg(SrcReg));
AdduInst.addOperand(MCOperand::createReg(TrgReg));