2010-04-05 03:09:29 +08:00
|
|
|
//===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===//
|
2010-04-05 02:34:07 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2010-04-05 03:09:29 +08:00
|
|
|
// This file implements the inline assembler pieces of the AsmPrinter class.
|
2010-04-05 02:34:07 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2014-04-23 19:16:03 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2017-11-08 09:01:31 +08:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
2014-01-04 03:21:54 +08:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/InlineAsm.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2010-04-05 02:34:07 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2016-01-27 18:01:28 +08:00
|
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
2010-04-05 02:34:07 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2011-07-09 13:47:46 +08:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2010-04-05 02:34:07 +08: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 07:11:24 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2011-08-25 02:08:43 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2010-04-05 02:34:07 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2010-04-05 02:34:07 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 10:02:50 +08:00
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
|
2012-09-08 02:16:38 +08:00
|
|
|
/// srcMgrDiagHandler - This callback is invoked when the SourceMgr for an
|
2010-11-17 16:03:32 +08:00
|
|
|
/// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo
|
|
|
|
/// struct above.
|
2012-09-08 02:16:38 +08:00
|
|
|
static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) {
|
[Assembler] Enable nicer diagnostics for inline assembly.
Fixed test.
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: 294458
2017-02-08 22:48:05 +08:00
|
|
|
AsmPrinter::SrcMgrDiagInfo *DiagInfo =
|
|
|
|
static_cast<AsmPrinter::SrcMgrDiagInfo *>(diagInfo);
|
2010-11-17 16:03:32 +08:00
|
|
|
assert(DiagInfo && "Diagnostic context not passed down?");
|
2011-09-22 05:36:53 +08:00
|
|
|
|
2017-02-13 21:58:00 +08:00
|
|
|
// Look up a LocInfo for the buffer this diagnostic is coming from.
|
|
|
|
unsigned BufNum = DiagInfo->SrcMgr.FindBufferContainingLoc(Diag.getLoc());
|
|
|
|
const MDNode *LocInfo = nullptr;
|
|
|
|
if (BufNum > 0 && BufNum <= DiagInfo->LocInfos.size())
|
|
|
|
LocInfo = DiagInfo->LocInfos[BufNum-1];
|
|
|
|
|
2010-11-17 16:20:42 +08:00
|
|
|
// If the inline asm had metadata associated with it, pull out a location
|
|
|
|
// cookie corresponding to which line the error occurred on.
|
2010-11-17 16:03:32 +08:00
|
|
|
unsigned LocCookie = 0;
|
2017-02-13 21:58:00 +08:00
|
|
|
if (LocInfo) {
|
2010-11-17 16:20:42 +08:00
|
|
|
unsigned ErrorLine = Diag.getLineNo()-1;
|
|
|
|
if (ErrorLine >= LocInfo->getNumOperands())
|
|
|
|
ErrorLine = 0;
|
2011-09-22 05:36:53 +08:00
|
|
|
|
2010-11-17 16:20:42 +08:00
|
|
|
if (LocInfo->getNumOperands() != 0)
|
|
|
|
if (const ConstantInt *CI =
|
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-10 02:38:53 +08:00
|
|
|
mdconst::dyn_extract<ConstantInt>(LocInfo->getOperand(ErrorLine)))
|
2010-11-17 16:03:32 +08:00
|
|
|
LocCookie = CI->getZExtValue();
|
2010-11-17 16:20:42 +08:00
|
|
|
}
|
2011-09-22 05:36:53 +08:00
|
|
|
|
2010-11-17 16:13:01 +08:00
|
|
|
DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie);
|
2010-11-17 16:03:32 +08: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 20:52:35 +08:00
|
|
|
unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr,
|
|
|
|
const MDNode *LocMDNode) const {
|
|
|
|
if (!DiagInfo) {
|
|
|
|
DiagInfo = make_unique<SrcMgrDiagInfo>();
|
|
|
|
|
|
|
|
MCContext &Context = MMI->getContext();
|
|
|
|
Context.setInlineSourceManager(&DiagInfo->SrcMgr);
|
|
|
|
|
|
|
|
LLVMContext &LLVMCtx = MMI->getModule()->getContext();
|
|
|
|
if (LLVMCtx.getInlineAsmDiagnosticHandler()) {
|
|
|
|
DiagInfo->DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler();
|
|
|
|
DiagInfo->DiagContext = LLVMCtx.getInlineAsmDiagnosticContext();
|
|
|
|
DiagInfo->SrcMgr.setDiagHandler(srcMgrDiagHandler, DiagInfo.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceMgr &SrcMgr = DiagInfo->SrcMgr;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
DiagInfo->LocInfos.resize(BufNum);
|
|
|
|
DiagInfo->LocInfos[BufNum - 1] = LocMDNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return BufNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
/// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
|
2015-03-17 02:02:16 +08:00
|
|
|
void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
2015-05-15 08:20:44 +08:00
|
|
|
const MCTargetOptions &MCOptions,
|
2015-03-17 02:02:16 +08:00
|
|
|
const MDNode *LocMDNode,
|
2012-09-06 07:57:37 +08:00
|
|
|
InlineAsm::AsmDialect Dialect) const {
|
2010-04-05 02:34:07 +08:00
|
|
|
assert(!Str.empty() && "Can't emit empty inline asm block");
|
2010-10-02 07:29:12 +08: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 07:11:24 +08: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 07:29:12 +08:00
|
|
|
|
2014-02-13 22:44:26 +08:00
|
|
|
// If the output streamer does not have mature MC support or the integrated
|
|
|
|
// assembler has been disabled, just emit the blob textually.
|
|
|
|
// Otherwise parse the asm and emit it via MC support.
|
2010-04-05 02:34:07 +08:00
|
|
|
// This is useful in case the asm parser doesn't handle something but the
|
|
|
|
// system assembler does.
|
2014-02-13 22:44:26 +08:00
|
|
|
const MCAsmInfo *MCAI = TM.getMCAsmInfo();
|
|
|
|
assert(MCAI && "No MCAsmInfo");
|
|
|
|
if (!MCAI->useIntegratedAssembler() &&
|
2015-04-25 03:11:51 +08:00
|
|
|
!OutStreamer->isIntegratedAssemblerRequired()) {
|
2015-02-20 03:52:25 +08:00
|
|
|
emitInlineAsmStart();
|
2015-04-25 03:11:51 +08:00
|
|
|
OutStreamer->EmitRawText(Str);
|
2015-03-17 02:02:16 +08:00
|
|
|
emitInlineAsmEnd(STI, nullptr);
|
2010-04-05 02:34:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-10-02 07:29:12 +08: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 20:52:35 +08:00
|
|
|
unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
|
|
|
|
DiagInfo->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 18:20:07 +08: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 20:52:35 +08:00
|
|
|
std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(
|
|
|
|
DiagInfo->SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
|
2011-07-08 09:53:10 +08: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-05-01 03:22:40 +08:00
|
|
|
// Do not use assembler-level information for parsing inline assembly.
|
|
|
|
OutStreamer->setUseAssemblerInfoForParsing(false);
|
|
|
|
|
2015-02-21 17:09:15 +08:00
|
|
|
// We create a new MCInstrInfo here since we might be at the module level
|
2015-02-20 07:52:35 +08:00
|
|
|
// and not have a MachineFunction to initialize the TargetInstrInfo from and
|
2015-02-21 17:09:15 +08: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());
|
2015-02-20 05:29:51 +08:00
|
|
|
std::unique_ptr<MCTargetAsmParser> TAP(TM.getTarget().createMCAsmParser(
|
2015-11-14 14:35:56 +08: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 07:11:24 +08:00
|
|
|
if (!TAP)
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("Inline asm not supported by this streamer because"
|
2010-04-08 18:44:28 +08:00
|
|
|
" we don't have an asm parser for this target\n");
|
2012-09-06 07:57:37 +08:00
|
|
|
Parser->setAssemblerDialect(Dialect);
|
2010-07-19 02:31:33 +08:00
|
|
|
Parser->setTargetParser(*TAP.get());
|
2017-11-09 20:45:40 +08:00
|
|
|
Parser->setEnablePrintSchedInfo(EnablePrintSchedInfo);
|
[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-25 04:23:57 +08:00
|
|
|
// Enable lexing Masm binary and hex integer literals in intel inline
|
|
|
|
// assembly.
|
2017-04-26 17:56:59 +08: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-25 04:23:57 +08:00
|
|
|
Parser->getLexer().setLexMasmIntegers(true);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (MF) {
|
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
|
|
TAP->SetFrameRegister(TRI->getFrameRegister(*MF));
|
|
|
|
}
|
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 07:11:24 +08:00
|
|
|
|
2015-02-20 03:52:25 +08: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 07:11:24 +08:00
|
|
|
// Don't implicitly switch to the text section before the asm.
|
2010-07-19 02:31:33 +08:00
|
|
|
int Res = Parser->Run(/*NoInitialTextSection*/ true,
|
|
|
|
/*NoFinalize*/ true);
|
2015-11-14 14:35:56 +08:00
|
|
|
emitInlineAsmEnd(STI, &TAP->getSTI());
|
[Assembler] Enable nicer diagnostics for inline assembly.
Fixed test.
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: 294458
2017-02-08 22:48:05 +08:00
|
|
|
|
|
|
|
if (Res && !DiagInfo->DiagHandler)
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("Error parsing inline asm\n");
|
2010-04-05 02:34:07 +08:00
|
|
|
}
|
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
|
|
|
MachineModuleInfo *MMI, int InlineAsmVariant,
|
|
|
|
AsmPrinter *AP, unsigned LocCookie,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
// Switch to the inline assembly variant.
|
|
|
|
OS << "\t.intel_syntax\n\t";
|
2010-04-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
2010-04-05 02:34:07 +08:00
|
|
|
unsigned NumOperands = MI->getNumOperands();
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2012-09-12 03:09:56 +08: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-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08: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-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
// Handle escapes.
|
|
|
|
switch (*LastEmitted) {
|
|
|
|
default: Done = false; break;
|
|
|
|
case '$':
|
|
|
|
++LastEmitted; // Consume second '$' character.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Done) break;
|
2010-04-05 02:34:07 +08:00
|
|
|
|
2016-11-29 08:29:27 +08: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 (LastEmitted[0] == '{' && LastEmitted[1] == ':') {
|
|
|
|
LastEmitted += 2;
|
|
|
|
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-12 03:09:56 +08:00
|
|
|
const char *IDStart = LastEmitted;
|
|
|
|
const char *IDEnd = IDStart;
|
|
|
|
while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd;
|
2010-04-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08: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-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
if (Val >= NumOperands-1)
|
|
|
|
report_fatal_error("Invalid $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
// Okay, we finally have a value number. Ask the target to print this
|
|
|
|
// operand!
|
|
|
|
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
bool Error = false;
|
2010-04-05 02:34:07 +08:00
|
|
|
|
2012-09-12 03:09:56 +08: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-11 05:36:05 +08:00
|
|
|
|
2012-09-12 03:09:56 +08: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 07:20:02 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
if (InlineAsm::isMemKind(OpFlags)) {
|
|
|
|
Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant,
|
2014-04-24 14:44:33 +08:00
|
|
|
/*Modifier*/ nullptr, OS);
|
2012-09-12 03:09:56 +08:00
|
|
|
} else {
|
|
|
|
Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant,
|
2014-04-24 14:44:33 +08:00
|
|
|
/*Modifier*/ nullptr, OS);
|
2012-09-12 03:09:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Error) {
|
2014-06-27 06:52:05 +08:00
|
|
|
std::string msg;
|
|
|
|
raw_string_ostream Msg(msg);
|
2012-09-12 03:09:56 +08:00
|
|
|
Msg << "invalid operand in inline asm: '" << AsmStr << "'";
|
|
|
|
MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-11 05:36:05 +08:00
|
|
|
}
|
2012-09-12 03:09:56 +08:00
|
|
|
OS << "\n\t.att_syntax\n" << (char)0; // null terminate string.
|
|
|
|
}
|
2012-09-11 05:36:05 +08:00
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
|
|
|
|
MachineModuleInfo *MMI, int InlineAsmVariant,
|
|
|
|
int AsmPrinterVariant, AsmPrinter *AP,
|
|
|
|
unsigned LocCookie, raw_ostream &OS) {
|
2010-04-05 02:34:07 +08:00
|
|
|
int CurVariant = -1; // The number of the {.|.|.} region we are in.
|
|
|
|
const char *LastEmitted = AsmStr; // One past the last character emitted.
|
2012-09-12 03:09:56 +08:00
|
|
|
unsigned NumOperands = MI->getNumOperands();
|
|
|
|
|
|
|
|
OS << '\t';
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08: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 06:42:30 +08:00
|
|
|
OS << '\n'; // Indent code with newline.
|
2010-04-05 02:34:07 +08: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 13:27:36 +08:00
|
|
|
if (CurVariant != -1)
|
2010-04-08 18:44:28 +08:00
|
|
|
report_fatal_error("Nested variants found in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-05 02:34:07 +08: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 07:29:12 +08:00
|
|
|
else
|
2010-04-05 02:34:07 +08:00
|
|
|
CurVariant = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Done) break;
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
bool HasCurlyBraces = false;
|
|
|
|
if (*LastEmitted == '{') { // ${variable}
|
|
|
|
++LastEmitted; // Consume '{' character.
|
|
|
|
HasCurlyBraces = true;
|
|
|
|
}
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08: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 14:44:33 +08:00
|
|
|
if (!StrEnd)
|
2010-04-08 18:44:28 +08:00
|
|
|
report_fatal_error("Unterminated ${:foo} operand in inline asm"
|
|
|
|
" string: '" + Twine(AsmStr) + "'");
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
std::string Val(StrStart, StrEnd);
|
2012-09-12 03:09:56 +08:00
|
|
|
AP->PrintSpecial(MI, OS, Val.c_str());
|
2010-04-05 02:34:07 +08:00
|
|
|
LastEmitted = StrEnd+1;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
const char *IDStart = LastEmitted;
|
2010-04-05 02:42:18 +08:00
|
|
|
const char *IDEnd = IDStart;
|
2010-10-02 07:29:12 +08:00
|
|
|
while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd;
|
|
|
|
|
2010-04-05 02:42:18 +08:00
|
|
|
unsigned Val;
|
|
|
|
if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val))
|
2010-04-08 18:44:28 +08:00
|
|
|
report_fatal_error("Bad $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-05 02:34:07 +08:00
|
|
|
LastEmitted = IDEnd;
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
char Modifier[2] = { 0, 0 };
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08: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 06:42:30 +08:00
|
|
|
if (*LastEmitted == 0)
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("Bad ${:} expression in inline asm string: '" +
|
2010-04-08 18:44:28 +08:00
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
Modifier[0] = *LastEmitted;
|
|
|
|
++LastEmitted; // Consume modifier character.
|
|
|
|
}
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-06 06:42:30 +08:00
|
|
|
if (*LastEmitted != '}')
|
2010-04-08 18:44:28 +08:00
|
|
|
report_fatal_error("Bad ${} expression in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-04-05 02:34:07 +08:00
|
|
|
++LastEmitted; // Consume '}' character.
|
|
|
|
}
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-06 06:42:30 +08:00
|
|
|
if (Val >= NumOperands-1)
|
2010-04-08 18:44:28 +08:00
|
|
|
report_fatal_error("Invalid $ operand number in inline asm string: '" +
|
|
|
|
Twine(AsmStr) + "'");
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
// Okay, we finally have a value number. Ask the target to print this
|
|
|
|
// operand!
|
|
|
|
if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
|
2011-01-08 07:50:32 +08:00
|
|
|
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
|
2010-04-05 02:34:07 +08: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-09 03:14:42 +08: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 09:33:51 +08:00
|
|
|
if (OpNo >= MI->getNumOperands() ||
|
2012-05-09 03:14:42 +08:00
|
|
|
MI->getOperand(OpNo).isMetadata()) {
|
2010-04-05 02:34:07 +08:00
|
|
|
Error = true;
|
|
|
|
} else {
|
|
|
|
unsigned OpFlags = MI->getOperand(OpNo).getImm();
|
|
|
|
++OpNo; // Skip over the ID number.
|
|
|
|
|
2015-06-09 08:31:39 +08:00
|
|
|
if (Modifier[0] == 'l') { // Labels are target independent.
|
2010-04-05 02:34:07 +08:00
|
|
|
// FIXME: What if the operand isn't an MBB, report error?
|
2015-06-09 08:31:39 +08:00
|
|
|
const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol();
|
|
|
|
Sym->print(OS, AP->MAI);
|
|
|
|
} else {
|
2010-04-07 13:27:36 +08:00
|
|
|
if (InlineAsm::isMemKind(OpFlags)) {
|
2012-09-11 05:10:49 +08:00
|
|
|
Error = AP->PrintAsmMemoryOperand(MI, OpNo, InlineAsmVariant,
|
2014-04-24 14:44:33 +08:00
|
|
|
Modifier[0] ? Modifier : nullptr,
|
2010-04-05 02:34:07 +08:00
|
|
|
OS);
|
|
|
|
} else {
|
2012-09-11 05:10:49 +08:00
|
|
|
Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant,
|
2014-04-24 14:44:33 +08:00
|
|
|
Modifier[0] ? Modifier : nullptr, OS);
|
2010-04-05 02:34:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Error) {
|
2014-06-27 06:52:05 +08: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 07:40:44 +08:00
|
|
|
Msg << "invalid operand in inline asm: '" << AsmStr << "'";
|
|
|
|
MMI->getModule()->getContext().emitError(LocCookie, Msg.str());
|
2010-04-05 02:34:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-12 03:09:56 +08:00
|
|
|
OS << '\n' << (char)0; // null terminate string.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitInlineAsm - This method formats and emits the specified machine
|
|
|
|
/// instruction that is an inline asm.
|
|
|
|
void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const {
|
|
|
|
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-25 03:11:51 +08:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmStart());
|
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
|
2012-09-12 03:09:56 +08:00
|
|
|
return;
|
2012-09-11 05:36:05 +08:00
|
|
|
}
|
|
|
|
|
2012-09-12 03:09:56 +08:00
|
|
|
// Emit the #APP start marker. This has to happen even if verbose-asm isn't
|
2014-01-17 00:28:37 +08:00
|
|
|
// enabled, so we use emitRawComment.
|
2015-04-25 03:11:51 +08:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmStart());
|
2012-09-12 03:09:56 +08:00
|
|
|
|
|
|
|
// Get the !srcloc metadata node if we have it, and decode the loc cookie from
|
|
|
|
// it.
|
|
|
|
unsigned LocCookie = 0;
|
2014-04-24 14:44:33 +08:00
|
|
|
const MDNode *LocMD = nullptr;
|
2012-09-12 03:09:56 +08: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-10 02:38:53 +08:00
|
|
|
if (const ConstantInt *CI =
|
|
|
|
mdconst::dyn_extract<ConstantInt>(LocMD->getOperand(0))) {
|
2012-09-12 03:09:56 +08:00
|
|
|
LocCookie = CI->getZExtValue();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the inline asm to a temporary string so we can emit it through
|
|
|
|
// EmitInlineAsm.
|
2014-06-27 06:52:05 +08:00
|
|
|
SmallString<256> StringData;
|
|
|
|
raw_svector_ostream OS(StringData);
|
2012-09-12 03:09:56 +08:00
|
|
|
|
|
|
|
// The variant of the current asmprinter.
|
|
|
|
int AsmPrinterVariant = MAI->getAssemblerDialect();
|
|
|
|
InlineAsm::AsmDialect InlineAsmVariant = MI->getInlineAsmDialect();
|
|
|
|
AsmPrinter *AP = const_cast<AsmPrinter*>(this);
|
|
|
|
if (InlineAsmVariant == InlineAsm::AD_ATT)
|
|
|
|
EmitGCCInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AsmPrinterVariant,
|
|
|
|
AP, LocCookie, OS);
|
|
|
|
else
|
|
|
|
EmitMSInlineAsmStr(AsmStr, MI, MMI, InlineAsmVariant, AP, LocCookie, OS);
|
|
|
|
|
2015-05-15 08:20:44 +08:00
|
|
|
// Reset SanitizeAddress based on the function's attribute.
|
|
|
|
MCTargetOptions MCOptions = TM.Options.MCOptions;
|
|
|
|
MCOptions.SanitizeAddress =
|
2017-12-16 06:22:58 +08:00
|
|
|
MF->getFunction().hasFnAttribute(Attribute::SanitizeAddress);
|
2015-05-15 08:20:44 +08: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 20:52:35 +08:00
|
|
|
// Emit warnings if we use reserved registers on the clobber list, as
|
|
|
|
// that might give surprising results.
|
|
|
|
std::vector<std::string> RestrRegs;
|
|
|
|
// 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);
|
|
|
|
if (MO.isImm()) {
|
|
|
|
unsigned Flags = MO.getImm();
|
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
|
|
if (InlineAsm::getKind(Flags) == InlineAsm::Kind_Clobber &&
|
|
|
|
!TRI->isAsmClobberable(*MF, MI->getOperand(I + 1).getReg())) {
|
|
|
|
RestrRegs.push_back(TRI->getName(MI->getOperand(I + 1).getReg()));
|
|
|
|
}
|
|
|
|
// Skip to one before the next operand descriptor, if it exists.
|
|
|
|
I += InlineAsm::getNumOperandRegisters(Flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!RestrRegs.empty()) {
|
|
|
|
unsigned BufNum = addInlineAsmDiagBuffer(OS.str(), LocMD);
|
|
|
|
auto &SrcMgr = DiagInfo->SrcMgr;
|
|
|
|
SMLoc Loc = SMLoc::getFromPointer(
|
|
|
|
SrcMgr.getMemoryBuffer(BufNum)->getBuffer().begin());
|
|
|
|
|
|
|
|
std::string Msg = "inline asm clobber list contains reserved registers: ";
|
|
|
|
for (auto I = RestrRegs.begin(), E = RestrRegs.end(); I != E; I++) {
|
|
|
|
if(I != RestrRegs.begin())
|
|
|
|
Msg += ", ";
|
|
|
|
Msg += *I;
|
|
|
|
}
|
|
|
|
std::string Note = "Reserved registers on the clobber list may not be "
|
|
|
|
"preserved across the asm statement, and clobbering them may "
|
|
|
|
"lead to undefined behaviour.";
|
|
|
|
SrcMgr.PrintMessage(Loc, SourceMgr::DK_Warning, Msg);
|
|
|
|
SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, Note);
|
|
|
|
}
|
|
|
|
|
2015-05-15 08:20:44 +08:00
|
|
|
EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD,
|
|
|
|
MI->getInlineAsmDialect());
|
2010-10-02 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08:00
|
|
|
// Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't
|
2014-01-17 00:28:37 +08:00
|
|
|
// enabled, so we use emitRawComment.
|
2015-04-25 03:11:51 +08:00
|
|
|
OutStreamer->emitRawComment(MAI->getInlineAsmEnd());
|
2010-04-05 02:34:07 +08: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 14:11:10 +08:00
|
|
|
const DataLayout &DL = MF->getDataLayout();
|
|
|
|
OS << DL.getPrivateGlobalPrefix();
|
2010-04-05 02:34:07 +08: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 07:29:12 +08:00
|
|
|
|
2010-04-05 02:34:07 +08: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 06:52:05 +08:00
|
|
|
std::string msg;
|
|
|
|
raw_string_ostream Msg(msg);
|
2010-04-05 02:34:07 +08:00
|
|
|
Msg << "Unknown special formatter '" << Code
|
|
|
|
<< "' for machine instr: " << *MI;
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error(Msg.str());
|
2010-10-02 07:29:12 +08:00
|
|
|
}
|
2010-04-05 02:34:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
|
|
|
|
/// instruction, using the specified assembler variant. Targets should
|
|
|
|
/// override this to format as appropriate.
|
|
|
|
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
2012-09-08 04:23:29 +08:00
|
|
|
unsigned AsmVariant, const char *ExtraCode,
|
|
|
|
raw_ostream &O) {
|
2012-06-22 01:14:46 +08:00
|
|
|
// Does this asm operand have a single letter operand modifier?
|
|
|
|
if (ExtraCode && ExtraCode[0]) {
|
|
|
|
if (ExtraCode[1] != 0) return true; // Unknown modifier.
|
|
|
|
|
|
|
|
const MachineOperand &MO = MI->getOperand(OpNo);
|
|
|
|
switch (ExtraCode[0]) {
|
|
|
|
default:
|
|
|
|
return true; // Unknown modifier.
|
|
|
|
case 'c': // Substitute immediate value without immediate syntax
|
2012-06-22 05:37:54 +08:00
|
|
|
if (MO.getType() != MachineOperand::MO_Immediate)
|
2012-06-22 01:14:46 +08:00
|
|
|
return true;
|
|
|
|
O << MO.getImm();
|
|
|
|
return false;
|
2012-06-22 05:37:54 +08:00
|
|
|
case 'n': // Negate the immediate constant.
|
|
|
|
if (MO.getType() != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << -MO.getImm();
|
|
|
|
return false;
|
2016-02-05 00:18:08 +08:00
|
|
|
case 's': // The GCC deprecated s modifier
|
|
|
|
if (MO.getType() != MachineOperand::MO_Immediate)
|
|
|
|
return true;
|
|
|
|
O << ((32 - MO.getImm()) & 31);
|
|
|
|
return false;
|
2012-06-22 01:14:46 +08:00
|
|
|
}
|
|
|
|
}
|
2010-04-05 02:34:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
|
|
|
unsigned AsmVariant,
|
|
|
|
const char *ExtraCode, raw_ostream &O) {
|
|
|
|
// Target doesn't support this yet!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-20 03:52:25 +08:00
|
|
|
void AsmPrinter::emitInlineAsmStart() const {}
|
2014-12-17 18:56:16 +08:00
|
|
|
|
2014-01-24 23:47:54 +08:00
|
|
|
void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
|
2014-02-07 02:19:40 +08:00
|
|
|
const MCSubtargetInfo *EndInfo) const {}
|