Skip to content

Commit dc5b614

Browse files
committed
[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 0b38af8 commit dc5b614

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
@@ -1187,6 +1187,10 @@ static void rewriteInputConstraintReferences(unsigned FirstIn,
11871187
if (NumDollars % 2 != 0 && Pos < AsmString.size()) {
11881188
// We have an operand reference.
11891189
size_t DigitStart = Pos;
1190+
if (AsmString[DigitStart] == '{') {
1191+
OS << '{';
1192+
++DigitStart;
1193+
}
11901194
size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart);
11911195
if (DigitEnd == std::string::npos)
11921196
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() {
@@ -689,7 +689,7 @@ void dot_operator(){
689689
void call_clobber() {
690690
__asm call t41
691691
// CHECK-LABEL: define void @call_clobber
692-
// CHECK: call void asm sideeffect inteldialect "call dword ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
692+
// CHECK: call void asm sideeffect inteldialect "call dword ptr ${0:P}", "*m,~{dirflag},~{fpsr},~{flags}"(void (i16)* @t41)
693693
}
694694

695695
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
@@ -5839,7 +5839,10 @@ bool AsmParser::parseMSInlineAsm(
58395839
InputDecls.push_back(OpDecl);
58405840
InputDeclsAddressOf.push_back(Operand.needAddressOf());
58415841
InputConstraints.push_back(Operand.getConstraint().str());
5842-
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
5842+
if (Operand.isCallOperand())
5843+
AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());
5844+
else
5845+
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
58435846
}
58445847
}
58455848

@@ -5929,6 +5932,9 @@ bool AsmParser::parseMSInlineAsm(
59295932
case AOK_Input:
59305933
OS << '$' << InputIdx++;
59315934
break;
5935+
case AOK_CallInput:
5936+
OS << "${" << InputIdx++ << ":P}";
5937+
break;
59325938
case AOK_Output:
59335939
OS << '$' << OutputIdx++;
59345940
break;

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

+9
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,15 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
28662866
}
28672867
}
28682868

2869+
// Mark the operands of a call instruction. These need to be handled
2870+
// differently when referenced in MS-style inline assembly.
2871+
if (Name.startswith("call") || Name.startswith("lcall")) {
2872+
for (size_t i = 1; i < Operands.size(); ++i) {
2873+
X86Operand &Op = static_cast<X86Operand &>(*Operands[i]);
2874+
Op.setCallOperand(true);
2875+
}
2876+
}
2877+
28692878
if (Flags)
28702879
Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc));
28712880
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; }
@@ -286,6 +287,9 @@ struct X86Operand final : public MCParsedAsmOperand {
286287
return AddressOf;
287288
}
288289

290+
bool isCallOperand() const override { return CallOperand; }
291+
void setCallOperand(bool IsCallOperand) { CallOperand = IsCallOperand; }
292+
289293
bool isMem() const override { return Kind == Memory; }
290294
bool isMemUnsized() const {
291295
return Kind == Memory && Mem.Size == 0;

llvm/lib/Target/X86/X86AsmPrinter.cpp

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

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

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

356364
bool NeedPlus = false;
357-
if (BaseReg.getReg()) {
365+
if (HasBaseReg) {
358366
PrintOperand(MI, OpNo + X86::AddrBaseReg, O);
359367
NeedPlus = true;
360368
}
@@ -372,7 +380,7 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
372380
PrintOperand(MI, OpNo + X86::AddrDisp, O);
373381
} else {
374382
int64_t DispVal = DispSpec.getImm();
375-
if (DispVal || (!IndexReg.getReg() && !BaseReg.getReg())) {
383+
if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {
376384
if (NeedPlus) {
377385
if (DispVal > 0)
378386
O << " + ";
@@ -525,11 +533,6 @@ bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
525533
bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
526534
const char *ExtraCode,
527535
raw_ostream &O) {
528-
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
529-
PrintIntelMemReference(MI, OpNo, O);
530-
return false;
531-
}
532-
533536
if (ExtraCode && ExtraCode[0]) {
534537
if (ExtraCode[1] != 0) return true; // Unknown modifier.
535538

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

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)