Skip to content

Commit 8da1908

Browse files
committed
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.
1 parent fd59209 commit 8da1908

File tree

5 files changed

+241
-3
lines changed

5 files changed

+241
-3
lines changed

include/llvm/MC/MCStreamer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class ARMTargetStreamer : public MCTargetStreamer {
8686
virtual void emitHandlerData() = 0;
8787
virtual void emitSetFP(unsigned FpReg, unsigned SpReg,
8888
int64_t Offset = 0) = 0;
89+
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0) = 0;
8990
virtual void emitPad(int64_t Offset) = 0;
9091
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
9192
bool isVector) = 0;

lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class UnwindContext {
126126
int FPReg;
127127

128128
public:
129-
UnwindContext(MCAsmParser &P) : Parser(P), FPReg(-1) {}
129+
UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {}
130130

131131
bool hasFnStart() const { return !FnStartLocs.empty(); }
132132
bool cantUnwind() const { return !CantUnwindLocs.empty(); }
@@ -181,7 +181,7 @@ class UnwindContext {
181181
PersonalityLocs = Locs();
182182
HandlerDataLocs = Locs();
183183
PersonalityIndexLocs = Locs();
184-
FPReg = -1;
184+
FPReg = ARM::SP;
185185
}
186186
};
187187

@@ -294,6 +294,7 @@ class ARMAsmParser : public MCTargetAsmParser {
294294
bool parseDirectiveLtorg(SMLoc L);
295295
bool parseDirectiveEven(SMLoc L);
296296
bool parseDirectivePersonalityIndex(SMLoc L);
297+
bool parseDirectiveMovSP(SMLoc L);
297298

298299
StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
299300
bool &CarrySetting, unsigned &ProcessorIMod,
@@ -8021,6 +8022,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
80218022
parseDirectiveEven(DirectiveID.getLoc());
80228023
else if (IDVal == ".personalityindex")
80238024
parseDirectivePersonalityIndex(DirectiveID.getLoc());
8025+
else if (IDVal == ".movsp")
8026+
parseDirectiveMovSP(DirectiveID.getLoc());
80248027
else
80258028
return true;
80268029
return false;
@@ -8550,7 +8553,7 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) {
85508553
}
85518554

85528555
// Consume comma
8553-
if (!Parser.getTok().is(AsmToken::Comma)) {
8556+
if (Parser.getTok().isNot(AsmToken::Comma)) {
85548557
Error(Parser.getTok().getLoc(), "comma expected");
85558558
return false;
85568559
}
@@ -8856,6 +8859,69 @@ bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) {
88568859
return false;
88578860
}
88588861

8862+
/// parseDirectiveMovSP
8863+
/// ::= .movsp reg [, #offset]
8864+
bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) {
8865+
if (!UC.isValid()) {
8866+
Parser.eatToEndOfStatement();
8867+
Error(L, ".fnstart must precede .movsp directives");
8868+
return false;
8869+
}
8870+
if (UC.getFPReg() != ARM::SP) {
8871+
Parser.eatToEndOfStatement();
8872+
Error(L, "unexpected .movsp directive");
8873+
return false;
8874+
}
8875+
8876+
SMLoc SPRegLoc = Parser.getTok().getLoc();
8877+
int SPReg = tryParseRegister();
8878+
if (SPReg == -1) {
8879+
Parser.eatToEndOfStatement();
8880+
Error(SPRegLoc, "register expected");
8881+
return false;
8882+
}
8883+
8884+
if (SPReg == ARM::SP || SPReg == ARM::PC) {
8885+
Parser.eatToEndOfStatement();
8886+
Error(SPRegLoc, "sp and pc are not permitted in .movsp directive");
8887+
return false;
8888+
}
8889+
8890+
int64_t Offset = 0;
8891+
if (Parser.getTok().is(AsmToken::Comma)) {
8892+
Parser.Lex();
8893+
8894+
if (Parser.getTok().isNot(AsmToken::Hash)) {
8895+
Error(Parser.getTok().getLoc(), "expected #constant");
8896+
Parser.eatToEndOfStatement();
8897+
return false;
8898+
}
8899+
Parser.Lex();
8900+
8901+
const MCExpr *OffsetExpr;
8902+
SMLoc OffsetLoc = Parser.getTok().getLoc();
8903+
if (Parser.parseExpression(OffsetExpr)) {
8904+
Parser.eatToEndOfStatement();
8905+
Error(OffsetLoc, "malformed offset expression");
8906+
return false;
8907+
}
8908+
8909+
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
8910+
if (!CE) {
8911+
Parser.eatToEndOfStatement();
8912+
Error(OffsetLoc, "offset must be an immediate constant");
8913+
return false;
8914+
}
8915+
8916+
Offset = CE->getValue();
8917+
}
8918+
8919+
getTargetStreamer().emitMovSP(SPReg, Offset);
8920+
UC.saveFPReg(SPReg);
8921+
8922+
return false;
8923+
}
8924+
88598925
/// Force static initialization.
88608926
extern "C" void LLVMInitializeARMAsmParser() {
88618927
RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);

lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer {
120120
virtual void emitPersonalityIndex(unsigned Index);
121121
virtual void emitHandlerData();
122122
virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0);
123+
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0);
123124
virtual void emitPad(int64_t Offset);
124125
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
125126
bool isVector);
@@ -163,6 +164,13 @@ void ARMTargetAsmStreamer::emitSetFP(unsigned FpReg, unsigned SpReg,
163164
OS << ", #" << Offset;
164165
OS << '\n';
165166
}
167+
void ARMTargetAsmStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
168+
OS << "\t.movfp\t";
169+
InstPrinter.printRegName(OS, Reg);
170+
if (Offset)
171+
OS << ", #" << Offset;
172+
OS << '\n';
173+
}
166174
void ARMTargetAsmStreamer::emitPad(int64_t Offset) {
167175
OS << "\t.pad\t#" << Offset << '\n';
168176
}
@@ -361,6 +369,7 @@ class ARMTargetELFStreamer : public ARMTargetStreamer {
361369
virtual void emitPersonalityIndex(unsigned Index);
362370
virtual void emitHandlerData();
363371
virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0);
372+
virtual void emitMovSP(unsigned Reg, int64_t Offset = 0);
364373
virtual void emitPad(int64_t Offset);
365374
virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
366375
bool isVector);
@@ -420,6 +429,7 @@ class ARMELFStreamer : public MCELFStreamer {
420429
void emitPersonalityIndex(unsigned index);
421430
void emitHandlerData();
422431
void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0);
432+
void emitMovSP(unsigned Reg, int64_t Offset = 0);
423433
void emitPad(int64_t Offset);
424434
void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector);
425435

@@ -627,6 +637,9 @@ void ARMTargetELFStreamer::emitSetFP(unsigned FpReg, unsigned SpReg,
627637
int64_t Offset) {
628638
getStreamer().emitSetFP(FpReg, SpReg, Offset);
629639
}
640+
void ARMTargetELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
641+
getStreamer().emitMovSP(Reg, Offset);
642+
}
630643
void ARMTargetELFStreamer::emitPad(int64_t Offset) {
631644
getStreamer().emitPad(Offset);
632645
}
@@ -1163,6 +1176,18 @@ void ARMELFStreamer::emitSetFP(unsigned NewFPReg, unsigned NewSPReg,
11631176
FPOffset += Offset;
11641177
}
11651178

1179+
void ARMELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) {
1180+
assert((Reg != ARM::SP && Reg != ARM::PC) &&
1181+
"the operand of .movsp cannot be either sp or pc");
1182+
assert(UsedFP && ".setfp must precede .movsp");
1183+
1184+
FPReg = Reg;
1185+
FPOffset = SPOffset + Offset;
1186+
1187+
const MCRegisterInfo *MRI = getContext().getRegisterInfo();
1188+
UnwindOpAsm.EmitSetSP(MRI->getEncodingValue(FPReg));
1189+
}
1190+
11661191
void ARMELFStreamer::emitPad(int64_t Offset) {
11671192
// Track the change of the $sp offset
11681193
SPOffset -= Offset;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
@ RUN: not llvm-mc -triple armv7-eabi -filetype asm -o /dev/null 2>&1 %s \
2+
@ RUN: | FileCheck %s
3+
4+
.syntax unified
5+
.thumb
6+
7+
.global false_start
8+
.type false_start,%function
9+
.thumb_func
10+
false_start:
11+
.movsp r7
12+
13+
@ CHECK: error: .fnstart must precede .movsp directive
14+
@ CHECK: .movsp r7
15+
@ CHECK: ^
16+
17+
.global beyond_saving
18+
.type beyond_saving,%function
19+
.thumb_func
20+
beyond_saving:
21+
.fnstart
22+
.setfp r11, sp, #8
23+
add r11, sp, #8
24+
.movsp r7
25+
mov r7, r11
26+
.fnend
27+
28+
@ CHECK: error: unexpected .movsp directive
29+
@ CHECK: .movsp r7
30+
@ CHECK: ^
31+
32+
33+
.global sp_invalid
34+
.type sp_invalid,%function
35+
.thumb_func
36+
sp_invalid:
37+
.fnstart
38+
.movsp r13
39+
mov sp, sp
40+
.fnend
41+
42+
@ CHECK: error: sp and pc are not permitted in .movsp directive
43+
@ CHECK: .movsp r13
44+
@ CHECK: ^
45+
46+
47+
.global pc_invalid
48+
.type pc_invalid,%function
49+
.thumb_func
50+
pc_invalid:
51+
.fnstart
52+
.movsp r15
53+
mov sp, pc
54+
.fnend
55+
56+
@ CHECK: error: sp and pc are not permitted in .movsp directive
57+
@ CHECK: .movsp r15
58+
@ CHECK: ^
59+
60+
61+
.global constant_required
62+
.type constant_required,%function
63+
.thumb_func
64+
constant_required:
65+
.fnstart
66+
.movsp r11,
67+
mov sp, r11
68+
.fnend
69+
70+
@ CHECK: error: expected #constant
71+
@ CHECK: .movsp r11,
72+
@ CHECK: ^
73+
74+
75+
.global constant_constant
76+
.type constant_constant,%function
77+
.thumb_func
78+
constant_constant:
79+
.fnstart
80+
.movsp r11, #constant
81+
mov sp, r11
82+
.fnend
83+
84+
@ CHECK: error: offset must be an immediate constant
85+
@ CHECK: .movsp r11, #constant
86+
@ CHECK: ^
87+
88+
89+
.arm
90+
91+
.global register_required
92+
.type register_required,%function
93+
register_required:
94+
.fnstart
95+
.movsp #42
96+
mov sp, #42
97+
.fnend
98+
99+
@ CHECK: error: register expected
100+
@ CHECK: .movsp #42
101+
@ CHECK: ^
102+

test/MC/ARM/eh-directive-movsp.s

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@ RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s | llvm-readobj -s -sd \
2+
@ RUN: | FileCheck %s
3+
4+
.syntax unified
5+
.thumb
6+
7+
.section .duplicate
8+
9+
.global duplicate
10+
.type duplicate,%function
11+
duplicate:
12+
.fnstart
13+
.setfp sp, sp, #8
14+
add sp, sp, #8
15+
.movsp r11
16+
mov r11, sp
17+
.fnend
18+
19+
@ CHECK: Section {
20+
@ CHECK: Name: .ARM.exidx.duplicate
21+
@ CHECK: SectionData (
22+
@ CHECK: 0000: 00000000 B09B9B80
23+
@ CHECK: )
24+
@ CHECK: }
25+
26+
27+
.section .squash
28+
29+
.global squash
30+
.type squash,%function
31+
squash:
32+
.fnstart
33+
.movsp ip
34+
mov ip, sp
35+
.save {fp, ip, lr}
36+
stmfd sp!, {fp, ip, lr}
37+
.fnend
38+
39+
@ CHECK: Section {
40+
@ CHECK: Name: .ARM.exidx.squash
41+
@ CHECK: SectionData (
42+
@ CHECK: 0000: 00000000 9C808580
43+
@ CHECK: )
44+
@ CHECK: }

0 commit comments

Comments
 (0)