-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Add diagnostic help for inline asm operand constraint 'H' #88248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -528,6 +528,20 @@ class InlineAsm final : public Value { | |
} | ||
}; | ||
|
||
/// Inline Asm specifies input & output constraint which can | ||
/// specifiy target specific criteria for operand. If this criteria | ||
/// does not match, we must throw error. | ||
/// NO_ERROR represents Operand constraints are valid/applicable | ||
/// OPERAND_ERROR represents some constraint(unspecified) failed | ||
/// UNKNOWN_MODIFIER_ERROR represents use of unknown char constraint | ||
/// CONSTRAINT_<char>_ERROR represents error regarding constraint. | ||
enum class AsmOperandErrorCode { | ||
NO_ERROR = 0, | ||
OPERAND_ERROR, | ||
UNKNOWN_MODIFIER_ERROR, | ||
CONSTRAINT_H_ERROR, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why can't we just make the constraint code available to the error printing code? Having one of these for every possible case sounds like a headache. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All constraint codes related to inline asm are defined in same file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The constraint H seems too specific. Why not just let this be an arbitrary string carried by Error? |
||
}; | ||
|
||
} // end namespace llvm | ||
|
||
#endif // LLVM_IR_INLINEASM_H | ||
#endif // LLVM_IR_INLINEASM_H | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing newline |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -273,7 +273,7 @@ static void EmitInlineAsmStr(const char *AsmStr, const MachineInstr *MI, | |||||||
unsigned OpNo = InlineAsm::MIOp_FirstOperand; | ||||||||
|
||||||||
bool Error = false; | ||||||||
|
||||||||
AsmOperandErrorCode OpErrorCode = AsmOperandErrorCode::NO_ERROR; | ||||||||
// Scan to find the machine operand number for the operand. | ||||||||
for (; Val; --Val) { | ||||||||
if (OpNo >= MI->getNumOperands()) | ||||||||
|
@@ -306,15 +306,15 @@ static void EmitInlineAsmStr(const char *AsmStr, const MachineInstr *MI, | |||||||
Error = AP->PrintAsmMemoryOperand( | ||||||||
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); | ||||||||
} else { | ||||||||
Error = AP->PrintAsmOperand(MI, OpNo, | ||||||||
Modifier[0] ? Modifier : nullptr, OS); | ||||||||
OpErrorCode = AP->PrintAsmOperand( | ||||||||
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS); | ||||||||
} | ||||||||
} | ||||||||
if (Error) { | ||||||||
std::string msg; | ||||||||
raw_string_ostream Msg(msg); | ||||||||
Msg << "invalid operand in inline asm: '" << AsmStr << "'"; | ||||||||
MMI->getModule()->getContext().emitError(LocCookie, Msg.str()); | ||||||||
if (Error || (OpErrorCode != AsmOperandErrorCode::NO_ERROR)) { | ||||||||
if (Error) | ||||||||
OpErrorCode = AsmOperandErrorCode::OPERAND_ERROR; | ||||||||
AP->diagnoseAsmOperandError(MMI->getModule()->getContext(), | ||||||||
OpErrorCode, AsmStr, LocCookie); | ||||||||
} | ||||||||
} | ||||||||
break; | ||||||||
|
@@ -461,50 +461,62 @@ void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) { | |||||||
printOffset(MO.getOffset(), OS); | ||||||||
} | ||||||||
|
||||||||
void AsmPrinter::diagnoseAsmOperandError(LLVMContext &C, | ||||||||
const AsmOperandErrorCode ErrCode, | ||||||||
const char *AsmStr, | ||||||||
const uint64_t Loc) { | ||||||||
std::string msg; | ||||||||
raw_string_ostream Msg(msg); | ||||||||
Msg << "invalid operand in inline asm: '" << AsmStr << "'"; | ||||||||
C.emitError(Loc, Msg.str()); | ||||||||
} | ||||||||
/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
/// instruction, using the specified assembler variant. Targets should | ||||||||
/// override this to format as appropriate for machine specific ExtraCodes | ||||||||
/// or when the arch-independent handling would be too complex otherwise. | ||||||||
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||||||||
const char *ExtraCode, raw_ostream &O) { | ||||||||
AsmOperandErrorCode AsmPrinter::PrintAsmOperand(const MachineInstr *MI, | ||||||||
unsigned OpNo, | ||||||||
const char *ExtraCode, | ||||||||
raw_ostream &O) { | ||||||||
// Does this asm operand have a single letter operand modifier? | ||||||||
if (ExtraCode && ExtraCode[0]) { | ||||||||
if (ExtraCode[1] != 0) return true; // Unknown modifier. | ||||||||
if (ExtraCode[1] != 0) | ||||||||
return AsmOperandErrorCode::UNKNOWN_MODIFIER_ERROR; // Unknown modifier. | ||||||||
|
||||||||
// https://gcc.gnu.org/onlinedocs/gccint/Output-Template.html | ||||||||
const MachineOperand &MO = MI->getOperand(OpNo); | ||||||||
switch (ExtraCode[0]) { | ||||||||
default: | ||||||||
return true; // Unknown modifier. | ||||||||
return AsmOperandErrorCode::UNKNOWN_MODIFIER_ERROR; // Unknown modifier. | ||||||||
case 'a': // Print as memory address. | ||||||||
if (MO.isReg()) { | ||||||||
PrintAsmMemoryOperand(MI, OpNo, nullptr, O); | ||||||||
return false; | ||||||||
return AsmOperandErrorCode::NO_ERROR; | ||||||||
} | ||||||||
[[fallthrough]]; // GCC allows '%a' to behave like '%c' with immediates. | ||||||||
case 'c': // Substitute immediate value without immediate syntax | ||||||||
if (MO.isImm()) { | ||||||||
O << MO.getImm(); | ||||||||
return false; | ||||||||
return AsmOperandErrorCode::NO_ERROR; | ||||||||
} | ||||||||
if (MO.isGlobal()) { | ||||||||
PrintSymbolOperand(MO, O); | ||||||||
return false; | ||||||||
return AsmOperandErrorCode::NO_ERROR; | ||||||||
} | ||||||||
return true; | ||||||||
return AsmOperandErrorCode::OPERAND_ERROR; | ||||||||
case 'n': // Negate the immediate constant. | ||||||||
if (!MO.isImm()) | ||||||||
return true; | ||||||||
return AsmOperandErrorCode::OPERAND_ERROR; | ||||||||
O << -MO.getImm(); | ||||||||
return false; | ||||||||
return AsmOperandErrorCode::NO_ERROR; | ||||||||
case 's': // The GCC deprecated s modifier | ||||||||
if (!MO.isImm()) | ||||||||
return true; | ||||||||
return AsmOperandErrorCode::OPERAND_ERROR; | ||||||||
O << ((32 - MO.getImm()) & 31); | ||||||||
return false; | ||||||||
return AsmOperandErrorCode::NO_ERROR; | ||||||||
} | ||||||||
} | ||||||||
return true; | ||||||||
return AsmOperandErrorCode::OPERAND_ERROR; | ||||||||
} | ||||||||
|
||||||||
bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally the mechanical change to use AsmOperandErrorCode instead of bool should be done first, before the behavior change