Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -557,10 +557,11 @@ /// Print the specified operand of MI, an INLINEASM instruction, using the /// specified assembler variant. Targets should override this to format as - /// appropriate. This method can return true if the operand is erroneous. + /// appropriate. This method can return true if the operand is erroneous, + /// and may supply some diagnostics via ErrorMsg virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS); + raw_ostream &OS, StringRef &ErrorMsg); /// Print the specified operand of MI, an INLINEASM instruction, using the /// specified assembler variant as an address. Targets should override this to Index: lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -246,6 +246,9 @@ OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; } + // Dedicate an Error Message container for target provided diagnostics + StringRef ErrorMsg; + // 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. @@ -261,13 +264,16 @@ /*Modifier*/ nullptr, OS); } else { Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, - /*Modifier*/ nullptr, OS); + /*Modifier*/ nullptr, OS, + ErrorMsg); } } if (Error) { std::string msg; raw_string_ostream Msg(msg); Msg << "invalid operand in inline asm: '" << AsmStr << "'"; + if (!ErrorMsg.empty()) + Msg << ErrorMsg; MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } break; @@ -412,6 +418,9 @@ OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; } + // Dedicate an Error Message container for target provided diagnostics + StringRef ErrorMsg; + // 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. @@ -433,14 +442,17 @@ OS); } else { Error = AP->PrintAsmOperand(MI, OpNo, InlineAsmVariant, - Modifier[0] ? Modifier : nullptr, OS); + Modifier[0] ? Modifier : nullptr, OS, + ErrorMsg); } } } if (Error) { std::string msg; raw_string_ostream Msg(msg); - Msg << "invalid operand in inline asm: '" << AsmStr << "'"; + Msg << (!ErrorMsg.empty() ? ErrorMsg : + "invalid operand in inline asm: "); + Msg << "'" << AsmStr << "'"; MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); } } @@ -562,7 +574,7 @@ /// override this to format as appropriate. bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { + raw_ostream &O, StringRef &ErrMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. Index: lib/Target/AArch64/AArch64AsmPrinter.cpp =================================================================== --- lib/Target/AArch64/AArch64AsmPrinter.cpp +++ lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -116,7 +116,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; @@ -314,11 +314,12 @@ bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { const MachineOperand &MO = MI->getOperand(OpNum); // First try the generic code, which knows about modifiers like 'c' and 'n'. - if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O)) + if (!AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O, ErrorMsg)) return false; // Does this asm operand have a single letter operand modifier? Index: lib/Target/AMDGPU/AMDGPUAsmPrinter.h =================================================================== --- lib/Target/AMDGPU/AMDGPUAsmPrinter.h +++ lib/Target/AMDGPU/AMDGPUAsmPrinter.h @@ -177,7 +177,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; protected: std::vector DisasmLines, HexLines; Index: lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp +++ lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp @@ -864,7 +864,8 @@ bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -872,7 +873,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); case 'r': break; } Index: lib/Target/ARM/ARMAsmPrinter.h =================================================================== --- lib/Target/ARM/ARMAsmPrinter.h +++ lib/Target/ARM/ARMAsmPrinter.h @@ -78,7 +78,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; Index: lib/Target/ARM/ARMAsmPrinter.cpp =================================================================== --- lib/Target/ARM/ARMAsmPrinter.cpp +++ lib/Target/ARM/ARMAsmPrinter.cpp @@ -252,7 +252,7 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { + raw_ostream &O, StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -260,7 +260,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O, + ErrorMsg); case 'a': // Print as a memory address. if (MI->getOperand(OpNum).isReg()) { O << "[" Index: lib/Target/Hexagon/HexagonAsmPrinter.h =================================================================== --- lib/Target/Hexagon/HexagonAsmPrinter.h +++ lib/Target/Hexagon/HexagonAsmPrinter.h @@ -49,7 +49,7 @@ void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) override; + raw_ostream &OS, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) override; Index: lib/Target/Hexagon/HexagonAsmPrinter.cpp =================================================================== --- lib/Target/Hexagon/HexagonAsmPrinter.cpp +++ lib/Target/Hexagon/HexagonAsmPrinter.cpp @@ -127,7 +127,8 @@ bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) { + raw_ostream &OS, + StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) @@ -136,7 +137,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, OS, + ErrorMsg); case 'c': // Don't print "$" before a global var name or constant. // Hexagon never has a prefix. printOperand(MI, OpNo, OS); Index: lib/Target/Lanai/LanaiAsmPrinter.cpp =================================================================== --- lib/Target/Lanai/LanaiAsmPrinter.cpp +++ lib/Target/Lanai/LanaiAsmPrinter.cpp @@ -50,7 +50,7 @@ void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; void EmitInstruction(const MachineInstr *MI) override; bool isBlockOnlyReachableByFallthrough( const MachineBasicBlock *MBB) const override; @@ -110,7 +110,8 @@ // PrintAsmOperand - Print out an operand for an inline asm expression. bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned /*AsmVariant*/, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1]) Index: lib/Target/MSP430/MSP430AsmPrinter.cpp =================================================================== --- lib/Target/MSP430/MSP430AsmPrinter.cpp +++ lib/Target/MSP430/MSP430AsmPrinter.cpp @@ -50,7 +50,8 @@ raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, + StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; @@ -124,7 +125,8 @@ /// bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) return true; // Unknown modifier. Index: lib/Target/Mips/MipsAsmPrinter.h =================================================================== --- lib/Target/Mips/MipsAsmPrinter.h +++ lib/Target/Mips/MipsAsmPrinter.h @@ -141,7 +141,7 @@ const MachineBasicBlock* MBB) const override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -453,7 +453,7 @@ // Print out an operand for an inline asm expression. bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { + raw_ostream &O, StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -462,7 +462,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O); + return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O, + ErrorMsg); case 'X': // hex const int if ((MO.getType()) != MachineOperand::MO_Immediate) return true; Index: lib/Target/NVPTX/NVPTXAsmPrinter.h =================================================================== --- lib/Target/NVPTX/NVPTXAsmPrinter.h +++ lib/Target/NVPTX/NVPTXAsmPrinter.h @@ -256,7 +256,7 @@ void printReturnValStr(const MachineFunction &MF, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &) override; + raw_ostream &, StringRef &ErrorMsg) override; void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier = nullptr); bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, Index: lib/Target/NVPTX/NVPTXAsmPrinter.cpp =================================================================== --- lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -2322,7 +2322,8 @@ /// bool NVPTXAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -2330,7 +2331,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); case 'r': break; } Index: lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- lib/Target/PowerPC/PPCAsmPrinter.cpp +++ lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -100,7 +100,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; @@ -253,7 +253,8 @@ /// bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -261,7 +262,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); case 'c': // Don't print "$" before a global var name or constant. break; // PPC never has a prefix. case 'L': // Write second word of DImode reference. Index: lib/Target/Sparc/SparcAsmPrinter.cpp =================================================================== --- lib/Target/Sparc/SparcAsmPrinter.cpp +++ lib/Target/Sparc/SparcAsmPrinter.cpp @@ -61,7 +61,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; @@ -408,14 +408,16 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { + raw_ostream &O, + StringRef &ErrorMsg) { if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); case 'f': case 'r': break; Index: lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- lib/Target/SystemZ/SystemZAsmPrinter.h +++ lib/Target/SystemZ/SystemZAsmPrinter.h @@ -32,7 +32,7 @@ void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) override; + raw_ostream &OS, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) override; Index: lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -497,7 +497,8 @@ unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) { + raw_ostream &OS, + StringRef &ErrorMsg) { if (ExtraCode && *ExtraCode == 'n') { if (!MI->getOperand(OpNo).isImm()) return true; Index: lib/Target/X86/X86AsmPrinter.h =================================================================== --- lib/Target/X86/X86AsmPrinter.h +++ lib/Target/X86/X86AsmPrinter.h @@ -122,7 +122,7 @@ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS) override; + raw_ostream &OS, StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS) override; Index: lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- lib/Target/X86/X86AsmPrinter.cpp +++ lib/Target/X86/X86AsmPrinter.cpp @@ -373,7 +373,8 @@ /// bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { + const char *ExtraCode, raw_ostream &O, + StringRef &ErrorMsg) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. @@ -383,7 +384,8 @@ switch (ExtraCode[0]) { default: // See if this is a generic print operand - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); case 'a': // This is an address. Currently only 'i' and 'r' are expected. switch (MO.getType()) { default: @@ -455,6 +457,14 @@ return false; } O << '-'; + break; + case 'H': + // Diagnostics. + // Reaching here means the user asked for the 'H' modifier, on a non + // (offsettable) memory operand. Properly report this false behavior. + ErrorMsg = "Cannot use 'H' modifier on a non-offsettable memory " + "reference: "; + return true; } } Index: lib/Target/XCore/XCoreAsmPrinter.cpp =================================================================== --- lib/Target/XCore/XCoreAsmPrinter.cpp +++ lib/Target/XCore/XCoreAsmPrinter.cpp @@ -68,7 +68,8 @@ void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) override; + raw_ostream &O, + StringRef &ErrorMsg) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; @@ -234,7 +235,8 @@ /// bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant,const char *ExtraCode, - raw_ostream &O) { + raw_ostream &O, + StringRef &ErrorMsg) { // Print the operand if there is no operand modifier. if (!ExtraCode || !ExtraCode[0]) { printOperand(MI, OpNo, O); @@ -242,7 +244,8 @@ } // Otherwise fallback on the default implementation. - return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O, + ErrorMsg); } bool XCoreAsmPrinter:: Index: test/CodeGen/X86/inline-asm-modifier-error.ll =================================================================== --- test/CodeGen/X86/inline-asm-modifier-error.ll +++ test/CodeGen/X86/inline-asm-modifier-error.ll @@ -0,0 +1,12 @@ +; RUN: not llc -march x86 < %s 2> %t +; RUN: FileCheck %s < %t + +; 'H' modifier, when applied on a non-memory operand +; CHECK: error: Cannot use 'H' modifier on a non-offsettable memory reference: 'movl $0, ${1:H}' + +define void @foo() local_unnamed_addr #0 { +entry: + tail call void asm sideeffect "movl $0, ${1:H}", "i,i,~{dirflag},~{fpsr},~{flags}"(i32 1, i32 2) + ret void +} +