Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -105,6 +105,8 @@ // selected. This usually happens after an '.end func' // directive. bool IsPicEnabled; + bool IsCpRestoreSet; + int CpRestoreOffset; // Print a warning along with its fix-it message at the given range. void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, @@ -198,6 +200,9 @@ void createNop(bool hasShortDelaySlot, SMLoc IDLoc, SmallVectorImpl &Instructions); + void createCpRestoreMemOp(bool IsLoad, int StackOffset, SMLoc IDLoc, + SmallVectorImpl &Instructions); + bool reportParseError(Twine ErrorMsg); bool reportParseError(SMLoc Loc, Twine ErrorMsg); @@ -211,6 +216,7 @@ bool parseSetArchDirective(); bool parseSetFeature(uint64_t Feature); bool parseDirectiveCpLoad(SMLoc Loc); + bool parseDirectiveCpRestore(SMLoc Loc); bool parseDirectiveCPSetup(); bool parseDirectiveNaN(); bool parseDirectiveSet(); @@ -360,6 +366,9 @@ IsPicEnabled = (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_); + + IsCpRestoreSet = false; + CpRestoreOffset = -1; } /// True if all of $fcc0 - $fcc7 exist for the current ISA. @@ -1232,7 +1241,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); - + bool ExpandedJalSym = false; Inst.setLoc(IDLoc); if (MCID.isBranch() || MCID.isCall()) { @@ -1476,7 +1485,10 @@ } MCInst JalrInst; - JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + if (IsCpRestoreSet && inMicroMipsMode()) + JalrInst.setOpcode(Mips::JALRS_MM); + else + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); JalrInst.addOperand(MCOperand::CreateReg(Mips::RA)); JalrInst.addOperand(MCOperand::CreateReg(Mips::T9)); @@ -1485,11 +1497,15 @@ // and is not necessary for correctness. Inst = JalrInst; + ExpandedJalSym = true; } // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. - if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { + // If we expanded a JAL, we need to add the trailing NOP after we push_back + // the expansion MCInst. + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder() && + !ExpandedJalSym) { Instructions.push_back(Inst); createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); return false; @@ -1684,11 +1700,39 @@ } } - if (needsExpansion(Inst)) - return expandInstruction(Inst, IDLoc, Instructions); - else + if (needsExpansion(Inst)) { + if (expandInstruction(Inst, IDLoc, Instructions)) + return true; + } else { Instructions.push_back(Inst); + } + + // Adding a trailing NOP after the expanded JAL needs to happen here (after we + // push_back the expansion MCInst). + if (ExpandedJalSym && AssemblerOptions.back()->isReorder()) + createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + + if ((Inst.getOpcode() == Mips::JalOneReg || + Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) && + inPicMode() && !(isABI_N32() || isABI_N64())) { + if (IsCpRestoreSet) { + // If .set noreorder has been used, emit a NOP after the generated JALR. + // If .set reorder has been used, we've already emitted the NOP. + if (!AssemblerOptions.back()->isReorder()) + createNop(hasShortDelaySlot(Inst.getOpcode()), IDLoc, Instructions); + // Load the $gp from the stack. + SmallVector LoadInsts; + createCpRestoreMemOp(true /*IsLoad*/, CpRestoreOffset /*StackOffset*/, + IDLoc, LoadInsts); + + for (const MCInst &Inst : LoadInsts) + Instructions.push_back(Inst); + + } else { + Warning(IDLoc, "no .cprestore used in PIC mode"); + } + } return false; } @@ -1778,7 +1822,10 @@ if (Opcode == Mips::JalOneReg) { // jal $rs => jalr $rs - if (inMicroMipsMode()) { + if (IsCpRestoreSet && inMicroMipsMode()) { + JalrInst.setOpcode(Mips::JALRS16_MM); + JalrInst.addOperand(FirstRegOp); + } else if (inMicroMipsMode()) { JalrInst.setOpcode(Mips::JALR16_MM); JalrInst.addOperand(FirstRegOp); } else { @@ -1788,7 +1835,10 @@ } } else if (Opcode == Mips::JalTwoReg) { // jal $rd, $rs => jalr $rd, $rs - JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + if (IsCpRestoreSet && inMicroMipsMode()) + JalrInst.setOpcode(Mips::JALRS_MM); + else + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); JalrInst.addOperand(FirstRegOp); const MCOperand SecondRegOp = Inst.getOperand(1); JalrInst.addOperand(SecondRegOp); @@ -1796,16 +1846,8 @@ Instructions.push_back(JalrInst); // If .set reorder is active, emit a NOP after it. - if (AssemblerOptions.back()->isReorder()) { - // This is a 32-bit NOP because these 2 pseudo-instructions - // do not have a short delay slot. - MCInst NopInst; - NopInst.setOpcode(Mips::SLL); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); - NopInst.addOperand(MCOperand::CreateImm(0)); - Instructions.push_back(NopInst); - } + if (AssemblerOptions.back()->isReorder()) + createNop(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc, Instructions); return false; } @@ -2255,6 +2297,26 @@ Instructions.push_back(NopInst); } +void MipsAsmParser::createCpRestoreMemOp( + bool IsLoad, int StackOffset, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + MCInst MemInst; + if (IsLoad) + MemInst.setOpcode(Mips::LW); + else + MemInst.setOpcode(Mips::SW); + + MemInst.addOperand(MCOperand::CreateReg(Mips::GP)); + MemInst.addOperand(MCOperand::CreateReg(Mips::SP)); + MemInst.addOperand(MCOperand::CreateImm(StackOffset)); + + // If the offset can not fit into 16 bits, we need to expand. + if (StackOffset < -32768 || StackOffset > 32767) + expandMemInst(MemInst, IDLoc, Instructions, IsLoad, true /*HasImmOpnd*/); + else + Instructions.push_back(MemInst); +} + unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { // As described by the Mips32r2 spec, the registers Rd and Rs for // jalr.hb must be different. @@ -3885,6 +3947,54 @@ return false; } +bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) { + MCAsmParser &Parser = getParser(); + + // Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it + // is used in non-PIC mode. + + if (inMips16Mode()) { + reportParseError(".cprestore is not supported in Mips16 mode"); + return false; + } + + // Get the stack offset value. + const MCExpr *StackOffset; + int64_t StackOffsetVal; + if (Parser.parseExpression(StackOffset)) { + reportParseError("expected stack offset value"); + return false; + } + + if (!StackOffset->EvaluateAsAbsolute(StackOffsetVal)) { + reportParseError("stack offset is not an absolute expression"); + return false; + } + + if (StackOffsetVal < 0) { + Warning(Loc, ".cprestore with negative stack offset has no effect"); + IsCpRestoreSet = false; + } else { + IsCpRestoreSet = true; + CpRestoreOffset = StackOffsetVal; + } + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + // Store the $gp on the stack. + SmallVector StoreInsts; + createCpRestoreMemOp(false /*IsLoad*/, CpRestoreOffset /*StackOffset*/, Loc, + StoreInsts); + + getTargetStreamer().emitDirectiveCpRestore(StoreInsts, CpRestoreOffset); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseDirectiveCPSetup() { MCAsmParser &Parser = getParser(); unsigned FuncReg; @@ -4306,6 +4416,8 @@ if (IDVal == ".cpload") return parseDirectiveCpLoad(DirectiveID.getLoc()); + if (IDVal == ".cprestore") + return parseDirectiveCpRestore(DirectiveID.getLoc()); if (IDVal == ".dword") { parseDataDirective(8, DirectiveID.getLoc()); return false; @@ -4356,6 +4468,7 @@ getTargetStreamer().emitDirectiveEnt(*Sym); CurrentFn = Sym; + IsCpRestoreSet = false; return false; } @@ -4384,6 +4497,7 @@ getTargetStreamer().emitDirectiveEnd(SymbolName); CurrentFn = nullptr; + IsCpRestoreSet = false; return false; } @@ -4455,6 +4569,7 @@ getTargetStreamer().emitFrame(StackReg, FrameSizeVal, ReturnRegOpnd.getGPR32Reg()); + IsCpRestoreSet = false; return false; } Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -83,6 +83,8 @@ void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {} +void MipsTargetStreamer::emitDirectiveCpRestore( + SmallVector &StoreInsts, int Offset) {} void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) { } @@ -329,6 +331,12 @@ forbidModuleDirective(); } +void MipsTargetAsmStreamer::emitDirectiveCpRestore( + SmallVector &StoreInsts, int Offset) { + OS << "\t.cprestore\t" << Offset << "\n"; + forbidModuleDirective(); +} + void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, @@ -715,6 +723,25 @@ forbidModuleDirective(); } +void MipsTargetELFStreamer::emitDirectiveCpRestore( + SmallVector &StoreInsts, int Offset) { + // .cprestore offset + // When PIC mode is enabled and the O32 ABI is used, this directive expands + // to: + // sw $gp, offset($sp) + // and adds a corresponding LW after every JAL. + + // Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it + // is used in non-PIC mode. + if (!Pic || (getABI().IsN32() || getABI().IsN64())) + return; + + for (const MCInst &Inst : StoreInsts) + getStreamer().EmitInstruction(Inst, STI); + + forbidModuleDirective(); +} + void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -74,6 +74,8 @@ // PIC support virtual void emitDirectiveCpLoad(unsigned RegNo); + virtual void emitDirectiveCpRestore(SmallVector &StoreInsts, + int Offset); virtual void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg); @@ -189,6 +191,8 @@ // PIC support void emitDirectiveCpLoad(unsigned RegNo) override; + void emitDirectiveCpRestore(SmallVector &StoreInsts, + int Offset) override; void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; @@ -234,6 +238,8 @@ // PIC support void emitDirectiveCpLoad(unsigned RegNo) override; + void emitDirectiveCpRestore(SmallVector &StoreInsts, + int Offset) override; void emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, const MCSymbol &Sym, bool IsReg) override; Index: test/MC/Mips/cprestore-bad.s =================================================================== --- /dev/null +++ test/MC/Mips/cprestore-bad.s @@ -0,0 +1,23 @@ +# RUN: not llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic 2>%t1 +# RUN: FileCheck %s < %t1 + + .text + .set noreorder + .cpload $25 + + .set mips16 + .cprestore 8 +# CHECK: :[[@LINE-1]]:14: error: .cprestore is not supported in Mips16 mode + .set nomips16 + + .cprestore +# CHECK: :[[@LINE-1]]:13: error: expected stack offset value + + .cprestore foo +# CHECK: :[[@LINE-1]]:17: error: stack offset is not an absolute expression + + .cprestore -8 +# CHECK: :[[@LINE-1]]:3: warning: .cprestore with negative stack offset has no effect + + .cprestore 8, 35, bar +# CHECK: :[[@LINE-1]]:15: error: unexpected token, expected end of statement Index: test/MC/Mips/cprestore-noreorder.s =================================================================== --- /dev/null +++ test/MC/Mips/cprestore-noreorder.s @@ -0,0 +1,97 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -| \ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=CHECK-FOR-STORE + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+micromips -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=static -show-encoding | \ +# RUN: FileCheck %s -check-prefix=NO-PIC + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N64 + + .text + .ent foo +foo: + .frame $sp, 0, $ra + .set noreorder + + .cpload $25 + .cprestore 8 + + jal $25 + jal $4, $25 + jal foo + + .end foo + +# CHECK-FOR-STORE: sw $gp, 8($sp) + +# CHECK: .cprestore 8 +# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# CHECK: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# CHECK: lw $25, %got(foo)($gp) # encoding: [0x8f,0x99,A,A] +# CHECK: # fixup A - offset: 0, value: foo@GOT, kind: fixup_Mips_GOT_Local +# CHECK: addiu $25, $25, %lo(foo) # encoding: [0x27,0x39,A,A] +# CHECK: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# CHECK: .end foo + +# MICROMIPS: .cprestore 8 +# MICROMIPS: jalrs16 $25 # encoding: [0x45,0xf9] +# MICROMIPS: nop # encoding: [0x00,0x00,0x00,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] + +# MICROMIPS: jalrs $4, $25 # encoding: [0x00,0x99,0x4f,0x3c] +# MICROMIPS: nop # encoding: [0x00,0x00,0x00,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] + +# MICROMIPS: lw $25, %got(foo)($gp) # encoding: [0xff,0x3c,A,A] +# MICROMIPS: # fixup A - offset: 0, value: foo@GOT, kind: fixup_MICROMIPS_GOT16 +# MICROMIPS: addiu $25, $25, %lo(foo) # encoding: [0x33,0x39,A,A] +# MICROMIPS: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_MICROMIPS_LO16 +# MICROMIPS: jalrs $ra, $25 # encoding: [0x03,0xf9,0x4f,0x3c] +# MICROMIPS: nop # encoding: [0x0c,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] +# MICROMIPS: .end foo + +# NO-PIC: .cprestore 8 +# NO-PIC: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# NO-PIC: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# NO-PIC: jal foo # encoding: [0b000011AA,A,A,A] +# NO-PIC: # fixup A - offset: 0, value: foo, kind: fixup_Mips_26 +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# NO-PIC: .end foo + +# BAD-ABI: .cprestore 8 +# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# BAD-ABI: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# BAD-ABI-N32: lw $25, %got_disp(foo)($gp) # encoding: [0x8f,0x99,A,A] +# BAD-ABI-N64: ld $25, %got_disp(foo)($gp) # encoding: [0xdf,0x99,A,A] +# BAD-ABI: # fixup A - offset: 0, value: foo@GOT_DISP, kind: fixup_Mips_GOT_DISP +# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# BAD-ABI: .end foo Index: test/MC/Mips/cprestore-reorder.s =================================================================== --- /dev/null +++ test/MC/Mips/cprestore-reorder.s @@ -0,0 +1,98 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -| \ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=CHECK-FOR-STORE + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=+micromips -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=static -show-encoding | \ +# RUN: FileCheck %s -check-prefix=NO-PIC + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -relocation-model=pic -show-encoding | \ +# RUN: FileCheck %s -check-prefix=BAD-ABI -check-prefix=BAD-ABI-N64 + + .text + .ent foo +foo: + .frame $sp, 0, $ra + .set noreorder + .cpload $25 + .set reorder + + .cprestore 8 + + jal $25 + jal $4, $25 + jal foo + + .end foo + +# CHECK-FOR-STORE: sw $gp, 8($sp) + +# CHECK: .cprestore 8 +# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# CHECK: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# CHECK: lw $25, %got(foo)($gp) # encoding: [0x8f,0x99,A,A] +# CHECK: # fixup A - offset: 0, value: foo@GOT, kind: fixup_Mips_GOT_Local +# CHECK: addiu $25, $25, %lo(foo) # encoding: [0x27,0x39,A,A] +# CHECK: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# CHECK: nop # encoding: [0x00,0x00,0x00,0x00] +# CHECK: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# CHECK: .end foo + +# MICROMIPS: .cprestore 8 +# MICROMIPS: jalrs16 $25 # encoding: [0x45,0xf9] +# MICROMIPS: nop # encoding: [0x0c,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] + +# MICROMIPS: jalrs $4, $25 # encoding: [0x00,0x99,0x4f,0x3c] +# MICROMIPS: nop # encoding: [0x0c,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] + +# MICROMIPS: lw $25, %got(foo)($gp) # encoding: [0xff,0x3c,A,A] +# MICROMIPS: # fixup A - offset: 0, value: foo@GOT, kind: fixup_MICROMIPS_GOT16 +# MICROMIPS: addiu $25, $25, %lo(foo) # encoding: [0x33,0x39,A,A] +# MICROMIPS: # fixup A - offset: 0, value: foo@ABS_LO, kind: fixup_MICROMIPS_LO16 +# MICROMIPS: jalrs $ra, $25 # encoding: [0x03,0xf9,0x4f,0x3c] +# MICROMIPS: nop # encoding: [0x0c,0x00] +# MICROMIPS: lw $gp, 8($sp) # encoding: [0xff,0x9d,0x00,0x08] +# MICROMIPS: .end foo + +# NO-PIC: .cprestore 8 +# NO-PIC: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# NO-PIC: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# NO-PIC: jal foo # encoding: [0b000011AA,A,A,A] +# NO-PIC: # fixup A - offset: 0, value: foo, kind: fixup_Mips_26 +# NO-PIC-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# NO-PIC: .end foo + +# BAD-ABI: .cprestore 8 +# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# BAD-ABI: jalr $4, $25 # encoding: [0x03,0x20,0x20,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] + +# BAD-ABI-N32: lw $25, %got_disp(foo)($gp) # encoding: [0x8f,0x99,A,A] +# BAD-ABI-N64: ld $25, %got_disp(foo)($gp) # encoding: [0xdf,0x99,A,A] +# BAD-ABI: # fixup A - offset: 0, value: foo@GOT_DISP, kind: fixup_Mips_GOT_DISP +# BAD-ABI: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# BAD-ABI-NOT: lw $gp, 8($sp) # encoding: [0x8f,0xbc,0x00,0x08] +# BAD-ABI: .end foo Index: test/MC/Mips/cprestore-warning-unused.s =================================================================== --- /dev/null +++ test/MC/Mips/cprestore-warning-unused.s @@ -0,0 +1,10 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic 2>%t1 +# RUN: FileCheck %s < %t1 + + .text + .set noreorder + .cpload $25 + .set reorder + + jal $25 +# CHECK: :[[@LINE-1]]:3: warning: no .cprestore used in PIC mode