Skip to content

Commit 2f94cae

Browse files
ericastorAmanieu
authored andcommitted
[ms] [X86] Use "P" modifier on operands to call instructions in inline X86 assembly.
Summary: This is documented as the appropriate template modifier for call operands. Fixes PR44272, and adds a regression test. Also adds support for operand modifiers in Intel-style inline assembly. Reviewers: rnk Reviewed By: rnk Subscribers: merge_guards_bot, hiraditya, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D71677
1 parent d7cdb43 commit 2f94cae

File tree

13 files changed

+113
-22
lines changed

13 files changed

+113
-22
lines changed

clang/lib/CodeGen/TargetInfo.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,10 @@ static void rewriteInputConstraintReferences(unsigned FirstIn,
11771177
if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
11781178
// We have an operand reference.
11791179
size_t DigitStart = Pos;
1180+
if (AsmString[DigitStart] == '{') {
1181+
OS << '{';
1182+
++DigitStart;
1183+
}
11801184
size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
11811185
if (DigitEnd == std::string::npos)
11821186
DigitEnd = AsmString.size();

clang/test/CodeGen/mozilla-ms-inline-asm.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void invoke(void* that, unsigned methodIndex,
2727
// CHECK-SAME: sub esp,eax
2828
// CHECK-SAME: mov ecx,esp
2929
// CHECK-SAME: push $0
30-
// CHECK-SAME: call dword ptr $2
30+
// CHECK-SAME: call dword ptr ${2:P}
3131
// CHECK-SAME: {{.*}}__MSASMLABEL_.${:uid}__noparams:
3232
// CHECK-SAME: mov ecx,$3
3333
// CHECK-SAME: push ecx

clang/test/CodeGen/ms-inline-asm.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ void t24_helper(void) {}
306306
void t24() {
307307
__asm call t24_helper
308308
// CHECK: t24
309-
// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
309+
// CHECK: call void asm sideeffect inteldialect "call dword ptr ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
310310
}
311311

312312
void t25() {
@@ -681,7 +681,7 @@ void dot_operator(){
681681
void call_clobber() {
682682
__asm call t41
683683
// CHECK-LABEL: define void @call_clobber
684-
// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
684+
// CHECK: call void asm sideeffect inteldialect "call dword ptr ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
685685
}
686686

687687
void xgetbv() {

clang/test/CodeGen/ms-inline-asm.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void test5() {
109109
__asm mov x, eax
110110
// CHECK: call void asm sideeffect inteldialect
111111
// CHECK-SAME: push $0
112-
// CHECK-SAME: call dword ptr $2
112+
// CHECK-SAME: call dword ptr ${2:P}
113113
// CHECK-SAME: mov $1, eax
114114
// CHECK-SAME: "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
115115
}

llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class MCParsedAsmOperand {
7171
/// variable/label? Only valid when parsing MS-style inline assembly.
7272
virtual bool needAddressOf() const { return false; }
7373

74+
/// isCallOperand - Is this an operand of an inline-assembly call instruction?
75+
/// Only valid when parsing MS-style inline assembly.
76+
virtual bool isCallOperand() const { return false; }
77+
7478
/// isOffsetOf - Do we need to emit code to get the offset of the variable,
7579
/// rather then the value of the variable? Only valid when parsing MS-style
7680
/// inline assembly.

llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum AsmRewriteKind {
3535
AOK_Align, // Rewrite align as .align.
3636
AOK_EVEN, // Rewrite even as .even.
3737
AOK_Emit, // Rewrite _emit as .byte.
38+
AOK_CallInput, // Rewrite in terms of ${N:P}.
3839
AOK_Input, // Rewrite in terms of $N.
3940
AOK_Output, // Rewrite in terms of $N.
4041
AOK_SizeDirective, // Add a sizing directive (e.g., dword ptr).
@@ -49,6 +50,7 @@ const char AsmRewritePrecedence [] = {
4950
2, // AOK_EVEN
5051
2, // AOK_Emit
5152
3, // AOK_Input
53+
3, // AOK_CallInput
5254
3, // AOK_Output
5355
5, // AOK_SizeDirective
5456
1, // AOK_Label

llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp

+33-4
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,17 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
207207
}
208208
if (Done) break;
209209

210+
bool HasCurlyBraces = false;
211+
if (*LastEmitted == '{') { // ${variable}
212+
++LastEmitted; // Consume '{' character.
213+
HasCurlyBraces = true;
214+
}
215+
210216
// If we have ${:foo}, then this is not a real operand reference, it is a
211217
// "magic" string reference, just like in .td files. Arrange to call
212218
// PrintSpecial.
213-
if (LastEmitted[0] == '{' && LastEmitted[1] == ':') {
214-
LastEmitted += 2;
219+
if (HasCurlyBraces && LastEmitted[0] == ':') {
220+
++LastEmitted;
215221
const char *StrStart = LastEmitted;
216222
const char *StrEnd = strchr(StrStart, '}');
217223
if (!StrEnd)
@@ -238,6 +244,27 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
238244
report_fatal_error("Invalid $ operand number in inline asm string: '" +
239245
Twine(AsmStr) + "'");
240246

247+
char Modifier[2] = { 0, 0 };
248+
249+
if (HasCurlyBraces) {
250+
// If we have curly braces, check for a modifier character. This
251+
// supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
252+
if (*LastEmitted == ':') {
253+
++LastEmitted; // Consume ':' character.
254+
if (*LastEmitted == 0)
255+
report_fatal_error("Bad ${:} expression in inline asm string: '" +
256+
Twine(AsmStr) + "'");
257+
258+
Modifier[0] = *LastEmitted;
259+
++LastEmitted; // Consume modifier character.
260+
}
261+
262+
if (*LastEmitted != '}')
263+
report_fatal_error("Bad ${} expression in inline asm string: '" +
264+
Twine(AsmStr) + "'");
265+
++LastEmitted; // Consume '}' character.
266+
}
267+
241268
// Okay, we finally have a value number. Ask the target to print this
242269
// operand!
243270
unsigned OpNo = InlineAsm::MIOp_FirstOperand;
@@ -262,9 +289,11 @@ static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI,
262289
++OpNo; // Skip over the ID number.
263290

264291
if (InlineAsm::isMemKind(OpFlags)) {
265-
Error = AP->PrintAsmMemoryOperand(MI, OpNo, /*Modifier*/ nullptr, OS);
292+
Error = AP->PrintAsmMemoryOperand(
293+
MI, OpNo, Modifier[0] ? Modifier : nullptr, OS);
266294
} else {
267-
Error = AP->PrintAsmOperand(MI, OpNo, /*Modifier*/ nullptr, OS);
295+
Error = AP->PrintAsmOperand(MI, OpNo,
296+
Modifier[0] ? Modifier : nullptr, OS);
268297
}
269298
}
270299
if (Error) {

llvm/lib/MC/MCParser/AsmParser.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -5728,7 +5728,10 @@ bool AsmParser::parseMSInlineAsm(
57285728
InputDecls.push_back(OpDecl);
57295729
InputDeclsAddressOf.push_back(Operand.needAddressOf());
57305730
InputConstraints.push_back(Operand.getConstraint().str());
5731-
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
5731+
if (Operand.isCallOperand())
5732+
AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());
5733+
else
5734+
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
57325735
}
57335736
}
57345737

@@ -5818,6 +5821,9 @@ bool AsmParser::parseMSInlineAsm(
58185821
case AOK_Input:
58195822
OS << '$' << InputIdx++;
58205823
break;
5824+
case AOK_CallInput:
5825+
OS << "${" << InputIdx++ << ":P}";
5826+
break;
58215827
case AOK_Output:
58225828
OS << '$' << OutputIdx++;
58235829
break;

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,15 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
28552855
}
28562856
}
28572857

2858+
// Mark the operands of a call instruction. These need to be handled
2859+
// differently when referenced in MS-style inline assembly.
2860+
if (Name.startswith("call") || Name.startswith("lcall")) {
2861+
for (size_t i = 1; i < Operands.size(); ++i) {
2862+
X86Operand &Op = static_cast<X86Operand &>(*Operands[i]);
2863+
Op.setCallOperand(true);
2864+
}
2865+
}
2866+
28582867
if (Flags)
28592868
Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc));
28602869
return false;

llvm/lib/Target/X86/AsmParser/X86Operand.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct X86Operand final : public MCParsedAsmOperand {
3636
StringRef SymName;
3737
void *OpDecl;
3838
bool AddressOf;
39+
bool CallOperand;
3940

4041
struct TokOp {
4142
const char *Data;
@@ -77,7 +78,7 @@ struct X86Operand final : public MCParsedAsmOperand {
7778
};
7879

7980
X86Operand(KindTy K, SMLoc Start, SMLoc End)
80-
: Kind(K), StartLoc(Start), EndLoc(End) {}
81+
: Kind(K), StartLoc(Start), EndLoc(End), CallOperand(false) {}
8182

8283
StringRef getSymName() override { return SymName; }
8384
void *getOpDecl() override { return OpDecl; }
@@ -277,6 +278,9 @@ struct X86Operand final : public MCParsedAsmOperand {
277278
return AddressOf;
278279
}
279280

281+
bool isCallOperand() const override { return CallOperand; }
282+
void setCallOperand(bool IsCallOperand) { CallOperand = IsCallOperand; }
283+
280284
bool isMem() const override { return Kind == Memory; }
281285
bool isMemUnsized() const {
282286
return Kind == Memory && Mem.Size == 0;

llvm/lib/Target/X86/X86AsmPrinter.cpp

+26-11
Original file line numberDiff line numberDiff line change
@@ -336,14 +336,22 @@ void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo,
336336
PrintLeaMemReference(MI, OpNo, O, Modifier);
337337
}
338338

339+
339340
void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
340-
unsigned OpNo, raw_ostream &O) {
341+
unsigned OpNo, raw_ostream &O,
342+
const char *Modifier) {
341343
const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);
342344
unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();
343345
const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);
344346
const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);
345347
const MachineOperand &SegReg = MI->getOperand(OpNo + X86::AddrSegmentReg);
346348

349+
// If we really don't want to print out (rip), don't.
350+
bool HasBaseReg = BaseReg.getReg() != 0;
351+
if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") &&
352+
BaseReg.getReg() == X86::RIP)
353+
HasBaseReg = false;
354+
347355
// If this has a segment register, print it.
348356
if (SegReg.getReg()) {
349357
PrintOperand(MI, OpNo + X86::AddrSegmentReg, O);
@@ -353,7 +361,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
353361
O << '[';
354362

355363
bool NeedPlus = false;
356-
if (BaseReg.getReg()) {
364+
if (HasBaseReg) {
357365
PrintOperand(MI, OpNo + X86::AddrBaseReg, O);
358366
NeedPlus = true;
359367
}
@@ -371,7 +379,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
371379
PrintOperand(MI, OpNo + X86::AddrDisp, O);
372380
} else {
373381
int64_t DispVal = DispSpec.getImm();
374-
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) {
382+
if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {
375383
if (NeedPlus) {
376384
if (DispVal > 0)
377385
O << " + ";
@@ -524,11 +532,6 @@ bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
524532
bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
525533
const char *ExtraCode,
526534
raw_ostream &O) {
527-
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
528-
PrintIntelMemReference(MI, OpNo, O);
529-
return false;
530-
}
531-
532535
if (ExtraCode && ExtraCode[0]) {
533536
if (ExtraCode[1] != 0) return true; // Unknown modifier.
534537

@@ -542,14 +545,26 @@ bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
542545
// These only apply to registers, ignore on mem.
543546
break;
544547
case 'H':
545-
PrintMemReference(MI, OpNo, O, "H");
548+
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
549+
return true; // Unsupported modifier in Intel inline assembly.
550+
} else {
551+
PrintMemReference(MI, OpNo, O, "H");
552+
}
546553
return false;
547554
case 'P': // Don't print @PLT, but do print as memory.
548-
PrintMemReference(MI, OpNo, O, "no-rip");
555+
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
556+
PrintIntelMemReference(MI, OpNo, O, "no-rip");
557+
} else {
558+
PrintMemReference(MI, OpNo, O, "no-rip");
559+
}
549560
return false;
550561
}
551562
}
552-
PrintMemReference(MI, OpNo, O, nullptr);
563+
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
564+
PrintIntelMemReference(MI, OpNo, O, nullptr);
565+
} else {
566+
PrintMemReference(MI, OpNo, O, nullptr);
567+
}
553568
return false;
554569
}
555570

llvm/lib/Target/X86/X86AsmPrinter.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
112112
void PrintMemReference(const MachineInstr *MI, unsigned OpNo, raw_ostream &O,
113113
const char *Modifier);
114114
void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo,
115-
raw_ostream &O);
115+
raw_ostream &O, const char *Modifier);
116116

117117
public:
118118
X86AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: llc < %s -mtriple=i686-- | FileCheck %s
2+
; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s
3+
4+
define void @func() {
5+
entry:
6+
ret void
7+
}
8+
9+
define void @main() {
10+
entry:
11+
call void asm sideeffect inteldialect "call ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void ()* @func)
12+
ret void
13+
; CHECK-LABEL: main:
14+
; CHECK: {{## InlineAsm Start|#APP}}
15+
; CHECK: {{call(l|q) func$}}
16+
; CHECK: {{## InlineAsm End|#NO_APP}}
17+
; CHECK: ret{{l|q}}
18+
}

0 commit comments

Comments
 (0)