const MCSubtargetInfo *STI);
void expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
- const MCSubtargetInfo *STI, bool isLoad, bool isImmOpnd);
+ const MCSubtargetInfo *STI, bool IsLoad, bool IsImmOpnd);
+
+ void expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsImmOpnd);
+
+ void expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsImmOpnd);
bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
}
void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
- const MCSubtargetInfo *STI, bool isLoad,
- bool isImmOpnd) {
+ const MCSubtargetInfo *STI, bool IsLoad,
+ bool IsImmOpnd) {
+ if (IsLoad) {
+ expandLoadInst(Inst, IDLoc, Out, STI, IsImmOpnd);
+ return;
+ }
+ expandStoreInst(Inst, IDLoc, Out, STI, IsImmOpnd);
+}
+
+void MipsAsmParser::expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsImmOpnd) {
MipsTargetStreamer &TOut = getTargetStreamer();
- MCOperand HiOperand, LoOperand;
- unsigned TmpRegNum;
- // 1st operand is either the source or destination register.
- assert(Inst.getOperand(0).isReg() && "expected register operand kind");
- unsigned RegOpNum = Inst.getOperand(0).getReg();
- // 2nd operand is the base register.
- assert(Inst.getOperand(1).isReg() && "expected register operand kind");
- unsigned BaseRegNum = Inst.getOperand(1).getReg();
- // 3rd operand is either an immediate or expression.
- if (isImmOpnd) {
- assert(Inst.getOperand(2).isImm() && "expected immediate operand kind");
- unsigned ImmOffset = Inst.getOperand(2).getImm();
- unsigned LoOffset = ImmOffset & 0x0000ffff;
- unsigned HiOffset = (ImmOffset & 0xffff0000) >> 16;
- // If msb of LoOffset is 1(negative number) we must increment HiOffset.
- if (LoOffset & 0x8000)
- HiOffset++;
- LoOperand = MCOperand::createImm(LoOffset);
- HiOperand = MCOperand::createImm(HiOffset);
- } else {
- const MCExpr *ExprOffset = Inst.getOperand(2).getExpr();
- LoOperand = MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo"));
- HiOperand = MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi"));
- }
- // These are some of the types of expansions we perform here:
- // 1) lw $8, sym => lui $8, %hi(sym)
- // lw $8, %lo(sym)($8)
- // 2) lw $8, offset($9) => lui $8, %hi(offset)
- // add $8, $8, $9
- // lw $8, %lo(offset)($9)
- // 3) lw $8, offset($8) => lui $at, %hi(offset)
- // add $at, $at, $8
- // lw $8, %lo(offset)($at)
- // 4) sw $8, sym => lui $at, %hi(sym)
- // sw $8, %lo(sym)($at)
- // 5) sw $8, offset($8) => lui $at, %hi(offset)
- // add $at, $at, $8
- // sw $8, %lo(offset)($at)
- // 6) ldc1 $f0, sym => lui $at, %hi(sym)
- // ldc1 $f0, %lo(sym)($at)
- //
- // For load instructions we can use the destination register as a temporary
- // if base and dst are different (examples 1 and 2) and if the base register
- // is general purpose otherwise we must use $at (example 6) and error if it's
- // not available. For stores we must use $at (examples 4 and 5) because we
- // must not clobber the source register setting up the offset.
+
+ unsigned DstReg = Inst.getOperand(0).getReg();
+ unsigned BaseReg = Inst.getOperand(1).getReg();
+
const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode());
- int16_t RegClassOp0 = Desc.OpInfo[0].RegClass;
- unsigned RegClassIDOp0 =
- getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID();
- bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) ||
- (RegClassIDOp0 == Mips::GPR64RegClassID);
- if (isLoad && IsGPR && (BaseRegNum != RegOpNum))
- TmpRegNum = RegOpNum;
- else {
+ int16_t DstRegClass = Desc.OpInfo[0].RegClass;
+ unsigned DstRegClassID =
+ getContext().getRegisterInfo()->getRegClass(DstRegClass).getID();
+ bool IsGPR = (DstRegClassID == Mips::GPR32RegClassID) ||
+ (DstRegClassID == Mips::GPR64RegClassID);
+
+ if (IsImmOpnd) {
+ // Try to use DstReg as the temporary.
+ if (IsGPR && (BaseReg != DstReg)) {
+ TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg,
+ Inst.getOperand(2).getImm(), DstReg, IDLoc,
+ STI);
+ return;
+ }
+
// At this point we need AT to perform the expansions and we exit if it is
// not available.
- TmpRegNum = getATReg(IDLoc);
- if (!TmpRegNum)
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
return;
+
+ TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg,
+ Inst.getOperand(2).getImm(), ATReg, IDLoc, STI);
+ return;
+ }
+
+ const MCExpr *ExprOffset = Inst.getOperand(2).getExpr();
+ MCOperand LoOperand =
+ MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo"));
+ MCOperand HiOperand =
+ MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi"));
+
+ // Try to use DstReg as the temporary.
+ if (IsGPR && (BaseReg != DstReg)) {
+ TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand,
+ LoOperand, DstReg, IDLoc, STI);
+ return;
+ }
+
+ // 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;
+
+ TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand,
+ LoOperand, ATReg, IDLoc, STI);
+}
+
+void MipsAsmParser::expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI,
+ bool IsImmOpnd) {
+ MipsTargetStreamer &TOut = getTargetStreamer();
+
+ unsigned SrcReg = Inst.getOperand(0).getReg();
+ unsigned BaseReg = Inst.getOperand(1).getReg();
+
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return;
+
+ if (IsImmOpnd) {
+ TOut.emitStoreWithImmOffset(Inst.getOpcode(), SrcReg, BaseReg,
+ Inst.getOperand(2).getImm(), ATReg, IDLoc, STI);
+ return;
}
- TOut.emitRX(Mips::LUi, TmpRegNum, HiOperand, IDLoc, STI);
- // Add temp register to base.
- if (BaseRegNum != Mips::ZERO)
- TOut.emitRRR(Mips::ADDu, TmpRegNum, TmpRegNum, BaseRegNum, IDLoc, STI);
- // And finally, create original instruction with low part
- // of offset and new base.
- TOut.emitRRX(Inst.getOpcode(), RegOpNum, TmpRegNum, LoOperand, IDLoc, STI);
+ const MCExpr *ExprOffset = Inst.getOperand(2).getExpr();
+ MCOperand LoOperand =
+ MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "lo"));
+ MCOperand HiOperand =
+ MCOperand::createExpr(evaluateRelocExpr(ExprOffset, "hi"));
+ TOut.emitStoreWithSymOffset(Inst.getOpcode(), SrcReg, BaseReg, HiOperand,
+ LoOperand, ATReg, IDLoc, STI);
}
bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc,
emitRRI(Mips::SLL, Mips::ZERO, Mips::ZERO, 0, IDLoc, STI);
}
+/// Emit a store instruction with an immediate offset. The immediate is
+/// expected to be out-of-range for a simm16 and will be expanded to
+/// appropriate instructions.
+void MipsTargetStreamer::emitStoreWithImmOffset(
+ unsigned Opcode, unsigned SrcReg, unsigned BaseReg, int64_t Offset,
+ unsigned ATReg, SMLoc IDLoc, const MCSubtargetInfo *STI) {
+ // sw $8, offset($8) => lui $at, %hi(offset)
+ // add $at, $at, $8
+ // sw $8, %lo(offset)($at)
+
+ unsigned LoOffset = Offset & 0x0000ffff;
+ unsigned HiOffset = (Offset & 0xffff0000) >> 16;
+
+ // If msb of LoOffset is 1(negative number) we must increment HiOffset
+ // to account for the sign-extension of the low part.
+ if (LoOffset & 0x8000)
+ HiOffset++;
+
+ // Generate the base address in ATReg.
+ emitRI(Mips::LUi, ATReg, HiOffset, IDLoc, STI);
+ if (BaseReg != Mips::ZERO)
+ emitRRR(Mips::ADDu, ATReg, ATReg, BaseReg, IDLoc, STI);
+ // Emit the store with the adjusted base and offset.
+ emitRRI(Opcode, SrcReg, ATReg, LoOffset, IDLoc, STI);
+}
+
+/// Emit a store instruction with an symbol offset. Symbols are assumed to be
+/// out of range for a simm16 will be expanded to appropriate instructions.
+void MipsTargetStreamer::emitStoreWithSymOffset(
+ unsigned Opcode, unsigned SrcReg, unsigned BaseReg, MCOperand &HiOperand,
+ MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI) {
+ // sw $8, sym => lui $at, %hi(sym)
+ // sw $8, %lo(sym)($at)
+
+ // Generate the base address in ATReg.
+ emitRX(Mips::LUi, ATReg, HiOperand, IDLoc, STI);
+ if (BaseReg != Mips::ZERO)
+ emitRRR(Mips::ADDu, ATReg, ATReg, BaseReg, IDLoc, STI);
+ // Emit the store with the adjusted base and offset.
+ emitRRX(Opcode, SrcReg, ATReg, LoOperand, IDLoc, STI);
+}
+
+/// Emit a load instruction with an immediate offset. The immediate is expected
+/// to be out-of-range for a simm16 and will be expanded to appropriate
+/// instructions. DstReg and TmpReg are permitted to be the same register iff
+/// DstReg is distinct from BaseReg and DstReg is a GPR. It is the callers
+/// responsibility to identify such cases and pass the appropriate register in
+/// TmpReg.
+void MipsTargetStreamer::emitLoadWithImmOffset(unsigned Opcode, unsigned DstReg,
+ unsigned BaseReg, int64_t Offset,
+ unsigned TmpReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI) {
+ // 1) lw $8, offset($9) => lui $8, %hi(offset)
+ // add $8, $8, $9
+ // lw $8, %lo(offset)($9)
+ // 2) lw $8, offset($8) => lui $at, %hi(offset)
+ // add $at, $at, $8
+ // lw $8, %lo(offset)($at)
+
+ unsigned LoOffset = Offset & 0x0000ffff;
+ unsigned HiOffset = (Offset & 0xffff0000) >> 16;
+
+ // If msb of LoOffset is 1(negative number) we must increment HiOffset
+ // to account for the sign-extension of the low part.
+ if (LoOffset & 0x8000)
+ HiOffset++;
+
+ // Generate the base address in TmpReg.
+ emitRI(Mips::LUi, TmpReg, HiOffset, IDLoc, STI);
+ if (BaseReg != Mips::ZERO)
+ emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
+ // Emit the load with the adjusted base and offset.
+ emitRRI(Opcode, DstReg, TmpReg, LoOffset, IDLoc, STI);
+}
+
+/// Emit a load instruction with an symbol offset. Symbols are assumed to be
+/// out of range for a simm16 will be expanded to appropriate instructions.
+/// DstReg and TmpReg are permitted to be the same register iff DstReg is a
+/// GPR. It is the callers responsibility to identify such cases and pass the
+/// appropriate register in TmpReg.
+void MipsTargetStreamer::emitLoadWithSymOffset(unsigned Opcode, unsigned DstReg,
+ unsigned BaseReg,
+ MCOperand &HiOperand,
+ MCOperand &LoOperand,
+ unsigned TmpReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI) {
+ // 1) lw $8, sym => lui $8, %hi(sym)
+ // lw $8, %lo(sym)($8)
+ // 2) ldc1 $f0, sym => lui $at, %hi(sym)
+ // ldc1 $f0, %lo(sym)($at)
+
+ // Generate the base address in TmpReg.
+ emitRX(Mips::LUi, TmpReg, HiOperand, IDLoc, STI);
+ if (BaseReg != Mips::ZERO)
+ emitRRR(Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI);
+ // Emit the load with the adjusted base and offset.
+ emitRRX(Opcode, DstReg, TmpReg, LoOperand, IDLoc, STI);
+}
+
MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
: MipsTargetStreamer(S), OS(OS) {}
void emitEmptyDelaySlot(bool hasShortDelaySlot, SMLoc IDLoc,
const MCSubtargetInfo *STI);
void emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI);
+ void emitStoreWithImmOffset(unsigned Opcode, unsigned SrcReg,
+ unsigned BaseReg, int64_t Offset, unsigned ATReg,
+ SMLoc IDLoc, const MCSubtargetInfo *STI);
+ void emitStoreWithSymOffset(unsigned Opcode, unsigned SrcReg,
+ unsigned BaseReg, MCOperand &HiOperand,
+ MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI);
+ void emitLoadWithImmOffset(unsigned Opcode, unsigned DstReg, unsigned BaseReg,
+ int64_t Offset, unsigned TmpReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI);
+ void emitLoadWithSymOffset(unsigned Opcode, unsigned DstReg, unsigned BaseReg,
+ MCOperand &HiOperand, MCOperand &LoOperand,
+ unsigned ATReg, SMLoc IDLoc,
+ const MCSubtargetInfo *STI);
void forbidModuleDirective() { ModuleDirectiveAllowed = false; }
void reallowModuleDirective() { ModuleDirectiveAllowed = true; }
# CHECK: lw $10, 123($10) # encoding: [0x4a,0xfd,0x7b,0x00]
# CHECK: lui $1, 2 # encoding: [0xa1,0x41,0x02,0x00]
# CHECK: addu $1, $1, $9 # encoding: [0x21,0x01,0x50,0x09]
-# CHECK: sw $10, 57920($1) # encoding: [0x41,0xf9,0x40,0xe2]
+# CHECK: sw $10, -7616($1) # encoding: [0x41,0xf9,0x40,0xe2]
li $5,123
li $6,-2345
sw $10, 123456($9)
# CHECK-LE: lui $1, 2 # encoding: [0x02,0x00,0x01,0x3c]
# CHECK-LE: addu $1, $1, $9 # encoding: [0x21,0x08,0x29,0x00]
-# CHECK-LE: sw $10, 57920($1) # encoding: [0x40,0xe2,0x2a,0xac]
+# CHECK-LE: sw $10, -7616($1) # encoding: [0x40,0xe2,0x2a,0xac]
lw $8, symbol
# CHECK-LE: lui $8, %hi(symbol) # encoding: [A,A,0x08,0x3c]