mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
ARM IAS: support .movsp
.movsp is an ARM unwinding directive that indicates to the unwinder that a register contains an offset from the current stack pointer. If the offset is unspecified, it defaults to zero. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200449 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2c9ed5d050
commit
7a38b33dec
@ -93,6 +93,7 @@ public:
|
||||
virtual void emitHandlerData() = 0;
|
||||
virtual void emitSetFP(unsigned FpReg, unsigned SpReg,
|
||||
int64_t Offset = 0) = 0;
|
||||
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0) = 0;
|
||||
virtual void emitPad(int64_t Offset) = 0;
|
||||
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
|
||||
bool isVector) = 0;
|
||||
|
@ -1091,11 +1091,11 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
|
||||
// instruction.
|
||||
ATS.emitPad(Offset);
|
||||
} else {
|
||||
MI->dump();
|
||||
llvm_unreachable("Unsupported opcode for unwinding information");
|
||||
// Move of SP to a register. Positive values correspond to an "add"
|
||||
// instruction.
|
||||
ATS.emitMovSP(DstReg, -Offset);
|
||||
}
|
||||
} else if (DstReg == ARM::SP) {
|
||||
// FIXME: .movsp goes here
|
||||
MI->dump();
|
||||
llvm_unreachable("Unsupported opcode for unwinding information");
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ class UnwindContext {
|
||||
int FPReg;
|
||||
|
||||
public:
|
||||
UnwindContext(MCAsmParser &P) : Parser(P), FPReg(-1) {}
|
||||
UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {}
|
||||
|
||||
bool hasFnStart() const { return !FnStartLocs.empty(); }
|
||||
bool cantUnwind() const { return !CantUnwindLocs.empty(); }
|
||||
@ -182,7 +182,7 @@ public:
|
||||
PersonalityLocs = Locs();
|
||||
HandlerDataLocs = Locs();
|
||||
PersonalityIndexLocs = Locs();
|
||||
FPReg = -1;
|
||||
FPReg = ARM::SP;
|
||||
}
|
||||
};
|
||||
|
||||
@ -297,6 +297,7 @@ class ARMAsmParser : public MCTargetAsmParser {
|
||||
bool parseDirectivePersonalityIndex(SMLoc L);
|
||||
bool parseDirectiveUnwindRaw(SMLoc L);
|
||||
bool parseDirectiveTLSDescSeq(SMLoc L);
|
||||
bool parseDirectiveMovSP(SMLoc L);
|
||||
|
||||
StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
|
||||
bool &CarrySetting, unsigned &ProcessorIMod,
|
||||
@ -8087,6 +8088,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
return parseDirectiveUnwindRaw(DirectiveID.getLoc());
|
||||
else if (IDVal == ".tlsdescseq")
|
||||
return parseDirectiveTLSDescSeq(DirectiveID.getLoc());
|
||||
else if (IDVal == ".movsp")
|
||||
return parseDirectiveMovSP(DirectiveID.getLoc());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8616,7 +8619,7 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) {
|
||||
}
|
||||
|
||||
// Consume comma
|
||||
if (!Parser.getTok().is(AsmToken::Comma)) {
|
||||
if (Parser.getTok().isNot(AsmToken::Comma)) {
|
||||
Error(Parser.getTok().getLoc(), "comma expected");
|
||||
return false;
|
||||
}
|
||||
@ -9028,6 +9031,69 @@ bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDirectiveMovSP
|
||||
/// ::= .movsp reg [, #offset]
|
||||
bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) {
|
||||
if (!UC.hasFnStart()) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(L, ".fnstart must precede .movsp directives");
|
||||
return false;
|
||||
}
|
||||
if (UC.getFPReg() != ARM::SP) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(L, "unexpected .movsp directive");
|
||||
return false;
|
||||
}
|
||||
|
||||
SMLoc SPRegLoc = Parser.getTok().getLoc();
|
||||
int SPReg = tryParseRegister();
|
||||
if (SPReg == -1) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(SPRegLoc, "register expected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SPReg == ARM::SP || SPReg == ARM::PC) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(SPRegLoc, "sp and pc are not permitted in .movsp directive");
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t Offset = 0;
|
||||
if (Parser.getTok().is(AsmToken::Comma)) {
|
||||
Parser.Lex();
|
||||
|
||||
if (Parser.getTok().isNot(AsmToken::Hash)) {
|
||||
Error(Parser.getTok().getLoc(), "expected #constant");
|
||||
Parser.eatToEndOfStatement();
|
||||
return false;
|
||||
}
|
||||
Parser.Lex();
|
||||
|
||||
const MCExpr *OffsetExpr;
|
||||
SMLoc OffsetLoc = Parser.getTok().getLoc();
|
||||
if (Parser.parseExpression(OffsetExpr)) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(OffsetLoc, "malformed offset expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
|
||||
if (!CE) {
|
||||
Parser.eatToEndOfStatement();
|
||||
Error(OffsetLoc, "offset must be an immediate constant");
|
||||
return false;
|
||||
}
|
||||
|
||||
Offset = CE->getValue();
|
||||
}
|
||||
|
||||
getTargetStreamer().emitMovSP(SPReg, Offset);
|
||||
UC.saveFPReg(SPReg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Force static initialization.
|
||||
extern "C" void LLVMInitializeARMAsmParser() {
|
||||
RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);
|
||||
|
@ -123,6 +123,7 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer {
|
||||
virtual void emitPersonalityIndex(unsigned Index);
|
||||
virtual void emitHandlerData();
|
||||
virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0);
|
||||
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0);
|
||||
virtual void emitPad(int64_t Offset);
|
||||
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
|
||||
bool isVector);
|
||||
@ -172,6 +173,16 @@ void ARMTargetAsmStreamer::emitSetFP(unsigned FpReg, unsigned SpReg,
|
||||
OS << ", #" << Offset;
|
||||
OS << '\n';
|
||||
}
|
||||
void ARMTargetAsmStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
|
||||
assert((Reg != ARM::SP && Reg != ARM::PC) &&
|
||||
"the operand of .movsp cannot be either sp or pc");
|
||||
|
||||
OS << "\t.movsp\t";
|
||||
InstPrinter.printRegName(OS, Reg);
|
||||
if (Offset)
|
||||
OS << ", #" << Offset;
|
||||
OS << '\n';
|
||||
}
|
||||
void ARMTargetAsmStreamer::emitPad(int64_t Offset) {
|
||||
OS << "\t.pad\t#" << Offset << '\n';
|
||||
}
|
||||
@ -387,6 +398,7 @@ private:
|
||||
virtual void emitPersonalityIndex(unsigned Index);
|
||||
virtual void emitHandlerData();
|
||||
virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0);
|
||||
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0);
|
||||
virtual void emitPad(int64_t Offset);
|
||||
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
|
||||
bool isVector);
|
||||
@ -448,6 +460,7 @@ public:
|
||||
void emitPersonalityIndex(unsigned index);
|
||||
void emitHandlerData();
|
||||
void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0);
|
||||
void emitMovSP(unsigned Reg, int64_t Offset = 0);
|
||||
void emitPad(int64_t Offset);
|
||||
void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector);
|
||||
void emitUnwindRaw(int64_t Offset, const SmallVectorImpl<uint8_t> &Opcodes);
|
||||
@ -657,6 +670,9 @@ void ARMTargetELFStreamer::emitSetFP(unsigned FpReg, unsigned SpReg,
|
||||
int64_t Offset) {
|
||||
getStreamer().emitSetFP(FpReg, SpReg, Offset);
|
||||
}
|
||||
void ARMTargetELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
|
||||
getStreamer().emitMovSP(Reg, Offset);
|
||||
}
|
||||
void ARMTargetELFStreamer::emitPad(int64_t Offset) {
|
||||
getStreamer().emitPad(Offset);
|
||||
}
|
||||
@ -1203,6 +1219,20 @@ void ARMELFStreamer::emitSetFP(unsigned NewFPReg, unsigned NewSPReg,
|
||||
FPOffset += Offset;
|
||||
}
|
||||
|
||||
void ARMELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
|
||||
assert((Reg != ARM::SP && Reg != ARM::PC) &&
|
||||
"the operand of .movsp cannot be either sp or pc");
|
||||
assert(FPReg == ARM::SP && "current FP must be SP");
|
||||
|
||||
FlushPendingOffset();
|
||||
|
||||
FPReg = Reg;
|
||||
FPOffset = SPOffset + Offset;
|
||||
|
||||
const MCRegisterInfo *MRI = getContext().getRegisterInfo();
|
||||
UnwindOpAsm.EmitSetSP(MRI->getEncodingValue(FPReg));
|
||||
}
|
||||
|
||||
void ARMELFStreamer::emitPad(int64_t Offset) {
|
||||
// Track the change of the $sp offset
|
||||
SPOffset -= Offset;
|
||||
|
102
test/MC/ARM/eh-directive-movsp-diagnostics.s
Normal file
102
test/MC/ARM/eh-directive-movsp-diagnostics.s
Normal file
@ -0,0 +1,102 @@
|
||||
@ RUN: not llvm-mc -triple armv7-eabi -filetype asm -o /dev/null 2>&1 %s \
|
||||
@ RUN: | FileCheck %s
|
||||
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.global false_start
|
||||
.type false_start,%function
|
||||
.thumb_func
|
||||
false_start:
|
||||
.movsp r7
|
||||
|
||||
@ CHECK: error: .fnstart must precede .movsp directive
|
||||
@ CHECK: .movsp r7
|
||||
@ CHECK: ^
|
||||
|
||||
.global beyond_saving
|
||||
.type beyond_saving,%function
|
||||
.thumb_func
|
||||
beyond_saving:
|
||||
.fnstart
|
||||
.setfp r11, sp, #8
|
||||
add r11, sp, #8
|
||||
.movsp r7
|
||||
mov r7, r11
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: unexpected .movsp directive
|
||||
@ CHECK: .movsp r7
|
||||
@ CHECK: ^
|
||||
|
||||
|
||||
.global sp_invalid
|
||||
.type sp_invalid,%function
|
||||
.thumb_func
|
||||
sp_invalid:
|
||||
.fnstart
|
||||
.movsp r13
|
||||
mov sp, sp
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: sp and pc are not permitted in .movsp directive
|
||||
@ CHECK: .movsp r13
|
||||
@ CHECK: ^
|
||||
|
||||
|
||||
.global pc_invalid
|
||||
.type pc_invalid,%function
|
||||
.thumb_func
|
||||
pc_invalid:
|
||||
.fnstart
|
||||
.movsp r15
|
||||
mov sp, pc
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: sp and pc are not permitted in .movsp directive
|
||||
@ CHECK: .movsp r15
|
||||
@ CHECK: ^
|
||||
|
||||
|
||||
.global constant_required
|
||||
.type constant_required,%function
|
||||
.thumb_func
|
||||
constant_required:
|
||||
.fnstart
|
||||
.movsp r11,
|
||||
mov sp, r11
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: expected #constant
|
||||
@ CHECK: .movsp r11,
|
||||
@ CHECK: ^
|
||||
|
||||
|
||||
.global constant_constant
|
||||
.type constant_constant,%function
|
||||
.thumb_func
|
||||
constant_constant:
|
||||
.fnstart
|
||||
.movsp r11, #constant
|
||||
mov sp, r11
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: offset must be an immediate constant
|
||||
@ CHECK: .movsp r11, #constant
|
||||
@ CHECK: ^
|
||||
|
||||
|
||||
.arm
|
||||
|
||||
.global register_required
|
||||
.type register_required,%function
|
||||
register_required:
|
||||
.fnstart
|
||||
.movsp #42
|
||||
mov sp, #42
|
||||
.fnend
|
||||
|
||||
@ CHECK: error: register expected
|
||||
@ CHECK: .movsp #42
|
||||
@ CHECK: ^
|
||||
|
44
test/MC/ARM/eh-directive-movsp.s
Normal file
44
test/MC/ARM/eh-directive-movsp.s
Normal file
@ -0,0 +1,44 @@
|
||||
@ RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s | llvm-readobj -s -sd \
|
||||
@ RUN: | FileCheck %s
|
||||
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.section .duplicate
|
||||
|
||||
.global duplicate
|
||||
.type duplicate,%function
|
||||
duplicate:
|
||||
.fnstart
|
||||
.setfp sp, sp, #8
|
||||
add sp, sp, #8
|
||||
.movsp r11
|
||||
mov r11, sp
|
||||
.fnend
|
||||
|
||||
@ CHECK: Section {
|
||||
@ CHECK: Name: .ARM.exidx.duplicate
|
||||
@ CHECK: SectionData (
|
||||
@ CHECK: 0000: 00000000 B09B9B80
|
||||
@ CHECK: )
|
||||
@ CHECK: }
|
||||
|
||||
|
||||
.section .squash
|
||||
|
||||
.global squash
|
||||
.type squash,%function
|
||||
squash:
|
||||
.fnstart
|
||||
.movsp ip
|
||||
mov ip, sp
|
||||
.save {fp, ip, lr}
|
||||
stmfd sp!, {fp, ip, lr}
|
||||
.fnend
|
||||
|
||||
@ CHECK: Section {
|
||||
@ CHECK: Name: .ARM.exidx.squash
|
||||
@ CHECK: SectionData (
|
||||
@ CHECK: 0000: 00000000 9C808580
|
||||
@ CHECK: )
|
||||
@ CHECK: }
|
Loading…
Reference in New Issue
Block a user