Skip to content

Commit

Permalink
Merge pull request #52 from Amanieu/rust-asm3
Browse files Browse the repository at this point in the history
Inline assembly changes for RFC 2873
  • Loading branch information
cuviper authored May 1, 2020
2 parents 94c0e0c + 66f695b commit e7aa4d5
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 25 deletions.
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; }

/// 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}.
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

0 comments on commit e7aa4d5

Please sign in to comment.