2010-04-04 21:09:29 +02:00
|
|
|
//===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
|
2010-04-04 20:34:07 +02:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2010-04-04 20:34:07 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2010-04-04 21:09:29 +02:00
|
|
|
// This file implements the inline assembler pieces of the AsmPrinter class.
|
2010-04-04 20:34:07 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2020-09-07 17:16:52 +02:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2017-06-06 13:49:48 +02:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2014-04-23 13:16:03 +02:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2017-11-08 02:01:31 +01:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 02:07:10 +01:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/Constants.h"
|
2014-01-03 20:21:54 +01:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2021-05-11 16:33:53 +02:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/InlineAsm.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2010-04-04 20:34:07 +02:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2016-01-27 11:01:28 +01:00
|
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
2010-04-04 20:34:07 +02:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2011-07-09 07:47:46 +02:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2010-04-04 20:34:07 +02:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
add .o file writing for inline asm in llc. Here's a silly
demo:
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
abc incl %eax
^
LLVM ERROR: Error parsing inline asm
Only problem seems to be that the parser finalizes OutStreamer
at the end of the first inline asm, which isn't what we want.
For example:
$ cat asm.c
int foo(int X) {
__asm__ ("incl %0" : "+r" (X));
return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
subq $8, %rsp
movl %edi, (%rsp)
movl %edi, %eax
## InlineAsm Start
incl %eax
## InlineAsm End
movl %eax, (%rsp)
movl %eax, 4(%rsp)
addq $8, %rsp
ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000 subq $0x08,%rsp
0000000000000004 movl %edi,(%rsp)
0000000000000007 movl %edi,%eax
0000000000000009 incl %eax
$
don't stop at inc!
llvm-svn: 100491
2010-04-06 01:11:24 +02:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2011-08-24 20:08:43 +02:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2010-04-04 20:34:07 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2010-04-04 20:34:07 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 04:02:50 +02:00
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr,
|
|
|
|
const MDNode *LocMDNode) const {
|
2021-02-23 18:47:15 +01:00
|
|
|
MCContext &Context = MMI->getContext();
|
|
|
|
Context.initInlineSourceManager();
|
|
|
|
SourceMgr &SrcMgr = *Context.getInlineSourceManager();
|
|
|
|
std::vector<const MDNode *> &LocInfos = Context.getLocInfos();
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
|
|
|
|
std::unique_ptr<MemoryBuffer> Buffer;
|
|
|
|
// The inline asm source manager will outlive AsmStr, so make a copy of the
|
|
|
|
// string for SourceMgr to own.
|
|
|
|
Buffer = MemoryBuffer::getMemBufferCopy(AsmStr, "<inline asm>");
|
|
|
|
|
|
|
|
// Tell SrcMgr about this buffer, it takes ownership of the buffer.
|
|
|
|
unsigned BufNum = SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
|
|
|
|
|
|
|
|
// Store LocMDNode in DiagInfo, using BufNum as an identifier.
|
|
|
|
if (LocMDNode) {
|
2021-02-23 18:47:15 +01:00
|
|
|
LocInfos.resize(BufNum);
|
|
|
|
LocInfos[BufNum - 1] = LocMDNode;
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return BufNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
/// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
|
2020-02-14 01:36:27 +01:00
|
|
|
void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
2015-05-15 02:20:44 +02:00
|
|
|
const MCTargetOptions &MCOptions,
|
2015-03-16 19:02:16 +01:00
|
|
|
const MDNode *LocMDNode,
|
2012-09-06 01:57:37 +02:00
|
|
|
InlineAsm::AsmDialect Dialect) const {
|
2010-04-04 20:34:07 +02:00
|
|
|
assert(!Str.empty() && "Can't emit empty inline asm block");
|
2010-10-02 01:29:12 +02:00
|
|
|
|
add .o file writing for inline asm in llc. Here's a silly
demo:
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
abc incl %eax
^
LLVM ERROR: Error parsing inline asm
Only problem seems to be that the parser finalizes OutStreamer
at the end of the first inline asm, which isn't what we want.
For example:
$ cat asm.c
int foo(int X) {
__asm__ ("incl %0" : "+r" (X));
return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
subq $8, %rsp
movl %edi, (%rsp)
movl %edi, %eax
## InlineAsm Start
incl %eax
## InlineAsm End
movl %eax, (%rsp)
movl %eax, 4(%rsp)
addq $8, %rsp
ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000 subq $0x08,%rsp
0000000000000004 movl %edi,(%rsp)
0000000000000007 movl %edi,%eax
0000000000000009 incl %eax
$
don't stop at inc!
llvm-svn: 100491
2010-04-06 01:11:24 +02:00
|
|
|
// Remember if the buffer is nul terminated or not so we can avoid a copy.
|
|
|
|
bool isNullTerminated = Str.back() == 0;
|
|
|
|
if (isNullTerminated)
|
|
|
|
Str = Str.substr(0, Str.size()-1);
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2014-02-13 15:44:26 +01:00
|
|
|
// If the output streamer does not have mature MC support or the integrated
|
2021-07-02 17:46:49 +02:00
|
|
|
// assembler has been disabled or not required, just emit the blob textually.
|
2014-02-13 15:44:26 +01:00
|
|
|
// Otherwise parse the asm and emit it via MC support.
|
2010-04-04 20:34:07 +02:00
|
|
|
// This is useful in case the asm parser doesn't handle something but the
|
|
|
|
// system assembler does.
|
2014-02-13 15:44:26 +01:00
|
|
|
const MCAsmInfo *MCAI = TM.getMCAsmInfo();
|
|
|
|
assert(MCAI && "No MCAsmInfo");
|
|
|
|
if (!MCAI->useIntegratedAssembler() &&
|
2021-07-02 17:46:49 +02:00
|
|
|
!MCAI->parseInlineAsmUsingAsmParser() &&
|
2015-04-24 21:11:51 +02:00
|
|
|
!OutStreamer->isIntegratedAssemblerRequired()) {
|
2015-02-19 20:52:25 +01:00
|
|
|
emitInlineAsmStart();
|
2020-02-15 17:52:56 +01:00
|
|
|
OutStreamer->emitRawText(Str);
|
2015-03-16 19:02:16 +01:00
|
|
|
emitInlineAsmEnd(STI, nullptr);
|
2010-04-04 20:34:07 +02:00
|
|
|
return;
|
|
|
|
}
|
2010-10-02 01:29:12 +02:00
|
|
|
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
|
2021-02-23 18:47:15 +01:00
|
|
|
SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
|
|
|
|
SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
|
[Assembler] Enable nicer diagnostics for inline assembly.
Summary:
Enables source location in diagnostic messages from the backend. This
is after parsing, during finalization. This requires the SourceMgr, the
inline assembly string buffer, and DiagInfo to still be alive after
EmitInlineAsm returns.
This patch creates a single SourceMgr for inline assembly inside the
AsmPrinter. MCContext gets a pointer to this SourceMgr. Using one
SourceMgr per call to EmitInlineAsm would make it difficult for
MCContext to figure out in which SourceMgr the SMLoc is located, while a
single SourceMgr can figure it out if it has multiple buffers.
The Str argument to EmitInlineAsm is copied into a buffer and owned by
the inline asm SourceMgr. This ensures that DiagHandlers won't print
garbage. (Clang emits a "note: instantiated into assembly here", which
refers to this string.)
The AsmParser gets destroyed before finalization, which means that the
DiagHandlers the AsmParser installs into the SourceMgr will be stale.
Restore the saved DiagHandlers.
Since now we're using just one SourceMgr for multiple inline asm
strings, we need to tell the AsmParser which buffer it needs to parse
currently. Hand a buffer id -- returned from SourceMgr::
AddNewSourceBuffer -- to the AsmParser.
Reviewers: rnk, grosbach, compnerd, rengolin, rovka, anemet
Reviewed By: rnk
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D29441
llvm-svn: 294433
2017-02-08 11:20:07 +01:00
|
|
|
|
2021-02-23 18:47:15 +01:00
|
|
|
std::unique_ptr<MCAsmParser> Parser(
|
|
|
|
createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
|
2011-07-08 03:53:10 +02:00
|
|
|
|
[MC] Change AsmParser to leverage Assembler during evaluation
Teach AsmParser to check with Assembler for when evaluating constant
expressions. This improves the handing of preprocessor expressions
that must be resolved at parse time. This idiom can be found as
assembling-time assertion checks in source-level assemblers. Note that
this relies on the MCStreamer to keep sufficient tabs on Section /
Fragment information which the MCAsmStreamer does not. As a result the
textual output may fail where the equivalent object generation would
pass. This can most easily be resolved by folding the MCAsmStreamer
and MCObjectStreamer together which is planned for in a separate
patch.
Currently, this feature is only enabled for assembly input, keeping IR
compilation consistent between assembly and object generation.
Reviewers: echristo, rnk, probinson, espindola, peter.smith
Reviewed By: peter.smith
Subscribers: eraman, peter.smith, arichardson, jyknight, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D45164
llvm-svn: 331218
2018-04-30 21:22:40 +02:00
|
|
|
// Do not use assembler-level information for parsing inline assembly.
|
|
|
|
OutStreamer->setUseAssemblerInfoForParsing(false);
|
|
|
|
|
2015-02-21 10:09:15 +01:00
|
|
|
// We create a new MCInstrInfo here since we might be at the module level
|
2015-02-20 00:52:35 +01:00
|
|
|
// and not have a MachineFunction to initialize the TargetInstrInfo from and
|
2015-02-21 10:09:15 +01:00
|
|
|
// we only need MCInstrInfo for asm parsing. We create one unconditionally
|
|
|
|
// because it's not subtarget dependent.
|
|
|
|
std::unique_ptr<MCInstrInfo> MII(TM.getTarget().createMCInstrInfo());
|
2020-11-22 06:04:12 +01:00
|
|
|
assert(MII && "Failed to create instruction info");
|
2015-02-19 22:29:51 +01:00
|
|
|
std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
|
2015-11-14 07:35:56 +01:00
|
|
|
STI, *Parser, *MII, MCOptions));
|
add .o file writing for inline asm in llc. Here's a silly
demo:
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
abc incl %eax
^
LLVM ERROR: Error parsing inline asm
Only problem seems to be that the parser finalizes OutStreamer
at the end of the first inline asm, which isn't what we want.
For example:
$ cat asm.c
int foo(int X) {
__asm__ ("incl %0" : "+r" (X));
return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
subq $8, %rsp
movl %edi, (%rsp)
movl %edi, %eax
## InlineAsm Start
incl %eax
## InlineAsm End
movl %eax, (%rsp)
movl %eax, 4(%rsp)
addq $8, %rsp
ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000 subq $0x08,%rsp
0000000000000004 movl %edi,(%rsp)
0000000000000007 movl %edi,%eax
0000000000000009 incl %eax
$
don't stop at inc!
llvm-svn: 100491
2010-04-06 01:11:24 +02:00
|
|
|
if (!TAP)
|
2010-04-08 00:58:41 +02:00
|
|
|
report_fatal_error("Inline asm not supported by this streamer because"
|
2010-04-08 12:44:28 +02:00
|
|
|
" we don't have an asm parser for this target\n");
|
2012-09-06 01:57:37 +02:00
|
|
|
Parser->setAssemblerDialect(Dialect);
|
2010-07-18 20:31:33 +02:00
|
|
|
Parser->setTargetParser(*TAP.get());
|
[MC] Separate masm integer literal lexer support from inline asm
Summary:
This renames the IsParsingMSInlineAsm member variable of AsmLexer to
LexMasmIntegers and moves it up to MCAsmLexer. This is the only behavior
controlled by that variable. I added a public setter, so that it can be
set from outside or from the llvm-mc command line. We may need to
arrange things so that users can get this behavior from clang, but
that's future work.
I also put additional hex literal lexing functionality under this flag
to fix PR32973. It appears that this hex literal parsing wasn't intended
to be enabled in non-masm-style blocks.
Now, masm integers (0b1101 and 0ABCh) work in __asm blocks from clang,
but 0b label references work when using .intel_syntax in standalone .s
files.
However, 0b label references will *not* work from __asm blocks in clang.
They will work from GCC inline asm blocks, which it sounds like is
important for Crypto++ as mentioned in PR36144.
Essentially, we only lex masm literals for inline asm blobs that use
intel syntax. If the .intel_syntax directive is used inside a gnu-style
inline asm statement, masm literals will not be lexed, which is
compatible with gas and llvm-mc standalone .s assembly.
This fixes PR36144 and PR32973.
Reviewers: Gerolf, avt77
Subscribers: eraman, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D53535
llvm-svn: 345189
2018-10-24 22:23:57 +02:00
|
|
|
// Enable lexing Masm binary and hex integer literals in intel inline
|
|
|
|
// assembly.
|
2017-04-26 11:56:59 +02:00
|
|
|
if (Dialect == InlineAsm::AD_Intel)
|
[MC] Separate masm integer literal lexer support from inline asm
Summary:
This renames the IsParsingMSInlineAsm member variable of AsmLexer to
LexMasmIntegers and moves it up to MCAsmLexer. This is the only behavior
controlled by that variable. I added a public setter, so that it can be
set from outside or from the llvm-mc command line. We may need to
arrange things so that users can get this behavior from clang, but
that's future work.
I also put additional hex literal lexing functionality under this flag
to fix PR32973. It appears that this hex literal parsing wasn't intended
to be enabled in non-masm-style blocks.
Now, masm integers (0b1101 and 0ABCh) work in __asm blocks from clang,
but 0b label references work when using .intel_syntax in standalone .s
files.
However, 0b label references will *not* work from __asm blocks in clang.
They will work from GCC inline asm blocks, which it sounds like is
important for Crypto++ as mentioned in PR36144.
Essentially, we only lex masm literals for inline asm blobs that use
intel syntax. If the .intel_syntax directive is used inside a gnu-style
inline asm statement, masm literals will not be lexed, which is
compatible with gas and llvm-mc standalone .s assembly.
This fixes PR36144 and PR32973.
Reviewers: Gerolf, avt77
Subscribers: eraman, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D53535
llvm-svn: 345189
2018-10-24 22:23:57 +02:00
|
|
|
Parser->getLexer().setLexMasmIntegers(true);
|
add .o file writing for inline asm in llc. Here's a silly
demo:
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
abc incl %eax
^
LLVM ERROR: Error parsing inline asm
Only problem seems to be that the parser finalizes OutStreamer
at the end of the first inline asm, which isn't what we want.
For example:
$ cat asm.c
int foo(int X) {
__asm__ ("incl %0" : "+r" (X));
return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
subq $8, %rsp
movl %edi, (%rsp)
movl %edi, %eax
## InlineAsm Start
incl %eax
## InlineAsm End
movl %eax, (%rsp)
movl %eax, 4(%rsp)
addq $8, %rsp
ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000 subq $0x08,%rsp
0000000000000004 movl %edi,(%rsp)
0000000000000007 movl %edi,%eax
0000000000000009 incl %eax
$
don't stop at inc!
llvm-svn: 100491
2010-04-06 01:11:24 +02:00
|
|
|
|
2015-02-19 20:52:25 +01:00
|
|
|
emitInlineAsmStart();
|
add .o file writing for inline asm in llc. Here's a silly
demo:
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
<inline asm>:1:2: error: unrecognized instruction
abc incl %eax
^
LLVM ERROR: Error parsing inline asm
Only problem seems to be that the parser finalizes OutStreamer
at the end of the first inline asm, which isn't what we want.
For example:
$ cat asm.c
int foo(int X) {
__asm__ ("incl %0" : "+r" (X));
return X;
}
$ clang asm.c -S -o - -emit-llvm | llc
...
subq $8, %rsp
movl %edi, (%rsp)
movl %edi, %eax
## InlineAsm Start
incl %eax
## InlineAsm End
movl %eax, (%rsp)
movl %eax, 4(%rsp)
addq $8, %rsp
ret
$ clang asm.c -S -o - -emit-llvm | llc -filetype=obj -o t.o
$ otool -tv t.o
t.o:
(__TEXT,__text) section
_foo:
0000000000000000 subq $0x08,%rsp
0000000000000004 movl %edi,(%rsp)
0000000000000007 movl %edi,%eax
0000000000000009 incl %eax
$
don't stop at inc!
llvm-svn: 100491
2010-04-06 01:11:24 +02:00
|
|
|
// Don't implicitly switch to the text section before the asm.
|
2021-02-23 18:47:15 +01:00
|
|
|
(void)Parser->Run(/*NoInitialTextSection*/ true,
|
|
|
|
/*NoFinalize*/ true);
|
2015-11-14 07:35:56 +01:00
|
|
|
emitInlineAsmEnd(STI, &TAP->getSTI());
|
2010-04-04 20:34:07 +02:00
|
|
|
}
|
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
[AsmPrinter] refactor to remove remove AsmVariant. NFC
Summary:
The InlineAsm::AsmDialect is only required for X86; no architecture
makes use of it and as such it gets passed around between arch-specific
and general code while being unused for all architectures but X86.
Since the AsmDialect is queried from a MachineInstr, which we also pass
around, remove the additional AsmDialect parameter and query for it deep
in the X86AsmPrinter only when needed/as late as possible.
This refactor should help later planned refactors to AsmPrinter, as this
difference in the X86AsmPrinter makes it harder to make AsmPrinter more
generic.
Reviewers: craig.topper
Subscribers: jholewinski, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, eraman, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, llvm-commits, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60488
llvm-svn: 358101
2019-04-10 18:38:43 +02:00
|
|
|
MachineModuleInfo *MMI, AsmPrinter *AP,
|
[clang] Use i64 for the !srcloc metadata on asm IR nodes.
This is part of a patch series working towards the ability to make
SourceLocation into a 64-bit type to handle larger translation units.
!srcloc is generated in clang codegen, and pulled back out by llvm
functions like AsmPrinter::emitInlineAsm that need to report errors in
the inline asm. From there it goes to LLVMContext::emitError, is
stored in DiagnosticInfoInlineAsm, and ends up back in clang, at
BackendConsumer::InlineAsmDiagHandler(), which reconstitutes a true
clang::SourceLocation from the integer cookie.
Throughout this code path, it's now 64-bit rather than 32, which means
that if SourceLocation is expanded to a 64-bit type, this error report
won't lose half of the data.
The compiler will tolerate both of i32 and i64 !srcloc metadata in
input IR without faulting. Test added in llvm/MC. (The semantic
accuracy of the metadata is another matter, but I don't know of any
situation where that matters: if you're reading an IR file written by
a previous run of clang, you don't have the SourceManager that can
relate those source locations back to the original source files.)
Original version of the patch by Mikhail Maltsev.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D105491
2021-07-22 11:08:06 +02:00
|
|
|
uint64_t LocCookie, raw_ostream &OS) {
|
2012-09-11 21:09:56 +02:00
|
|
|
// Switch to the inline assembly variant.
|
|
|
|
OS << "\t.intel_syntax\n\t";
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
2010-04-04 20:34:07 +02:00
|
|
|
unsigned NumOperands = MI->getNumOperands();
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
while (*LastEmitted) {
|
|
|
|
switch (*LastEmitted) {
|
|
|
|
default: {
|
|
|
|
// Not a special case, emit the string section literally.
|
|
|
|
const char *LiteralEnd = LastEmitted+1;
|
|
|
|
while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
|
|
|
|
*LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
|
|
|
|
++LiteralEnd;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
OS.write(LastEmitted, LiteralEnd-LastEmitted);
|
|
|
|
LastEmitted = LiteralEnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\n':
|
|
|
|
++LastEmitted; // Consume newline character.
|
|
|
|
OS << '\n'; // Indent code with newline.
|
|
|
|
break;
|
|
|
|
case '$': {
|
|
|
|
++LastEmitted; // Consume '$' character.
|
|
|
|
bool Done = true;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
// Handle escapes.
|
|
|
|
switch (*LastEmitted) {
|
|
|
|
default: Done = false; break;
|
|
|
|
case '$':
|
|
|
|
++LastEmitted; // Consume second '$' character.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Done) break;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2019-12-22 06:09:37 +01:00
|
|
|
bool HasCurlyBraces = false;
|
|
|
|
if (*LastEmitted == '{') { // ${variable}
|
|
|
|
++LastEmitted; // Consume '{' character.
|
|
|
|
HasCurlyBraces = true;
|
|
|
|
}
|
|
|
|
|
2016-11-29 01:29:27 +01:00
|
|
|
// If we have ${:foo}, then this is not a real operand reference, it is a
|
|
|
|
// "magic" string reference, just like in .td files. Arrange to call
|
|
|
|
// PrintSpecial.
|
2019-12-22 06:09:37 +01:00
|
|
|
if (HasCurlyBraces && LastEmitted[0] == ':') {
|
|
|
|
++LastEmitted;
|
2016-11-29 01:29:27 +01:00
|
|
|
const char *StrStart = LastEmitted;
|
|
|
|
const char *StrEnd = strchr(StrStart, '}');
|
|
|
|
if (!StrEnd)
|
|
|
|
report_fatal_error("Unterminated ${:foo} operand in inline asm"
|
|
|
|
" string: '" + Twine(AsmStr) + "'");
|
|
|
|
|
|
|
|
std::string Val(StrStart, StrEnd);
|
|
|
|
AP->PrintSpecial(MI, OS, Val.c_str());
|
|
|
|
LastEmitted = StrEnd+1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
const char *IDStart = LastEmitted;
|
|
|
|
const char *IDEnd = IDStart;
|
2021-01-22 04:59:50 +01:00
|
|
|
while (isDigit(*IDEnd))
|
|
|
|
++IDEnd;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
unsigned Val;
|
|
|
|
if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
|
|
|
|
report_fatal_error("Bad $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
|
|
|
LastEmitted = IDEnd;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
if (Val >= NumOperands-1)
|
|
|
|
report_fatal_error("Invalid $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2019-12-22 06:09:37 +01:00
|
|
|
char Modifier[2] = { 0, 0 };
|
|
|
|
|
|
|
|
if (HasCurlyBraces) {
|
|
|
|
// If we have curly braces, check for a modifier character. This
|
|
|
|
// supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
|
|
|
|
if (*LastEmitted == ':') {
|
|
|
|
++LastEmitted; // Consume ':' character.
|
|
|
|
if (*LastEmitted == 0)
|
|
|
|
report_fatal_error("Bad ${:} expression in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
|
|
|
|
|
|
|
Modifier[0] = *LastEmitted;
|
|
|
|
++LastEmitted; // Consume modifier character.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*LastEmitted != '}')
|
|
|
|
report_fatal_error("Bad ${} expression in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
|
|
|
++LastEmitted; // Consume '}' character.
|
|
|
|
}
|
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
// Okay, we finally have a value number. Ask the target to print this
|
|
|
|
// operand!
|
|
|
|
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
bool Error = false;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
// Scan to find the machine operand number for the operand.
|
|
|
|
for (; Val; --Val) {
|
|
|
|
if (OpNo >= MI->getNumOperands()) break;
|
|
|
|
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
|
|
|
OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
|
|
|
|
}
|
2012-09-10 23:36:05 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
// We may have a location metadata attached to the end of the
|
|
|
|
// instruction, and at no point should see metadata at any
|
|
|
|
// other point while processing. It's an error if so.
|
|
|
|
if (OpNo >= MI->getNumOperands() ||
|
|
|
|
MI->getOperand(OpNo).isMetadata()) {
|
|
|
|
Error = true;
|
|
|
|
} else {
|
|
|
|
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
|
|
|
++OpNo; // Skip over the ID number.
|
2013-06-25 01:20:02 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
if (InlineAsm::isMemKind(OpFlags)) {
|
2019-12-22 06:09:37 +01:00
|
|
|
Error = AP->PrintAsmMemoryOperand(
|
|
|
|
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
|
2012-09-11 21:09:56 +02:00
|
|
|
} else {
|
2019-12-22 06:09:37 +01:00
|
|
|
Error = AP->PrintAsmOperand(MI, OpNo,
|
|
|
|
Modifier[0] ? Modifier : nullptr, OS);
|
2012-09-11 21:09:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Error) {
|
2014-06-27 00:52:05 +02:00
|
|
|
std::string msg;
|
|
|
|
raw_string_ostream Msg(msg);
|
2012-09-11 21:09:56 +02:00
|
|
|
Msg << "invalid operand in inline asm: '" << AsmStr << "'";
|
|
|
|
MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-10 23:36:05 +02:00
|
|
|
}
|
2012-09-11 21:09:56 +02:00
|
|
|
OS << "\n\t.att_syntax\n" << (char)0; // null terminate string.
|
|
|
|
}
|
2012-09-10 23:36:05 +02:00
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
[AsmParser][SystemZ][z/OS] Introducing HLASM Parser support to AsmParser - Part 1
- This patch (is one in a series of patches) which introduces HLASM Parser support (for the first parameter of inline asm statements) to LLVM ([[ https://lists.llvm.org/pipermail/llvm-dev/2021-January/147686.html | main RFC here ]])
- This patch in particular introduces HLASM Parser support for Z machine instructions.
- The approach taken here was to subclass `AsmParser`, and make various functions and variables as "protected" wherever appropriate.
- The `HLASMAsmParser` class overrides the `parseStatement` function. Two new private functions `parseAsHLASMLabel` and `parseAsMachineInstruction` are introduced as well.
The general syntax is laid out as follows (more information available in [[ https://www.ibm.com/support/knowledgecenter/SSENW6_1.6.0/com.ibm.hlasm.v1r6.asm/asmr1023.pdf | HLASM V1R6 Language Reference Manual ]] - Chapter 2 - Instruction Statement Format):
```
<TokA><spaces.*><TokB><spaces.*><TokC><spaces.*><TokD>
```
1. TokA is referred to as the Name Entry. This token is optional
2. TokB is referred to as the Operation Entry. This token is mandatory.
3. TokC is referred to as the Operand Entry. This token is mandatory
4. TokD is referred to as the Remarks Entry. This token is optional
- If TokA is provided, then we either parse TokA as a possible comment or as a label (Name Entry), Tok B as the Operation Entry and so on.
- If TokA is not provided (i.e. we have one or more spaces and then the first token), then we will parse the first token (i.e TokB) as a possible Z machine instruction, TokC as the operands to the Z machine instruction and TokD as a possible Remark field
- TokC (Operand Entry), no spaces are allowed between OperandEntries. If a space occurs it is classified as an error.
- TokD if provided is taken as is, and emitted as a comment.
The following additional approach was examined, but not taken:
- Adding custom private only functions to base AsmParser class, and only invoking them for z/OS. While this would eliminate the need for another child class, these private functions would be of non-use to every other target. Similarly, adding any pure virtual functions to the base MCAsmParser class and overriding them in AsmParser would also have the same disadvantage.
Testing:
- This patch doesn't have tests added with it, for the sole reason that MCStreamer Support and Object File support hasn't been added for the z/OS target (yet). Hence, it's not possible generate code outright for the z/OS target. They are in the process of being committed / process of being worked on.
- Any comments / feedback on how to combat this "lack of testing" due to other missing required features is appreciated.
Reviewed By: Kai, uweigand
Differential Revision: https://reviews.llvm.org/D98276
2021-05-19 17:05:00 +02:00
|
|
|
MachineModuleInfo *MMI, const MCAsmInfo *MAI,
|
[clang] Use i64 for the !srcloc metadata on asm IR nodes.
This is part of a patch series working towards the ability to make
SourceLocation into a 64-bit type to handle larger translation units.
!srcloc is generated in clang codegen, and pulled back out by llvm
functions like AsmPrinter::emitInlineAsm that need to report errors in
the inline asm. From there it goes to LLVMContext::emitError, is
stored in DiagnosticInfoInlineAsm, and ends up back in clang, at
BackendConsumer::InlineAsmDiagHandler(), which reconstitutes a true
clang::SourceLocation from the integer cookie.
Throughout this code path, it's now 64-bit rather than 32, which means
that if SourceLocation is expanded to a 64-bit type, this error report
won't lose half of the data.
The compiler will tolerate both of i32 and i64 !srcloc metadata in
input IR without faulting. Test added in llvm/MC. (The semantic
accuracy of the metadata is another matter, but I don't know of any
situation where that matters: if you're reading an IR file written by
a previous run of clang, you don't have the SourceManager that can
relate those source locations back to the original source files.)
Original version of the patch by Mikhail Maltsev.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D105491
2021-07-22 11:08:06 +02:00
|
|
|
AsmPrinter *AP, uint64_t LocCookie,
|
[AsmPrinter] refactor to remove remove AsmVariant. NFC
Summary:
The InlineAsm::AsmDialect is only required for X86; no architecture
makes use of it and as such it gets passed around between arch-specific
and general code while being unused for all architectures but X86.
Since the AsmDialect is queried from a MachineInstr, which we also pass
around, remove the additional AsmDialect parameter and query for it deep
in the X86AsmPrinter only when needed/as late as possible.
This refactor should help later planned refactors to AsmPrinter, as this
difference in the X86AsmPrinter makes it harder to make AsmPrinter more
generic.
Reviewers: craig.topper
Subscribers: jholewinski, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, eraman, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, llvm-commits, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60488
llvm-svn: 358101
2019-04-10 18:38:43 +02:00
|
|
|
raw_ostream &OS) {
|
2010-04-04 20:34:07 +02:00
|
|
|
int CurVariant = -1; // The number of the {.|.|.} region we are in.
|
|
|
|
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
2012-09-11 21:09:56 +02:00
|
|
|
unsigned NumOperands = MI->getNumOperands();
|
[AsmParser][SystemZ][z/OS] Introducing HLASM Parser support to AsmParser - Part 1
- This patch (is one in a series of patches) which introduces HLASM Parser support (for the first parameter of inline asm statements) to LLVM ([[ https://lists.llvm.org/pipermail/llvm-dev/2021-January/147686.html | main RFC here ]])
- This patch in particular introduces HLASM Parser support for Z machine instructions.
- The approach taken here was to subclass `AsmParser`, and make various functions and variables as "protected" wherever appropriate.
- The `HLASMAsmParser` class overrides the `parseStatement` function. Two new private functions `parseAsHLASMLabel` and `parseAsMachineInstruction` are introduced as well.
The general syntax is laid out as follows (more information available in [[ https://www.ibm.com/support/knowledgecenter/SSENW6_1.6.0/com.ibm.hlasm.v1r6.asm/asmr1023.pdf | HLASM V1R6 Language Reference Manual ]] - Chapter 2 - Instruction Statement Format):
```
<TokA><spaces.*><TokB><spaces.*><TokC><spaces.*><TokD>
```
1. TokA is referred to as the Name Entry. This token is optional
2. TokB is referred to as the Operation Entry. This token is mandatory.
3. TokC is referred to as the Operand Entry. This token is mandatory
4. TokD is referred to as the Remarks Entry. This token is optional
- If TokA is provided, then we either parse TokA as a possible comment or as a label (Name Entry), Tok B as the Operation Entry and so on.
- If TokA is not provided (i.e. we have one or more spaces and then the first token), then we will parse the first token (i.e TokB) as a possible Z machine instruction, TokC as the operands to the Z machine instruction and TokD as a possible Remark field
- TokC (Operand Entry), no spaces are allowed between OperandEntries. If a space occurs it is classified as an error.
- TokD if provided is taken as is, and emitted as a comment.
The following additional approach was examined, but not taken:
- Adding custom private only functions to base AsmParser class, and only invoking them for z/OS. While this would eliminate the need for another child class, these private functions would be of non-use to every other target. Similarly, adding any pure virtual functions to the base MCAsmParser class and overriding them in AsmParser would also have the same disadvantage.
Testing:
- This patch doesn't have tests added with it, for the sole reason that MCStreamer Support and Object File support hasn't been added for the z/OS target (yet). Hence, it's not possible generate code outright for the z/OS target. They are in the process of being committed / process of being worked on.
- Any comments / feedback on how to combat this "lack of testing" due to other missing required features is appreciated.
Reviewed By: Kai, uweigand
Differential Revision: https://reviews.llvm.org/D98276
2021-05-19 17:05:00 +02:00
|
|
|
int AsmPrinterVariant = MAI->getAssemblerDialect();
|
2012-09-11 21:09:56 +02:00
|
|
|
|
[AsmParser][SystemZ][z/OS] Introducing HLASM Parser support to AsmParser - Part 1
- This patch (is one in a series of patches) which introduces HLASM Parser support (for the first parameter of inline asm statements) to LLVM ([[ https://lists.llvm.org/pipermail/llvm-dev/2021-January/147686.html | main RFC here ]])
- This patch in particular introduces HLASM Parser support for Z machine instructions.
- The approach taken here was to subclass `AsmParser`, and make various functions and variables as "protected" wherever appropriate.
- The `HLASMAsmParser` class overrides the `parseStatement` function. Two new private functions `parseAsHLASMLabel` and `parseAsMachineInstruction` are introduced as well.
The general syntax is laid out as follows (more information available in [[ https://www.ibm.com/support/knowledgecenter/SSENW6_1.6.0/com.ibm.hlasm.v1r6.asm/asmr1023.pdf | HLASM V1R6 Language Reference Manual ]] - Chapter 2 - Instruction Statement Format):
```
<TokA><spaces.*><TokB><spaces.*><TokC><spaces.*><TokD>
```
1. TokA is referred to as the Name Entry. This token is optional
2. TokB is referred to as the Operation Entry. This token is mandatory.
3. TokC is referred to as the Operand Entry. This token is mandatory
4. TokD is referred to as the Remarks Entry. This token is optional
- If TokA is provided, then we either parse TokA as a possible comment or as a label (Name Entry), Tok B as the Operation Entry and so on.
- If TokA is not provided (i.e. we have one or more spaces and then the first token), then we will parse the first token (i.e TokB) as a possible Z machine instruction, TokC as the operands to the Z machine instruction and TokD as a possible Remark field
- TokC (Operand Entry), no spaces are allowed between OperandEntries. If a space occurs it is classified as an error.
- TokD if provided is taken as is, and emitted as a comment.
The following additional approach was examined, but not taken:
- Adding custom private only functions to base AsmParser class, and only invoking them for z/OS. While this would eliminate the need for another child class, these private functions would be of non-use to every other target. Similarly, adding any pure virtual functions to the base MCAsmParser class and overriding them in AsmParser would also have the same disadvantage.
Testing:
- This patch doesn't have tests added with it, for the sole reason that MCStreamer Support and Object File support hasn't been added for the z/OS target (yet). Hence, it's not possible generate code outright for the z/OS target. They are in the process of being committed / process of being worked on.
- Any comments / feedback on how to combat this "lack of testing" due to other missing required features is appreciated.
Reviewed By: Kai, uweigand
Differential Revision: https://reviews.llvm.org/D98276
2021-05-19 17:05:00 +02:00
|
|
|
if (MAI->getEmitGNUAsmStartIndentationMarker())
|
|
|
|
OS << '\t';
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
while (*LastEmitted) {
|
|
|
|
switch (*LastEmitted) {
|
|
|
|
default: {
|
|
|
|
// Not a special case, emit the string section literally.
|
|
|
|
const char *LiteralEnd = LastEmitted+1;
|
|
|
|
while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
|
|
|
|
*LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n')
|
|
|
|
++LiteralEnd;
|
|
|
|
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
|
|
|
OS.write(LastEmitted, LiteralEnd-LastEmitted);
|
|
|
|
LastEmitted = LiteralEnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\n':
|
|
|
|
++LastEmitted; // Consume newline character.
|
2010-04-06 00:42:30 +02:00
|
|
|
OS << '\n'; // Indent code with newline.
|
2010-04-04 20:34:07 +02:00
|
|
|
break;
|
|
|
|
case '$': {
|
|
|
|
++LastEmitted; // Consume '$' character.
|
|
|
|
bool Done = true;
|
|
|
|
|
|
|
|
// Handle escapes.
|
|
|
|
switch (*LastEmitted) {
|
|
|
|
default: Done = false; break;
|
|
|
|
case '$': // $$ -> $
|
|
|
|
if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
|
|
|
|
OS << '$';
|
|
|
|
++LastEmitted; // Consume second '$' character.
|
|
|
|
break;
|
|
|
|
case '(': // $( -> same as GCC's { character.
|
|
|
|
++LastEmitted; // Consume '(' character.
|
2010-04-07 07:27:36 +02:00
|
|
|
if (CurVariant != -1)
|
2010-04-08 12:44:28 +02:00
|
|
|
report_fatal_error("Nested variants found in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-04 20:34:07 +02:00
|
|
|
CurVariant = 0; // We're in the first variant now.
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
++LastEmitted; // consume '|' character.
|
|
|
|
if (CurVariant == -1)
|
|
|
|
OS << '|'; // this is gcc's behavior for | outside a variant
|
|
|
|
else
|
|
|
|
++CurVariant; // We're in the next variant.
|
|
|
|
break;
|
|
|
|
case ')': // $) -> same as GCC's } char.
|
|
|
|
++LastEmitted; // consume ')' character.
|
|
|
|
if (CurVariant == -1)
|
|
|
|
OS << '}'; // this is gcc's behavior for } outside a variant
|
2010-10-02 01:29:12 +02:00
|
|
|
else
|
2010-04-04 20:34:07 +02:00
|
|
|
CurVariant = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Done) break;
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
bool HasCurlyBraces = false;
|
|
|
|
if (*LastEmitted == '{') { // ${variable}
|
|
|
|
++LastEmitted; // Consume '{' character.
|
|
|
|
HasCurlyBraces = true;
|
|
|
|
}
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
// If we have ${:foo}, then this is not a real operand reference, it is a
|
|
|
|
// "magic" string reference, just like in .td files. Arrange to call
|
|
|
|
// PrintSpecial.
|
|
|
|
if (HasCurlyBraces && *LastEmitted == ':') {
|
|
|
|
++LastEmitted;
|
|
|
|
const char *StrStart = LastEmitted;
|
|
|
|
const char *StrEnd = strchr(StrStart, '}');
|
2014-04-24 08:44:33 +02:00
|
|
|
if (!StrEnd)
|
2010-04-08 12:44:28 +02:00
|
|
|
report_fatal_error("Unterminated ${:foo} operand in inline asm"
|
|
|
|
" string: '" + Twine(AsmStr) + "'");
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
std::string Val(StrStart, StrEnd);
|
2012-09-11 21:09:56 +02:00
|
|
|
AP->PrintSpecial(MI, OS, Val.c_str());
|
2010-04-04 20:34:07 +02:00
|
|
|
LastEmitted = StrEnd+1;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
const char *IDStart = LastEmitted;
|
2010-04-04 20:42:18 +02:00
|
|
|
const char *IDEnd = IDStart;
|
2021-01-22 04:59:50 +01:00
|
|
|
while (isDigit(*IDEnd))
|
|
|
|
++IDEnd;
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:42:18 +02:00
|
|
|
unsigned Val;
|
|
|
|
if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
|
2010-04-08 12:44:28 +02:00
|
|
|
report_fatal_error("Bad $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-04 20:34:07 +02:00
|
|
|
LastEmitted = IDEnd;
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
char Modifier[2] = { 0, 0 };
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
if (HasCurlyBraces) {
|
|
|
|
// If we have curly braces, check for a modifier character. This
|
|
|
|
// supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
|
|
|
|
if (*LastEmitted == ':') {
|
|
|
|
++LastEmitted; // Consume ':' character.
|
2010-04-06 00:42:30 +02:00
|
|
|
if (*LastEmitted == 0)
|
2010-04-08 00:58:41 +02:00
|
|
|
report_fatal_error("Bad ${:} expression in inline asm string: '" +
|
2010-04-08 12:44:28 +02:00
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
Modifier[0] = *LastEmitted;
|
|
|
|
++LastEmitted; // Consume modifier character.
|
|
|
|
}
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-06 00:42:30 +02:00
|
|
|
if (*LastEmitted != '}')
|
2010-04-08 12:44:28 +02:00
|
|
|
report_fatal_error("Bad ${} expression in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-04 20:34:07 +02:00
|
|
|
++LastEmitted; // Consume '}' character.
|
|
|
|
}
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-06 00:42:30 +02:00
|
|
|
if (Val >= NumOperands-1)
|
2010-04-08 12:44:28 +02:00
|
|
|
report_fatal_error("Invalid $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
// Okay, we finally have a value number. Ask the target to print this
|
|
|
|
// operand!
|
|
|
|
if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
|
2011-01-08 00:50:32 +01:00
|
|
|
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
|
2010-04-04 20:34:07 +02:00
|
|
|
|
|
|
|
bool Error = false;
|
|
|
|
|
|
|
|
// Scan to find the machine operand number for the operand.
|
|
|
|
for (; Val; --Val) {
|
|
|
|
if (OpNo >= MI->getNumOperands()) break;
|
|
|
|
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
|
|
|
OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1;
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:14:42 +02:00
|
|
|
// We may have a location metadata attached to the end of the
|
|
|
|
// instruction, and at no point should see metadata at any
|
|
|
|
// other point while processing. It's an error if so.
|
2012-03-22 02:33:51 +01:00
|
|
|
if (OpNo >= MI->getNumOperands() ||
|
2012-05-08 21:14:42 +02:00
|
|
|
MI->getOperand(OpNo).isMetadata()) {
|
2010-04-04 20:34:07 +02:00
|
|
|
Error = true;
|
|
|
|
} else {
|
|
|
|
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
|
|
|
++OpNo; // Skip over the ID number.
|
|
|
|
|
2019-04-18 04:39:37 +02:00
|
|
|
// FIXME: Shouldn't arch-independent output template handling go into
|
[AsmPrinter] defer %c to base class for ARM, PPC, and Hexagon. NFC
Summary:
None of these derived classes do anything that the base class cannot.
If we remove these case statements, then the base class can handle them
just fine.
Reviewers: peter.smith, echristo
Reviewed By: echristo
Subscribers: nemanjai, javed.absar, eraman, kristof.beyls, hiraditya, kbarton, jsji, llvm-commits, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60803
llvm-svn: 358603
2019-04-17 20:22:48 +02:00
|
|
|
// PrintAsmOperand?
|
2019-12-24 01:57:41 +01:00
|
|
|
// Labels are target independent.
|
|
|
|
if (MI->getOperand(OpNo).isBlockAddress()) {
|
|
|
|
const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress();
|
|
|
|
MCSymbol *Sym = AP->GetBlockAddressSymbol(BA);
|
|
|
|
Sym->print(OS, AP->MAI);
|
|
|
|
MMI->getContext().registerInlineAsmLabel(Sym);
|
|
|
|
} else if (MI->getOperand(OpNo).isMBB()) {
|
|
|
|
const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
|
|
|
|
Sym->print(OS, AP->MAI);
|
|
|
|
} else if (Modifier[0] == 'l') {
|
|
|
|
Error = true;
|
|
|
|
} else if (InlineAsm::isMemKind(OpFlags)) {
|
|
|
|
Error = AP->PrintAsmMemoryOperand(
|
|
|
|
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
|
2015-06-09 02:31:39 +02:00
|
|
|
} else {
|
2019-12-24 01:57:41 +01:00
|
|
|
Error = AP->PrintAsmOperand(MI, OpNo,
|
|
|
|
Modifier[0] ? Modifier : nullptr, OS);
|
2010-04-04 20:34:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Error) {
|
2014-06-27 00:52:05 +02:00
|
|
|
std::string msg;
|
|
|
|
raw_string_ostream Msg(msg);
|
introduce a new recoverable error handling API to LLVMContext
and use it in one place in inline asm handling stuff. Before
we'd generate this for an invalid modifier letter:
$ clang asm.c -c -o t.o
fatal error: error in backend: Invalid operand found in inline asm: 'abc incl ${0:Z}'
INLINEASM <es:abc incl ${0:Z}>, 10, %EAX<def>, 2147483657, %EAX, 14, %EFLAGS<earlyclobber,def,dead>, <!-1>
Now we generate this:
$ clang asm.c -c -o t.o
error: invalid operand in inline asm: 'incl ${0:Z}'
asm.c:3:12: note: generated from here
__asm__ ("incl %Z0" : "+r" (X));
^
1 error generated.
This is much better but still admittedly not great ("why" is the operand
invalid??), codegen should try harder with its diagnostics :)
llvm-svn: 100723
2010-04-08 01:40:44 +02:00
|
|
|
Msg << "invalid operand in inline asm: '" << AsmStr << "'";
|
|
|
|
MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
|
2010-04-04 20:34:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-11 21:09:56 +02:00
|
|
|
OS << '\n' << (char)0; // null terminate string.
|
|
|
|
}
|
|
|
|
|
2020-02-14 01:36:27 +01:00
|
|
|
/// This method formats and emits the specified machine instruction that is an
|
|
|
|
/// inline asm.
|
|
|
|
void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const {
|
2012-09-11 21:09:56 +02:00
|
|
|
assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms");
|
|
|
|
|
|
|
|
// Count the number of register definitions to find the asm string.
|
|
|
|
unsigned NumDefs = 0;
|
|
|
|
for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
|
|
|
|
++NumDefs)
|
|
|
|
assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
|
|
|
|
|
|
|
|
assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
|
|
|
|
|
|
|
|
// Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
|
|
|
|
const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
|
|
|
|
|
|
|
|
// If this asmstr is empty, just print the #APP/#NOAPP markers.
|
|
|
|
// These are useful to see where empty asm's wound up.
|
|
|
|
if (AsmStr[0] == 0) {
|
2015-04-24 21:11:51 +02:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmStart());
|
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
|
2012-09-11 21:09:56 +02:00
|
|
|
return;
|
2012-09-10 23:36:05 +02:00
|
|
|
}
|
|
|
|
|
2012-09-11 21:09:56 +02:00
|
|
|
// Emit the #APP start marker. This has to happen even if verbose-asm isn't
|
2014-01-16 17:28:37 +01:00
|
|
|
// enabled, so we use emitRawComment.
|
2015-04-24 21:11:51 +02:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmStart());
|
2012-09-11 21:09:56 +02:00
|
|
|
|
|
|
|
// Get the !srcloc metadata node if we have it, and decode the loc cookie from
|
|
|
|
// it.
|
[clang] Use i64 for the !srcloc metadata on asm IR nodes.
This is part of a patch series working towards the ability to make
SourceLocation into a 64-bit type to handle larger translation units.
!srcloc is generated in clang codegen, and pulled back out by llvm
functions like AsmPrinter::emitInlineAsm that need to report errors in
the inline asm. From there it goes to LLVMContext::emitError, is
stored in DiagnosticInfoInlineAsm, and ends up back in clang, at
BackendConsumer::InlineAsmDiagHandler(), which reconstitutes a true
clang::SourceLocation from the integer cookie.
Throughout this code path, it's now 64-bit rather than 32, which means
that if SourceLocation is expanded to a 64-bit type, this error report
won't lose half of the data.
The compiler will tolerate both of i32 and i64 !srcloc metadata in
input IR without faulting. Test added in llvm/MC. (The semantic
accuracy of the metadata is another matter, but I don't know of any
situation where that matters: if you're reading an IR file written by
a previous run of clang, you don't have the SourceManager that can
relate those source locations back to the original source files.)
Original version of the patch by Mikhail Maltsev.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D105491
2021-07-22 11:08:06 +02:00
|
|
|
uint64_t LocCookie = 0;
|
2014-04-24 08:44:33 +02:00
|
|
|
const MDNode *LocMD = nullptr;
|
2012-09-11 21:09:56 +02:00
|
|
|
for (unsigned i = MI->getNumOperands(); i != 0; --i) {
|
|
|
|
if (MI->getOperand(i-1).isMetadata() &&
|
|
|
|
(LocMD = MI->getOperand(i-1).getMetadata()) &&
|
|
|
|
LocMD->getNumOperands() != 0) {
|
IR: Split Metadata from Value
Split `Metadata` away from the `Value` class hierarchy, as part of
PR21532. Assembly and bitcode changes are in the wings, but this is the
bulk of the change for the IR C++ API.
I have a follow-up patch prepared for `clang`. If this breaks other
sub-projects, I apologize in advance :(. Help me compile it on Darwin
I'll try to fix it. FWIW, the errors should be easy to fix, so it may
be simpler to just fix it yourself.
This breaks the build for all metadata-related code that's out-of-tree.
Rest assured the transition is mechanical and the compiler should catch
almost all of the problems.
Here's a quick guide for updating your code:
- `Metadata` is the root of a class hierarchy with three main classes:
`MDNode`, `MDString`, and `ValueAsMetadata`. It is distinct from
the `Value` class hierarchy. It is typeless -- i.e., instances do
*not* have a `Type`.
- `MDNode`'s operands are all `Metadata *` (instead of `Value *`).
- `TrackingVH<MDNode>` and `WeakVH` referring to metadata can be
replaced with `TrackingMDNodeRef` and `TrackingMDRef`, respectively.
If you're referring solely to resolved `MDNode`s -- post graph
construction -- just use `MDNode*`.
- `MDNode` (and the rest of `Metadata`) have only limited support for
`replaceAllUsesWith()`.
As long as an `MDNode` is pointing at a forward declaration -- the
result of `MDNode::getTemporary()` -- it maintains a side map of its
uses and can RAUW itself. Once the forward declarations are fully
resolved RAUW support is dropped on the ground. This means that
uniquing collisions on changing operands cause nodes to become
"distinct". (This already happened fairly commonly, whenever an
operand went to null.)
If you're constructing complex (non self-reference) `MDNode` cycles,
you need to call `MDNode::resolveCycles()` on each node (or on a
top-level node that somehow references all of the nodes). Also,
don't do that. Metadata cycles (and the RAUW machinery needed to
construct them) are expensive.
- An `MDNode` can only refer to a `Constant` through a bridge called
`ConstantAsMetadata` (one of the subclasses of `ValueAsMetadata`).
As a side effect, accessing an operand of an `MDNode` that is known
to be, e.g., `ConstantInt`, takes three steps: first, cast from
`Metadata` to `ConstantAsMetadata`; second, extract the `Constant`;
third, cast down to `ConstantInt`.
The eventual goal is to introduce `MDInt`/`MDFloat`/etc. and have
metadata schema owners transition away from using `Constant`s when
the type isn't important (and they don't care about referring to
`GlobalValue`s).
In the meantime, I've added transitional API to the `mdconst`
namespace that matches semantics with the old code, in order to
avoid adding the error-prone three-step equivalent to every call
site. If your old code was:
MDNode *N = foo();
bar(isa <ConstantInt>(N->getOperand(0)));
baz(cast <ConstantInt>(N->getOperand(1)));
bak(cast_or_null <ConstantInt>(N->getOperand(2)));
bat(dyn_cast <ConstantInt>(N->getOperand(3)));
bay(dyn_cast_or_null<ConstantInt>(N->getOperand(4)));
you can trivially match its semantics with:
MDNode *N = foo();
bar(mdconst::hasa <ConstantInt>(N->getOperand(0)));
baz(mdconst::extract <ConstantInt>(N->getOperand(1)));
bak(mdconst::extract_or_null <ConstantInt>(N->getOperand(2)));
bat(mdconst::dyn_extract <ConstantInt>(N->getOperand(3)));
bay(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(4)));
and when you transition your metadata schema to `MDInt`:
MDNode *N = foo();
bar(isa <MDInt>(N->getOperand(0)));
baz(cast <MDInt>(N->getOperand(1)));
bak(cast_or_null <MDInt>(N->getOperand(2)));
bat(dyn_cast <MDInt>(N->getOperand(3)));
bay(dyn_cast_or_null<MDInt>(N->getOperand(4)));
- A `CallInst` -- specifically, intrinsic instructions -- can refer to
metadata through a bridge called `MetadataAsValue`. This is a
subclass of `Value` where `getType()->isMetadataTy()`.
`MetadataAsValue` is the *only* class that can legally refer to a
`LocalAsMetadata`, which is a bridged form of non-`Constant` values
like `Argument` and `Instruction`. It can also refer to any other
`Metadata` subclass.
(I'll break all your testcases in a follow-up commit, when I propagate
this change to assembly.)
llvm-svn: 223802
2014-12-09 19:38:53 +01:00
|
|
|
if (const ConstantInt *CI =
|
|
|
|
mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
|
2012-09-11 21:09:56 +02:00
|
|
|
LocCookie = CI->getZExtValue();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the inline asm to a temporary string so we can emit it through
|
|
|
|
// EmitInlineAsm.
|
2014-06-27 00:52:05 +02:00
|
|
|
SmallString<256> StringData;
|
|
|
|
raw_svector_ostream OS(StringData);
|
2012-09-11 21:09:56 +02:00
|
|
|
|
|
|
|
AsmPrinter *AP = const_cast<AsmPrinter*>(this);
|
[AsmPrinter] refactor to remove remove AsmVariant. NFC
Summary:
The InlineAsm::AsmDialect is only required for X86; no architecture
makes use of it and as such it gets passed around between arch-specific
and general code while being unused for all architectures but X86.
Since the AsmDialect is queried from a MachineInstr, which we also pass
around, remove the additional AsmDialect parameter and query for it deep
in the X86AsmPrinter only when needed/as late as possible.
This refactor should help later planned refactors to AsmPrinter, as this
difference in the X86AsmPrinter makes it harder to make AsmPrinter more
generic.
Reviewers: craig.topper
Subscribers: jholewinski, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, eraman, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, llvm-commits, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60488
llvm-svn: 358101
2019-04-10 18:38:43 +02:00
|
|
|
if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)
|
[AsmParser][SystemZ][z/OS] Introducing HLASM Parser support to AsmParser - Part 1
- This patch (is one in a series of patches) which introduces HLASM Parser support (for the first parameter of inline asm statements) to LLVM ([[ https://lists.llvm.org/pipermail/llvm-dev/2021-January/147686.html | main RFC here ]])
- This patch in particular introduces HLASM Parser support for Z machine instructions.
- The approach taken here was to subclass `AsmParser`, and make various functions and variables as "protected" wherever appropriate.
- The `HLASMAsmParser` class overrides the `parseStatement` function. Two new private functions `parseAsHLASMLabel` and `parseAsMachineInstruction` are introduced as well.
The general syntax is laid out as follows (more information available in [[ https://www.ibm.com/support/knowledgecenter/SSENW6_1.6.0/com.ibm.hlasm.v1r6.asm/asmr1023.pdf | HLASM V1R6 Language Reference Manual ]] - Chapter 2 - Instruction Statement Format):
```
<TokA><spaces.*><TokB><spaces.*><TokC><spaces.*><TokD>
```
1. TokA is referred to as the Name Entry. This token is optional
2. TokB is referred to as the Operation Entry. This token is mandatory.
3. TokC is referred to as the Operand Entry. This token is mandatory
4. TokD is referred to as the Remarks Entry. This token is optional
- If TokA is provided, then we either parse TokA as a possible comment or as a label (Name Entry), Tok B as the Operation Entry and so on.
- If TokA is not provided (i.e. we have one or more spaces and then the first token), then we will parse the first token (i.e TokB) as a possible Z machine instruction, TokC as the operands to the Z machine instruction and TokD as a possible Remark field
- TokC (Operand Entry), no spaces are allowed between OperandEntries. If a space occurs it is classified as an error.
- TokD if provided is taken as is, and emitted as a comment.
The following additional approach was examined, but not taken:
- Adding custom private only functions to base AsmParser class, and only invoking them for z/OS. While this would eliminate the need for another child class, these private functions would be of non-use to every other target. Similarly, adding any pure virtual functions to the base MCAsmParser class and overriding them in AsmParser would also have the same disadvantage.
Testing:
- This patch doesn't have tests added with it, for the sole reason that MCStreamer Support and Object File support hasn't been added for the z/OS target (yet). Hence, it's not possible generate code outright for the z/OS target. They are in the process of being committed / process of being worked on.
- Any comments / feedback on how to combat this "lack of testing" due to other missing required features is appreciated.
Reviewed By: Kai, uweigand
Differential Revision: https://reviews.llvm.org/D98276
2021-05-19 17:05:00 +02:00
|
|
|
EmitGCCInlineAsmStr(AsmStr, MI, MMI, MAI, AP, LocCookie, OS);
|
2012-09-11 21:09:56 +02:00
|
|
|
else
|
[AsmPrinter] refactor to remove remove AsmVariant. NFC
Summary:
The InlineAsm::AsmDialect is only required for X86; no architecture
makes use of it and as such it gets passed around between arch-specific
and general code while being unused for all architectures but X86.
Since the AsmDialect is queried from a MachineInstr, which we also pass
around, remove the additional AsmDialect parameter and query for it deep
in the X86AsmPrinter only when needed/as late as possible.
This refactor should help later planned refactors to AsmPrinter, as this
difference in the X86AsmPrinter makes it harder to make AsmPrinter more
generic.
Reviewers: craig.topper
Subscribers: jholewinski, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, eraman, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, llvm-commits, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60488
llvm-svn: 358101
2019-04-10 18:38:43 +02:00
|
|
|
EmitMSInlineAsmStr(AsmStr, MI, MMI, AP, LocCookie, OS);
|
2012-09-11 21:09:56 +02:00
|
|
|
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
// Emit warnings if we use reserved registers on the clobber list, as
|
2020-09-07 17:16:52 +02:00
|
|
|
// that might lead to undefined behaviour.
|
|
|
|
SmallVector<Register, 8> RestrRegs;
|
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
// Start with the first operand descriptor, and iterate over them.
|
|
|
|
for (unsigned I = InlineAsm::MIOp_FirstOperand, NumOps = MI->getNumOperands();
|
|
|
|
I < NumOps; ++I) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(I);
|
2020-09-07 17:16:52 +02:00
|
|
|
if (!MO.isImm())
|
|
|
|
continue;
|
|
|
|
unsigned Flags = MO.getImm();
|
|
|
|
if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber) {
|
|
|
|
Register Reg = MI->getOperand(I + 1).getReg();
|
|
|
|
if (!TRI->isAsmClobberable(*MF, Reg))
|
|
|
|
RestrRegs.push_back(Reg);
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
}
|
2020-09-07 17:16:52 +02:00
|
|
|
// Skip to one before the next operand descriptor, if it exists.
|
|
|
|
I += InlineAsm::getNumOperandRegisters(Flags);
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!RestrRegs.empty()) {
|
|
|
|
std::string Msg = "inline asm clobber list contains reserved registers: ";
|
2021-02-03 07:52:48 +01:00
|
|
|
ListSeparator LS;
|
|
|
|
for (const Register &RR : RestrRegs) {
|
|
|
|
Msg += LS;
|
|
|
|
Msg += TRI->getName(RR);
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
}
|
2020-09-07 17:16:52 +02:00
|
|
|
const char *Note =
|
|
|
|
"Reserved registers on the clobber list may not be "
|
|
|
|
"preserved across the asm statement, and clobbering them may "
|
|
|
|
"lead to undefined behaviour.";
|
2021-05-11 16:33:53 +02:00
|
|
|
MMI->getModule()->getContext().diagnose(DiagnosticInfoInlineAsm(
|
|
|
|
LocCookie, Msg.c_str(), DiagnosticSeverity::DS_Warning));
|
|
|
|
MMI->getModule()->getContext().diagnose(
|
|
|
|
DiagnosticInfoInlineAsm(LocCookie, Note, DiagnosticSeverity::DS_Note));
|
[CodeGen] emit inline asm clobber list warnings for reserved (cont)
Summary:
This is a continuation of https://reviews.llvm.org/D49727
Below the original text, current changes in the comments:
Currently, in line with GCC, when specifying reserved registers like sp or pc on an inline asm() clobber list, we don't always preserve the original value across the statement. And in general, overwriting reserved registers can have surprising results.
For example:
extern int bar(int[]);
int foo(int i) {
int a[i]; // VLA
asm volatile(
"mov r7, #1"
:
:
: "r7"
);
return 1 + bar(a);
}
Compiled for thumb, this gives:
$ clang --target=arm-arm-none-eabi -march=armv7a -c test.c -o - -S -O1 -mthumb
...
foo:
.fnstart
@ %bb.0: @ %entry
.save {r4, r5, r6, r7, lr}
push {r4, r5, r6, r7, lr}
.setfp r7, sp, #12
add r7, sp, #12
.pad #4
sub sp, #4
movs r1, #7
add.w r0, r1, r0, lsl #2
bic r0, r0, #7
sub.w r0, sp, r0
mov sp, r0
@APP
mov.w r7, #1
@NO_APP
bl bar
adds r0, #1
sub.w r4, r7, #12
mov sp, r4
pop {r4, r5, r6, r7, pc}
...
r7 is used as the frame pointer for thumb targets, and this function needs to restore the SP from the FP because of the variable-length stack allocation a. r7 is clobbered by the inline assembly (and r7 is included in the clobber list), but LLVM does not preserve the value of the frame pointer across the assembly block.
This type of behavior is similar to GCC's and has been discussed on the bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11807 . No consensus seemed to have been reached on the way forward. Clang behavior has briefly been discussed on the CFE mailing (starting here: http://lists.llvm.org/pipermail/cfe-dev/2018-July/058392.html). I've opted for following Eli Friedman's advice to print warnings when there are reserved registers on the clobber list so as not to diverge from GCC behavior for now.
The patch uses MachineRegisterInfo's target-specific knowledge of reserved registers, just before we convert the inline asm string in the AsmPrinter.
If we find a reserved register, we print a warning:
repro.c:6:7: warning: inline asm clobber list contains reserved registers: R7 [-Winline-asm]
"mov r7, #1"
^
Reviewers: efriedma, olista01, javed.absar
Reviewed By: efriedma
Subscribers: eraman, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D51165
llvm-svn: 341062
2018-08-30 14:52:35 +02:00
|
|
|
}
|
|
|
|
|
2020-02-14 01:36:27 +01:00
|
|
|
emitInlineAsm(OS.str(), getSubtargetInfo(), TM.Options.MCOptions, LocMD,
|
2015-05-15 02:20:44 +02:00
|
|
|
MI->getInlineAsmDialect());
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
// Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't
|
2014-01-16 17:28:37 +01:00
|
|
|
// enabled, so we use emitRawComment.
|
2015-04-24 21:11:51 +02:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
|
2010-04-04 20:34:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintSpecial - Print information related to the specified machine instr
|
|
|
|
/// that is independent of the operand, and may be independent of the instr
|
|
|
|
/// itself. This can be useful for portably encoding the comment character
|
|
|
|
/// or other bits of target-specific knowledge into the asmstrings. The
|
|
|
|
/// syntax used is ${:comment}. Targets can override this to add support
|
|
|
|
/// for their own strange codes.
|
|
|
|
void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
|
|
|
|
const char *Code) const {
|
|
|
|
if (!strcmp(Code, "private")) {
|
2015-07-16 08:11:10 +02:00
|
|
|
const DataLayout &DL = MF->getDataLayout();
|
|
|
|
OS << DL.getPrivateGlobalPrefix();
|
2010-04-04 20:34:07 +02:00
|
|
|
} else if (!strcmp(Code, "comment")) {
|
|
|
|
OS << MAI->getCommentString();
|
|
|
|
} else if (!strcmp(Code, "uid")) {
|
|
|
|
// Comparing the address of MI isn't sufficient, because machineinstrs may
|
|
|
|
// be allocated to the same address across functions.
|
2010-10-02 01:29:12 +02:00
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
// If this is a new LastFn instruction, bump the counter.
|
|
|
|
if (LastMI != MI || LastFn != getFunctionNumber()) {
|
|
|
|
++Counter;
|
|
|
|
LastMI = MI;
|
|
|
|
LastFn = getFunctionNumber();
|
|
|
|
}
|
|
|
|
OS << Counter;
|
|
|
|
} else {
|
2014-06-27 00:52:05 +02:00
|
|
|
std::string msg;
|
|
|
|
raw_string_ostream Msg(msg);
|
2010-04-04 20:34:07 +02:00
|
|
|
Msg << "Unknown special formatter '" << Code
|
|
|
|
<< "' for machine instr: " << *MI;
|
2010-04-08 00:58:41 +02:00
|
|
|
report_fatal_error(Msg.str());
|
2010-10-02 01:29:12 +02:00
|
|
|
}
|
2010-04-04 20:34:07 +02:00
|
|
|
}
|
|
|
|
|
[AsmPrinter] refactor to support %c w/ GlobalAddress'
Summary:
Targets like ARM, MSP430, PPC, and SystemZ have complex behavior when
printing the address of a MachineOperand::MO_GlobalAddress. Move that
handling into a new overriden method in each base class. A virtual
method was added to the base class for handling the generic case.
Refactors a few subclasses to support the target independent %a, %c, and
%n.
The patch also contains small cleanups for AVRAsmPrinter and
SystemZAsmPrinter.
It seems that NVPTXTargetLowering is possibly missing some logic to
transform GlobalAddressSDNodes for
TargetLowering::LowerAsmOperandForConstraint to handle with "i" extended
inline assembly asm constraints.
Fixes:
- https://bugs.llvm.org/show_bug.cgi?id=41402
- https://github.com/ClangBuiltLinux/linux/issues/449
Reviewers: echristo, void
Reviewed By: void
Subscribers: void, craig.topper, jholewinski, dschuff, jyknight, dylanmckay, sdardis, nemanjai, javed.absar, sbc100, jgravelle-google, eraman, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, jrtc27, atanasyan, jsji, llvm-commits, kees, tpimh, nathanchance, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60887
llvm-svn: 359337
2019-04-26 20:45:04 +02:00
|
|
|
void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) {
|
|
|
|
assert(MO.isGlobal() && "caller should check MO.isGlobal");
|
2021-05-07 18:44:26 +02:00
|
|
|
getSymbolPreferLocal(*MO.getGlobal())->print(OS, MAI);
|
[AsmPrinter] refactor to support %c w/ GlobalAddress'
Summary:
Targets like ARM, MSP430, PPC, and SystemZ have complex behavior when
printing the address of a MachineOperand::MO_GlobalAddress. Move that
handling into a new overriden method in each base class. A virtual
method was added to the base class for handling the generic case.
Refactors a few subclasses to support the target independent %a, %c, and
%n.
The patch also contains small cleanups for AVRAsmPrinter and
SystemZAsmPrinter.
It seems that NVPTXTargetLowering is possibly missing some logic to
transform GlobalAddressSDNodes for
TargetLowering::LowerAsmOperandForConstraint to handle with "i" extended
inline assembly asm constraints.
Fixes:
- https://bugs.llvm.org/show_bug.cgi?id=41402
- https://github.com/ClangBuiltLinux/linux/issues/449
Reviewers: echristo, void
Reviewed By: void
Subscribers: void, craig.topper, jholewinski, dschuff, jyknight, dylanmckay, sdardis, nemanjai, javed.absar, sbc100, jgravelle-google, eraman, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, jrtc27, atanasyan, jsji, llvm-commits, kees, tpimh, nathanchance, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60887
llvm-svn: 359337
2019-04-26 20:45:04 +02:00
|
|
|
printOffset(MO.getOffset(), OS);
|
|
|
|
}
|
|
|
|
|
2010-04-04 20:34:07 +02:00
|
|
|
/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
|
|
|
|
/// instruction, using the specified assembler variant. Targets should
|
2019-04-18 00:21:10 +02:00
|
|
|
/// override this to format as appropriate for machine specific ExtraCodes
|
|
|
|
/// or when the arch-independent handling would be too complex otherwise.
|
2010-04-04 20:34:07 +02:00
|
|
|
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
[AsmPrinter] refactor to remove remove AsmVariant. NFC
Summary:
The InlineAsm::AsmDialect is only required for X86; no architecture
makes use of it and as such it gets passed around between arch-specific
and general code while being unused for all architectures but X86.
Since the AsmDialect is queried from a MachineInstr, which we also pass
around, remove the additional AsmDialect parameter and query for it deep
in the X86AsmPrinter only when needed/as late as possible.
This refactor should help later planned refactors to AsmPrinter, as this
difference in the X86AsmPrinter makes it harder to make AsmPrinter more
generic.
Reviewers: craig.topper
Subscribers: jholewinski, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, eraman, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, llvm-commits, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60488
llvm-svn: 358101
2019-04-10 18:38:43 +02:00
|
|
|
const char *ExtraCode, raw_ostream &O) {
|
2012-06-21 19:14:46 +02:00
|
|
|
// Does this asm operand have a single letter operand modifier?
|
|
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
|
|
|
|
[AsmPrinter] defer %c to base class for ARM, PPC, and Hexagon. NFC
Summary:
None of these derived classes do anything that the base class cannot.
If we remove these case statements, then the base class can handle them
just fine.
Reviewers: peter.smith, echristo
Reviewed By: echristo
Subscribers: nemanjai, javed.absar, eraman, kristof.beyls, hiraditya, kbarton, jsji, llvm-commits, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60803
llvm-svn: 358603
2019-04-17 20:22:48 +02:00
|
|
|
// https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html
|
2012-06-21 19:14:46 +02:00
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
|
|
|
switch (ExtraCode[0]) {
|
|
|
|
default:
|
|
|
|
return true; // Unknown modifier.
|
2019-04-18 00:21:10 +02:00
|
|
|
case 'a': // Print as memory address.
|
|
|
|
if (MO.isReg()) {
|
|
|
|
PrintAsmMemoryOperand(MI, OpNo, nullptr, O);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates.
|
2012-06-21 19:14:46 +02:00
|
|
|
case 'c': // Substitute immediate value without immediate syntax
|
[AsmPrinter] refactor to support %c w/ GlobalAddress'
Summary:
Targets like ARM, MSP430, PPC, and SystemZ have complex behavior when
printing the address of a MachineOperand::MO_GlobalAddress. Move that
handling into a new overriden method in each base class. A virtual
method was added to the base class for handling the generic case.
Refactors a few subclasses to support the target independent %a, %c, and
%n.
The patch also contains small cleanups for AVRAsmPrinter and
SystemZAsmPrinter.
It seems that NVPTXTargetLowering is possibly missing some logic to
transform GlobalAddressSDNodes for
TargetLowering::LowerAsmOperandForConstraint to handle with "i" extended
inline assembly asm constraints.
Fixes:
- https://bugs.llvm.org/show_bug.cgi?id=41402
- https://github.com/ClangBuiltLinux/linux/issues/449
Reviewers: echristo, void
Reviewed By: void
Subscribers: void, craig.topper, jholewinski, dschuff, jyknight, dylanmckay, sdardis, nemanjai, javed.absar, sbc100, jgravelle-google, eraman, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, jrtc27, atanasyan, jsji, llvm-commits, kees, tpimh, nathanchance, peter.smith, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60887
llvm-svn: 359337
2019-04-26 20:45:04 +02:00
|
|
|
if (MO.isImm()) {
|
|
|
|
O << MO.getImm();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (MO.isGlobal()) {
|
|
|
|
PrintSymbolOperand(MO, O);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2012-06-21 23:37:54 +02:00
|
|
|
case 'n': // Negate the immediate constant.
|
2019-04-18 00:21:10 +02:00
|
|
|
if (!MO.isImm())
|
2012-06-21 23:37:54 +02:00
|
|
|
return true;
|
|
|
|
O << -MO.getImm();
|
|
|
|
return false;
|
2016-02-04 17:18:08 +01:00
|
|
|
case 's': // The GCC deprecated s modifier
|
2019-04-18 00:21:10 +02:00
|
|
|
if (!MO.isImm())
|
2016-02-04 17:18:08 +01:00
|
|
|
return true;
|
|
|
|
O << ((32 - MO.getImm()) & 31);
|
|
|
|
return false;
|
2012-06-21 19:14:46 +02:00
|
|
|
}
|
|
|
|
}
|
2010-04-04 20:34:07 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
|
|
|
const char *ExtraCode, raw_ostream &O) {
|
|
|
|
// Target doesn't support this yet!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-19 20:52:25 +01:00
|
|
|
void AsmPrinter::emitInlineAsmStart() const {}
|
2014-12-17 11:56:16 +01:00
|
|
|
|
2014-01-24 16:47:54 +01:00
|
|
|
void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
|
2014-02-06 19:19:40 +01:00
|
|
|
const MCSubtargetInfo *EndInfo) const {}
|