summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/CodeGen/AsmPrinter.h5
-rw-r--r--llvm/include/llvm/CodeGen/TargetRegisterInfo.h7
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp110
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp5
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.h2
-rw-r--r--llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp5
-rw-r--r--llvm/lib/Target/ARM/ARMBaseRegisterInfo.h2
-rw-r--r--llvm/test/CodeGen/AArch64/inline-asm-clobber.ll8
-rw-r--r--llvm/test/CodeGen/ARM/inline-asm-clobber.ll27
9 files changed, 139 insertions, 32 deletions
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index b6056380916..14bc0816782 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -631,6 +631,11 @@ private:
/// inline asm.
void EmitInlineAsm(const MachineInstr *MI) const;
+ /// Add inline assembly info to the diagnostics machinery, so we can
+ /// emit file and position info. Returns SrcMgr memory buffer position.
+ unsigned addInlineAsmDiagBuffer(StringRef AsmStr,
+ const MDNode *LocMDNode) const;
+
//===------------------------------------------------------------------===//
// Internal Implementation Details
//===------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 55a8ba630a5..7013c3e74b4 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -510,6 +510,13 @@ public:
/// markSuperRegs() and checkAllSuperRegsMarked() in this case.
virtual BitVector getReservedRegs(const MachineFunction &MF) const = 0;
+ /// Returns false if we can't guarantee that Physreg, specified as an IR asm
+ /// clobber constraint, will be preserved across the statement.
+ virtual bool isAsmClobberable(const MachineFunction &MF,
+ unsigned PhysReg) const {
+ return true;
+ }
+
/// Returns true if PhysReg is unallocatable and constant throughout the
/// function. Used by MachineRegisterInfo::isConstantPhysReg().
virtual bool isConstantPhysReg(unsigned PhysReg) const { return false; }
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
index 4159eb19423..2920ac66290 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
@@ -71,6 +71,42 @@ static void srcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) {
DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie);
}
+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;
+}
+
+
/// EmitInlineAsm - Emit a blob of inline asm to the output streamer.
void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
const MCTargetOptions &MCOptions,
@@ -98,39 +134,11 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
return;
}
- if (!DiagInfo) {
- DiagInfo = make_unique<SrcMgrDiagInfo>();
+ unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
+ DiagInfo->SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
- 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;
- SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
-
- std::unique_ptr<MemoryBuffer> Buffer;
- // The inline asm source manager will outlive Str, so make a copy of the
- // string for SourceMgr to own.
- Buffer = MemoryBuffer::getMemBufferCopy(Str, "<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;
- }
-
- std::unique_ptr<MCAsmParser> Parser(
- createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
+ std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(
+ DiagInfo->SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
// Do not use assembler-level information for parsing inline assembly.
OutStreamer->setUseAssemblerInfoForParsing(false);
@@ -519,6 +527,44 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const {
MCOptions.SanitizeAddress =
MF->getFunction().hasFnAttribute(Attribute::SanitizeAddress);
+ // 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);
+ }
+
EmitInlineAsm(OS.str(), getSubtargetInfo(), MCOptions, LocMD,
MI->getInlineAsmDialect());
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index a7c2c1b8125..8d7639b78ef 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -189,6 +189,11 @@ bool AArch64RegisterInfo::isReservedReg(const MachineFunction &MF,
return false;
}
+bool AArch64RegisterInfo::isAsmClobberable(const MachineFunction &MF,
+ unsigned PhysReg) const {
+ return !isReservedReg(MF, PhysReg);
+}
+
bool AArch64RegisterInfo::isConstantPhysReg(unsigned PhysReg) const {
return PhysReg == AArch64::WZR || PhysReg == AArch64::XZR;
}
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index 57000d37090..d57ebbe9c00 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -69,6 +69,8 @@ public:
const uint32_t *getWindowsStackProbePreservedMask() const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
+ bool isAsmClobberable(const MachineFunction &MF,
+ unsigned PhysReg) const override;
bool isConstantPhysReg(unsigned PhysReg) const override;
const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index 5342e6e2cd1..02b3daf3c6f 100644
--- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -209,6 +209,11 @@ getReservedRegs(const MachineFunction &MF) const {
return Reserved;
}
+bool ARMBaseRegisterInfo::
+isAsmClobberable(const MachineFunction &MF, unsigned PhysReg) const {
+ return !getReservedRegs(MF).test(PhysReg);
+}
+
const TargetRegisterClass *
ARMBaseRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
const MachineFunction &) const {
diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
index f755f66a0f3..521e1b84f88 100644
--- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
+++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
@@ -131,6 +131,8 @@ public:
CallingConv::ID) const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
+ bool isAsmClobberable(const MachineFunction &MF,
+ unsigned PhysReg) const override;
const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
diff --git a/llvm/test/CodeGen/AArch64/inline-asm-clobber.ll b/llvm/test/CodeGen/AArch64/inline-asm-clobber.ll
new file mode 100644
index 00000000000..028cf0b6db1
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/inline-asm-clobber.ll
@@ -0,0 +1,8 @@
+; RUN: llc <%s -mtriple=aarch64-none-eabi 2>&1 | FileCheck %s
+
+; CHECK: warning: inline asm clobber list contains reserved registers: SP
+
+define void @foo() nounwind {
+ call void asm sideeffect "mov x7, #1", "~{x7},~{sp}"()
+ ret void
+}
diff --git a/llvm/test/CodeGen/ARM/inline-asm-clobber.ll b/llvm/test/CodeGen/ARM/inline-asm-clobber.ll
new file mode 100644
index 00000000000..458949a5c94
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/inline-asm-clobber.ll
@@ -0,0 +1,27 @@
+; RUN: llc <%s -mtriple=arm-none-eabi 2>&1 | FileCheck %s -check-prefix=CHECK
+
+; RUN: llc <%s -mtriple=arm-none-eabi -relocation-model=rwpi 2>&1 \
+; RUN: | FileCheck %s -check-prefix=RWPI
+
+; RUN: llc <%s -mtriple=arm-none-eabi --disable-fp-elim 2>&1 \
+; RUN: | FileCheck %s -check-prefix=NO_FP_ELIM
+
+; CHECK: warning: inline asm clobber list contains reserved registers: SP, PC
+; CHECK: warning: inline asm clobber list contains reserved registers: R11
+; RWPI: warning: inline asm clobber list contains reserved registers: R9, SP, PC
+; RWPI: warning: inline asm clobber list contains reserved registers: R11
+; NO_FP_ELIM: warning: inline asm clobber list contains reserved registers: R11, SP, PC
+; NO_FP_ELIM: warning: inline asm clobber list contains reserved registers: R11
+
+define void @foo() nounwind {
+ call void asm sideeffect "mov r7, #1",
+ "~{r9},~{r11},~{r12},~{lr},~{sp},~{pc},~{r10}"()
+ ret void
+}
+
+define i32 @bar(i32 %i) {
+ %vla = alloca i32, i32 %i, align 4
+ tail call void asm sideeffect "mov r7, #1", "~{r11}"()
+ %1 = load volatile i32, i32* %vla, align 4
+ ret i32 %1
+}
OpenPOWER on IntegriCloud