Skip to content
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

Inline assembly changes for RFC 2873 #52

Merged
merged 2 commits into from
May 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,10 @@ static void rewriteInputConstraintReferences(unsigned FirstIn,
if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
// We have an operand reference.
size_t DigitStart = Pos;
if (AsmString[DigitStart] == '{') {
OS << '{';
++DigitStart;
}
size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
if (DigitEnd == std::string::npos)
DigitEnd = AsmString.size();
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/mozilla-ms-inline-asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void invoke(void* that, unsigned methodIndex,
// CHECK-SAME: sub esp,eax
// CHECK-SAME: mov ecx,esp
// CHECK-SAME: push $0
// CHECK-SAME: call dword ptr $2
// CHECK-SAME: call dword ptr ${2:P}
// CHECK-SAME: {{.*}}__MSASMLABEL_.${:uid}__noparams:
// CHECK-SAME: mov ecx,$3
// CHECK-SAME: push ecx
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/ms-inline-asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ void t24_helper(void) {}
void t24() {
__asm call t24_helper
// CHECK: t24
// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
// CHECK: call void asm sideeffect inteldialect "call dword ptr ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
}

void t25() {
Expand Down Expand Up @@ -681,7 +681,7 @@ void dot_operator(){
void call_clobber() {
__asm call t41
// CHECK-LABEL: define void @call_clobber
// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
// CHECK: call void asm sideeffect inteldialect "call dword ptr ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
}

void xgetbv() {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/ms-inline-asm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void test5() {
__asm mov x, eax
// CHECK: call void asm sideeffect inteldialect
// CHECK-SAME: push $0
// CHECK-SAME: call dword ptr $2
// CHECK-SAME: call dword ptr ${2:P}
// CHECK-SAME: mov $1, eax
// CHECK-SAME: "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class MCParsedAsmOperand {
/// variable/label? Only valid when parsing MS-style inline assembly.
virtual bool needAddressOf() const { return false; }

/// isCallOperand - Is this an operand of an inline-assembly call instruction?
/// Only valid when parsing MS-style inline assembly.
virtual bool isCallOperand() const { return false; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also an ABI break.


/// isOffsetOf - Do we need to emit code to get the offset of the variable,
/// rather then the value of the variable? Only valid when parsing MS-style
/// inline assembly.
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum AsmRewriteKind {
AOK_Align, // Rewrite align as .align.
AOK_EVEN, // Rewrite even as .even.
AOK_Emit, // Rewrite _emit as .byte.
AOK_CallInput, // Rewrite in terms of ${N:P}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an ABI break, if anyone considers backporting to their own LLVM, but I think it's fine in the context of Rust's own use of LLVM.

AOK_Input, // Rewrite in terms of $N.
AOK_Output, // Rewrite in terms of $N.
AOK_SizeDirective, // Add a sizing directive (e.g., dword ptr).
Expand All @@ -49,6 +50,7 @@ const char AsmRewritePrecedence [] = {
2, // AOK_EVEN
2, // AOK_Emit
3, // AOK_Input
3, // AOK_CallInput
3, // AOK_Output
5, // AOK_SizeDirective
1, // AOK_Label
Expand Down
37 changes: 33 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,17 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
}
if (Done) break;

bool HasCurlyBraces = false;
if (*LastEmitted == '{') { // ${variable}
++LastEmitted; // Consume '{' character.
HasCurlyBraces = true;
}

// 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;
if (HasCurlyBraces && LastEmitted[0] == ':') {
++LastEmitted;
const char *StrStart = LastEmitted;
const char *StrEnd = strchr(StrStart, '}');
if (!StrEnd)
Expand All @@ -238,6 +244,27 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
report_fatal_error("Invalid $ operand number in inline asm string: '" +
Twine(AsmStr) + "'");

char Modifier[2] = { 0, 0 };

if (HasCurlyBraces) {
// If we have curly braces, check for a modifier character. This
// supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
if (*LastEmitted == ':') {
++LastEmitted; // Consume ':' character.
if (*LastEmitted == 0)
report_fatal_error("Bad ${:} expression in inline asm string: '" +
Twine(AsmStr) + "'");

Modifier[0] = *LastEmitted;
++LastEmitted; // Consume modifier character.
}

if (*LastEmitted != '}')
report_fatal_error("Bad ${} expression in inline asm string: '" +
Twine(AsmStr) + "'");
++LastEmitted; // Consume '}' character.
}

// Okay, we finally have a value number. Ask the target to print this
// operand!
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
Expand All @@ -262,9 +289,11 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
++OpNo; // Skip over the ID number.

if (InlineAsm::isMemKind(OpFlags)) {
Error = AP->PrintAsmMemoryOperand(MI, OpNo, /*Modifier*/ nullptr, OS);
Error = AP->PrintAsmMemoryOperand(
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
} else {
Error = AP->PrintAsmOperand(MI, OpNo, /*Modifier*/ nullptr, OS);
Error = AP->PrintAsmOperand(MI, OpNo,
Modifier[0] ? Modifier : nullptr, OS);
}
}
if (Error) {
Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5728,7 +5728,10 @@ bool AsmParser::parseMSInlineAsm(
InputDecls.push_back(OpDecl);
InputDeclsAddressOf.push_back(Operand.needAddressOf());
InputConstraints.push_back(Operand.getConstraint().str());
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
if (Operand.isCallOperand())
AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());
else
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
}
}

Expand Down Expand Up @@ -5818,6 +5821,9 @@ bool AsmParser::parseMSInlineAsm(
case AOK_Input:
OS << '$' << InputIdx++;
break;
case AOK_CallInput:
OS << "${" << InputIdx++ << ":P}";
break;
case AOK_Output:
OS << '$' << OutputIdx++;
break;
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2855,6 +2855,15 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
}

// Mark the operands of a call instruction. These need to be handled
// differently when referenced in MS-style inline assembly.
if (Name.startswith("call") || Name.startswith("lcall")) {
for (size_t i = 1; i < Operands.size(); ++i) {
X86Operand &Op = static_cast<X86Operand &>(*Operands[i]);
Op.setCallOperand(true);
}
}

if (Flags)
Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc));
return false;
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/X86/AsmParser/X86Operand.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct X86Operand final : public MCParsedAsmOperand {
StringRef SymName;
void *OpDecl;
bool AddressOf;
bool CallOperand;

struct TokOp {
const char *Data;
Expand Down Expand Up @@ -77,7 +78,7 @@ struct X86Operand final : public MCParsedAsmOperand {
};

X86Operand(KindTy K, SMLoc Start, SMLoc End)
: Kind(K), StartLoc(Start), EndLoc(End) {}
: Kind(K), StartLoc(Start), EndLoc(End), CallOperand(false) {}

StringRef getSymName() override { return SymName; }
void *getOpDecl() override { return OpDecl; }
Expand Down Expand Up @@ -277,6 +278,9 @@ struct X86Operand final : public MCParsedAsmOperand {
return AddressOf;
}

bool isCallOperand() const override { return CallOperand; }
void setCallOperand(bool IsCallOperand) { CallOperand = IsCallOperand; }

bool isMem() const override { return Kind == Memory; }
bool isMemUnsized() const {
return Kind == Memory && Mem.Size == 0;
Expand Down
83 changes: 71 additions & 12 deletions llvm/lib/Target/X86/X86AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,22 @@ void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo,
PrintLeaMemReference(MI, OpNo, O, Modifier);
}


void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
unsigned OpNo, raw_ostream &O) {
unsigned OpNo, raw_ostream &O,
const char *Modifier) {
const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);
unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();
const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);
const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);
const MachineOperand &SegReg = MI->getOperand(OpNo + X86::AddrSegmentReg);

// If we really don't want to print out (rip), don't.
bool HasBaseReg = BaseReg.getReg() != 0;
if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") &&
BaseReg.getReg() == X86::RIP)
HasBaseReg = false;

// If this has a segment register, print it.
if (SegReg.getReg()) {
PrintOperand(MI, OpNo + X86::AddrSegmentReg, O);
Expand All @@ -353,7 +361,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
O << '[';

bool NeedPlus = false;
if (BaseReg.getReg()) {
if (HasBaseReg) {
PrintOperand(MI, OpNo + X86::AddrBaseReg, O);
NeedPlus = true;
}
Expand All @@ -371,7 +379,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
PrintOperand(MI, OpNo + X86::AddrDisp, O);
} else {
int64_t DispVal = DispSpec.getImm();
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) {
if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {
if (NeedPlus) {
if (DispVal > 0)
O << " + ";
Expand All @@ -389,7 +397,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
static bool printAsmMRegister(X86AsmPrinter &P, const MachineOperand &MO,
char Mode, raw_ostream &O) {
unsigned Reg = MO.getReg();
bool EmitPercent = true;
bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;

if (!X86::GR8RegClass.contains(Reg) &&
!X86::GR16RegClass.contains(Reg) &&
Expand Down Expand Up @@ -428,6 +436,42 @@ static bool printAsmMRegister(X86AsmPrinter &P, const MachineOperand &MO,
return false;
}

static bool printAsmVRegister(X86AsmPrinter &P, const MachineOperand &MO,
char Mode, raw_ostream &O) {
unsigned Reg = MO.getReg();
bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;

unsigned Index;
if (X86::VR128XRegClass.contains(Reg))
Index = Reg - X86::XMM0;
else if (X86::VR256XRegClass.contains(Reg))
Index = Reg - X86::YMM0;
else if (X86::VR512RegClass.contains(Reg))
Index = Reg - X86::ZMM0;
else
return true;

switch (Mode) {
default: // Unknown mode.
return true;
case 'x': // Print V4SFmode register
Reg = X86::XMM0 + Index;
break;
case 't': // Print V8SFmode register
Reg = X86::YMM0 + Index;
break;
case 'g': // Print V16SFmode register
Reg = X86::ZMM0 + Index;
break;
}

if (EmitPercent)
O << '%';

O << X86ATTInstPrinter::getRegisterName(Reg);
return false;
}

/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
Expand Down Expand Up @@ -502,6 +546,14 @@ bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
PrintOperand(MI, OpNo, O);
return false;

case 'x': // Print V4SFmode register
case 't': // Print V8SFmode register
case 'g': // Print V16SFmode register
if (MO.isReg())
return printAsmVRegister(*this, MO, ExtraCode[0], O);
PrintOperand(MI, OpNo, O);
return false;

case 'P': // This is the operand of a call, treat specially.
PrintPCRelImm(MI, OpNo, O);
return false;
Expand All @@ -524,11 +576,6 @@ bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode,
raw_ostream &O) {
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
PrintIntelMemReference(MI, OpNo, O);
return false;
}

if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.

Expand All @@ -542,14 +589,26 @@ bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
// These only apply to registers, ignore on mem.
break;
case 'H':
PrintMemReference(MI, OpNo, O, "H");
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
return true; // Unsupported modifier in Intel inline assembly.
} else {
PrintMemReference(MI, OpNo, O, "H");
}
return false;
case 'P': // Don't print @PLT, but do print as memory.
PrintMemReference(MI, OpNo, O, "no-rip");
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
PrintIntelMemReference(MI, OpNo, O, "no-rip");
} else {
PrintMemReference(MI, OpNo, O, "no-rip");
}
return false;
}
}
PrintMemReference(MI, OpNo, O, nullptr);
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
PrintIntelMemReference(MI, OpNo, O, nullptr);
} else {
PrintMemReference(MI, OpNo, O, nullptr);
}
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/X86/X86AsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
void PrintMemReference(const MachineInstr *MI, unsigned OpNo, raw_ostream &O,
const char *Modifier);
void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O);
raw_ostream &O, const char *Modifier);

public:
X86AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
Expand Down
Loading