From 100018952c88c37a8d4b2dafa368619b3ee45a62 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Thu, 12 May 2016 14:01:50 +0000 Subject: [PATCH] [mips][ias] Fix O32 .cprestore directive when inside .set noat region and offset is in range. Summary: This expands on r269179 to fix an additional case that was not covered by our tests. The assembler temporary is not needed when the .cprestore offset fits inside a simm16 and it is not an error to use it inside a '.set noat' in this case. Reviewers: emaste, seanbruno, sdardis Subscribers: dsanders, sdardis, llvm-commits Differential Revision: http://reviews.llvm.org/D20199 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269295 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 21 ++++++++----------- .../Mips/MCTargetDesc/MipsTargetStreamer.cpp | 13 ++++++------ lib/Target/Mips/MipsTargetStreamer.h | 21 +++++++++++++++++-- test/MC/Mips/cprestore-noreorder-noat.s | 21 ++++++++++++++++++- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index f7fd72fd27f..128cef7bc8d 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -2633,16 +2633,17 @@ void MipsAsmParser::expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, unsigned SrcReg = Inst.getOperand(0).getReg(); unsigned BaseReg = Inst.getOperand(1).getReg(); + if (IsImmOpnd) { + TOut.emitStoreWithImmOffset(Inst.getOpcode(), SrcReg, BaseReg, + Inst.getOperand(2).getImm(), + [&]() { return getATReg(IDLoc); }, IDLoc, STI); + return; + } + 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( MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); @@ -3626,12 +3627,8 @@ void MipsAsmParser::createCpRestoreMemOp(bool IsLoad, int StackOffset, return; } - unsigned ATReg = getATReg(IDLoc); - if (!ATReg) - return; - - TOut.emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, StackOffset, ATReg, - IDLoc, STI); + TOut.emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, StackOffset, + [&]() { return getATReg(IDLoc); }, IDLoc, STI); } unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { diff --git a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp index c9e240c7fb3..c6bb84d3b02 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -228,7 +228,8 @@ void MipsTargetStreamer::emitGPRestore(int Offset, SMLoc IDLoc, /// Emit a store instruction with an immediate offset. void MipsTargetStreamer::emitStoreWithImmOffset( unsigned Opcode, unsigned SrcReg, unsigned BaseReg, int64_t Offset, - unsigned ATReg, SMLoc IDLoc, const MCSubtargetInfo *STI) { + std::function GetATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI) { if (isInt<16>(Offset)) { emitRRI(Opcode, SrcReg, BaseReg, Offset, IDLoc, STI); return; @@ -238,6 +239,10 @@ void MipsTargetStreamer::emitStoreWithImmOffset( // add $at, $at, $8 // sw $8, %lo(offset)($at) + unsigned ATReg = GetATReg(); + if (!ATReg) + return; + unsigned LoOffset = Offset & 0x0000ffff; unsigned HiOffset = (Offset & 0xffff0000) >> 16; @@ -1055,12 +1060,8 @@ bool MipsTargetELFStreamer::emitDirectiveCpRestore( if (!Pic || (getABI().IsN32() || getABI().IsN64())) return true; - unsigned ATReg = GetATReg(); - if (!ATReg) - return false; - // Store the $gp on the stack. - emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, Offset, ATReg, IDLoc, + emitStoreWithImmOffset(Mips::SW, Mips::GP, Mips::SP, Offset, GetATReg, IDLoc, STI); return true; } diff --git a/lib/Target/Mips/MipsTargetStreamer.h b/lib/Target/Mips/MipsTargetStreamer.h index c0b3c443f97..d418f80916b 100644 --- a/lib/Target/Mips/MipsTargetStreamer.h +++ b/lib/Target/Mips/MipsTargetStreamer.h @@ -122,9 +122,18 @@ public: void emitEmptyDelaySlot(bool hasShortDelaySlot, SMLoc IDLoc, const MCSubtargetInfo *STI); void emitNop(SMLoc IDLoc, const MCSubtargetInfo *STI); + + /// Emit a store instruction with an offset. If the offset is out of range + /// then it will be synthesized using the assembler temporary. + /// + /// GetATReg() is a callback that can be used to obtain the current assembler + /// temporary and is only called when the assembler temporary is required. It + /// must handle the case where no assembler temporary is available (typically + /// by reporting an error). void emitStoreWithImmOffset(unsigned Opcode, unsigned SrcReg, - unsigned BaseReg, int64_t Offset, unsigned ATReg, - SMLoc IDLoc, const MCSubtargetInfo *STI); + unsigned BaseReg, int64_t Offset, + std::function GetATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI); void emitStoreWithSymOffset(unsigned Opcode, unsigned SrcReg, unsigned BaseReg, MCOperand &HiOperand, MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc, @@ -237,6 +246,14 @@ public: // PIC support void emitDirectiveCpLoad(unsigned RegNo) override; + + /// Emit a .cprestore directive. If the offset is out of range then it will + /// be synthesized using the assembler temporary. + /// + /// GetATReg() is a callback that can be used to obtain the current assembler + /// temporary and is only called when the assembler temporary is required. It + /// must handle the case where no assembler temporary is available (typically + /// by reporting an error). bool emitDirectiveCpRestore(int Offset, std::function GetATReg, SMLoc IDLoc, const MCSubtargetInfo *STI) override; void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, diff --git a/test/MC/Mips/cprestore-noreorder-noat.s b/test/MC/Mips/cprestore-noreorder-noat.s index d71d8fb91ed..0716145effa 100644 --- a/test/MC/Mips/cprestore-noreorder-noat.s +++ b/test/MC/Mips/cprestore-noreorder-noat.s @@ -24,7 +24,7 @@ foo: .cpload $25 .cprestore 8 -# O32: :[[@LINE-1]]:3: error: pseudo-instruction requires $at, which is not available +# O32-NOT: error: pseudo-instruction requires $at, which is not available # N32-NOT: error: pseudo-instruction requires $at, which is not available # N64-NOT: error: pseudo-instruction requires $at, which is not available # NO-STORE-NOT: sw $gp, 8($sp) @@ -34,3 +34,22 @@ foo: jal foo .end foo + + .ent bar +bar: + .frame $sp, 0, $ra + .set noreorder + .set noat + + .cpload $25 + .cprestore 65536 +# O32: :[[@LINE-1]]:3: error: pseudo-instruction requires $at, which is not available +# N32-NOT: error: pseudo-instruction requires $at, which is not available +# N64-NOT: error: pseudo-instruction requires $at, which is not available +# NO-STORE-NOT: sw $gp, + + jal $25 + jal $4, $25 + jal bar + + .end bar