Overview: When parsing a function label, AsmParser emits the .thumb_func directive and closes the open IT block (if one is open right before the function label) too late, so that both the .thumb_func directive and conditional instructions of the IT block are emitted after the function label.
Steps to Reproduce:
1) Save the following native assembly code to it-block.S:
Note two types of errors: i. For both function labels f1 and f2, the corresponding .thumb_func directive is after the function label; ii. The movpl instruction, which should be before f2 and is NOT part of function f2, is emitted after f2 and becomes part of function f2.
Expected Results: i. For both function labels f1 and f2, the corresponding .thumb_func directive should be before the label; ii. The movepl instruction should be before label f2.
Additional information:
As the following code snippet copied from lib/MC/MCParser/AsmParser.cpp shows, when parsing a label, AsmParser::parseStatement calls MCTargetAsmParser::onLabelParsed of a target parser after emitting the label:
// Emit the label.
if (!getTargetParser().isParsingInlineAsm())
Out.EmitLabel(Sym, IDLoc);
// If we are generating dwarf for assembly source files then gather the
// info to make a dwarf label entry for this label if needed.
if (getContext().getGenDwarfForAssembly())
MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),
IDLoc);
getTargetParser().onLabelParsed(Sym);
For ARM, calling MCTargetAsmParser::onLabelParsed after emitting the label seems to be the cause of the bug.
If I understand it correctly, ARMAsmParser::onLabelParsed (defined in lib/Target/ARM/AsmParser/ARMAsmParser.cpp) performs two tasks: i. Close the current implicit IT block (if one is open for new conditional instructions) BEFORE the label, so that the IT block cannot be entered from the middle of it. ii. Emit a .thumb_func directive, if the label is the first label following a previously parsed .thumb_func directive without an optional symbol. It seems that the two types of errors are direct consequences of calling MCTargetAsmParser::onLabelParsed after emitting the label being parsed.
What's more, MCTargetAsmParser::onLabelParsed seems to be only used by the ARM backend.
Therefore, in order to fix the bug, it seems sufficient to call MCTargetAsmParser::onLabelParsed before emitting the label being parsed.
Extended Description
Overview: When parsing a function label, AsmParser emits the .thumb_func directive and closes the open IT block (if one is open right before the function label) too late, so that both the .thumb_func directive and conditional instructions of the IT block are emitted after the function label.
Steps to Reproduce:
1) Save the following native assembly code to it-block.S:
f1: CMP r0, #10
f2: MOVS r1, #0 .Ltmp: CMP r0, #0 ITTT PL ADDPL r1, r1, r0 SUBPL r0, r0, #1 BPL .Ltmp MOV r0, r1 BX lr
2) Run llvm-mc on it-block.S and ask it to generate native assembly code, using the following command line:
llvm-mc -arch=thumb -filetype=asm -mattr=+soft-float,-neon,-crypto,+strict-align -mcpu=cortex-m3 -n -triple=armv7m-none-none-eabi -o=it-block-roundtrip.s it-block.S -arm-implicit-it=always
Actual Results: The native assembly code generated by llvm-mc is as follows:
.text .p2align 1 .code 16 .globl f1 .globl f2 f1: .thumb_func cmp r0, #10
f2: it pl movpl r0, #0 .thumb_func movs r1, #0 .Ltmp: cmp r0, #0 ittt pl addpl r1, r1, r0 subpl r0, r0, #1 bpl .Ltmp mov r0, r1 bx lr
Note two types of errors: i. For both function labels f1 and f2, the corresponding .thumb_func directive is after the function label; ii. The movpl instruction, which should be before f2 and is NOT part of function f2, is emitted after f2 and becomes part of function f2.
Expected Results: i. For both function labels f1 and f2, the corresponding .thumb_func directive should be before the label; ii. The movepl instruction should be before label f2.
Additional information:
As the following code snippet copied from lib/MC/MCParser/AsmParser.cpp shows, when parsing a label, AsmParser::parseStatement calls MCTargetAsmParser::onLabelParsed of a target parser after emitting the label:
For ARM, calling MCTargetAsmParser::onLabelParsed after emitting the label seems to be the cause of the bug.
If I understand it correctly, ARMAsmParser::onLabelParsed (defined in lib/Target/ARM/AsmParser/ARMAsmParser.cpp) performs two tasks: i. Close the current implicit IT block (if one is open for new conditional instructions) BEFORE the label, so that the IT block cannot be entered from the middle of it. ii. Emit a .thumb_func directive, if the label is the first label following a previously parsed .thumb_func directive without an optional symbol. It seems that the two types of errors are direct consequences of calling MCTargetAsmParser::onLabelParsed after emitting the label being parsed.
What's more, MCTargetAsmParser::onLabelParsed seems to be only used by the ARM backend.
Therefore, in order to fix the bug, it seems sufficient to call MCTargetAsmParser::onLabelParsed before emitting the label being parsed.