[mips][ias] Split expandMemInst between MipsAsmParser and MipsTargetStreamer. Almost NFC.

Summary:
The portion in MipsAsmParser is responsible for figuring out which expansion to
use, while the portion in MipsTargetStreamer is responsible for emitting it.

This allows us to remove the call to isIntegratedAssemblerRequired() which is
currently ensuring the effect of .cprestore only occurs when writing objects.

The small functional change is that the memory offsets are now correctly
printed as signed values.

Reviewers: sdardis

Subscribers: dsanders, sdardis, llvm-commits

Differential Revision: http://reviews.llvm.org/D19714


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268042 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2016-04-29 13:43:45 +00:00
parent a0e83333a7
commit f4d5a508ae
5 changed files with 207 additions and 68 deletions

View File

@ -201,7 +201,13 @@ class MipsAsmParser : public MCTargetAsmParser {
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);
@ -2526,78 +2532,97 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
}
void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI, bool isLoad,
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"));
const MCSubtargetInfo *STI, bool IsLoad,
bool IsImmOpnd) {
if (IsLoad) {
expandLoadInst(Inst, IDLoc, Out, STI, IsImmOpnd);
return;
}
// 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.
expandStoreInst(Inst, IDLoc, Out, STI, IsImmOpnd);
}
void MipsAsmParser::expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI, bool IsImmOpnd) {
MipsTargetStreamer &TOut = getTargetStreamer();
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;
}
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"));
// 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;
}
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,

View File

@ -207,6 +207,106 @@ void MipsTargetStreamer::emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI) {
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) {}

View File

@ -116,6 +116,20 @@ public:
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; }

View File

@ -39,7 +39,7 @@
# 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

View File

@ -47,7 +47,7 @@
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]