Skip to content

Commit ee08897

Browse files
committed
Reland "Fix miscompile of MS inline assembly with stack realignment"
This re-lands commit r196876, which was reverted in r196879. The tests have been fixed to pass on platforms with a stack alignment larger than 4. Update to clang side tests will land shortly. llvm-svn: 196939
1 parent 6f2f390 commit ee08897

File tree

10 files changed

+108
-35
lines changed

10 files changed

+108
-35
lines changed

llvm/include/llvm/CodeGen/MachineFrameInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ class MachineFrameInfo {
223223
/// Whether the "realign-stack" option is on.
224224
bool RealignOption;
225225

226+
/// True if the function includes inline assembly that adjusts the stack
227+
/// pointer.
228+
bool HasInlineAsmWithSPAdjust;
229+
226230
const TargetFrameLowering *getFrameLowering() const;
227231
public:
228232
explicit MachineFrameInfo(const TargetMachine &TM, bool RealignOpt)
@@ -451,6 +455,10 @@ class MachineFrameInfo {
451455
bool hasCalls() const { return HasCalls; }
452456
void setHasCalls(bool V) { HasCalls = V; }
453457

458+
/// Returns true if the function contains any stack-adjusting inline assembly.
459+
bool hasInlineAsmWithSPAdjust() const { return HasInlineAsmWithSPAdjust; }
460+
void setHasInlineAsmWithSPAdjust(bool B) { HasInlineAsmWithSPAdjust = B; }
461+
454462
/// getMaxCallFrameSize - Return the maximum size of a call frame that must be
455463
/// allocated for an outgoing function call. This is only available if
456464
/// CallFrameSetup/Destroy pseudo instructions are used by the target, and

llvm/include/llvm/CodeGen/MachineFunction.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ class MachineFunction {
131131
/// about the control flow of such functions.
132132
bool ExposesReturnsTwice;
133133

134-
/// True if the function includes MS-style inline assembly.
135-
bool HasMSInlineAsm;
134+
/// True if the function includes any inline assembly.
135+
bool HasInlineAsm;
136136

137137
MachineFunction(const MachineFunction &) LLVM_DELETED_FUNCTION;
138138
void operator=(const MachineFunction&) LLVM_DELETED_FUNCTION;
@@ -218,15 +218,14 @@ class MachineFunction {
218218
ExposesReturnsTwice = B;
219219
}
220220

221-
/// Returns true if the function contains any MS-style inline assembly.
222-
bool hasMSInlineAsm() const {
223-
return HasMSInlineAsm;
221+
/// Returns true if the function contains any inline assembly.
222+
bool hasInlineAsm() const {
223+
return HasInlineAsm;
224224
}
225225

226-
/// Set a flag that indicates that the function contains MS-style inline
227-
/// assembly.
228-
void setHasMSInlineAsm(bool B) {
229-
HasMSInlineAsm = B;
226+
/// Set a flag that indicates that the function contains inline assembly.
227+
void setHasInlineAsm(bool B) {
228+
HasInlineAsm = B;
230229
}
231230

232231
/// getInfo - Keep track of various per-function pieces of information for

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,12 +851,20 @@ void RegsForValue::AddInlineAsmOperands(unsigned Code, bool HasMatching,
851851
SDValue Res = DAG.getTargetConstant(Flag, MVT::i32);
852852
Ops.push_back(Res);
853853

854+
unsigned SP = TLI.getStackPointerRegisterToSaveRestore();
854855
for (unsigned Value = 0, Reg = 0, e = ValueVTs.size(); Value != e; ++Value) {
855856
unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVTs[Value]);
856857
MVT RegisterVT = RegVTs[Value];
857858
for (unsigned i = 0; i != NumRegs; ++i) {
858859
assert(Reg < Regs.size() && "Mismatch in # registers expected");
859-
Ops.push_back(DAG.getRegister(Regs[Reg++], RegisterVT));
860+
unsigned TheReg = Regs[Reg++];
861+
Ops.push_back(DAG.getRegister(TheReg, RegisterVT));
862+
863+
// Notice if we clobbered the stack pointer. Yes, inline asm can do this.
864+
if (TheReg == SP && Code == InlineAsm::Kind_Clobber) {
865+
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
866+
MFI->setHasInlineAsmWithSPAdjust(true);
867+
}
860868
}
861869
}
862870
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,9 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
428428

429429
SDB->init(GFI, *AA, LibInfo);
430430

431-
MF->setHasMSInlineAsm(false);
431+
MF->setHasInlineAsm(false);
432+
MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false);
433+
432434
SelectAllBasicBlocks(Fn);
433435

434436
// If the first basic block in the function has live ins that need to be
@@ -512,7 +514,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
512514
for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E;
513515
++I) {
514516

515-
if (MFI->hasCalls() && MF->hasMSInlineAsm())
517+
if (MFI->hasCalls() && MF->hasInlineAsm())
516518
break;
517519

518520
const MachineBasicBlock *MBB = I;
@@ -523,8 +525,8 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
523525
II->isStackAligningInlineAsm()) {
524526
MFI->setHasCalls(true);
525527
}
526-
if (II->isMSInlineAsm()) {
527-
MF->setHasMSInlineAsm(true);
528+
if (II->isInlineAsm()) {
529+
MF->setHasInlineAsm(true);
528530
}
529531
}
530532
}

llvm/lib/MC/MCParser/AsmParser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4208,6 +4208,11 @@ bool AsmParser::parseMSInlineAsm(
42084208
AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size()));
42094209
}
42104210
}
4211+
4212+
// Consider implicit defs to be clobbers. Think of cpuid and push.
4213+
const uint16_t *ImpDefs = Desc.getImplicitDefs();
4214+
for (unsigned I = 0, E = Desc.getNumImplicitDefs(); I != E; ++I)
4215+
ClobberRegs.push_back(ImpDefs[I]);
42114216
}
42124217

42134218
// Set the number of Outputs and Inputs.

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF) const {
5050
return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
5151
RegInfo->needsStackRealignment(MF) ||
5252
MFI->hasVarSizedObjects() ||
53-
MFI->isFrameAddressTaken() || MF.hasMSInlineAsm() ||
53+
MFI->isFrameAddressTaken() || MFI->hasInlineAsmWithSPAdjust() ||
5454
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
5555
MMI.callsUnwindInit() || MMI.callsEHReturn());
5656
}

llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
347347
"Stack realignment in presence of dynamic allocas is not supported with"
348348
"this calling convention.");
349349

350+
// FIXME: Do a proper analysis of the inline asm to see if it actually
351+
// conflicts with the base register we chose.
352+
if (MF.hasInlineAsm())
353+
report_fatal_error("Stack realignment in presence of dynamic stack "
354+
"adjustments is not supported with inline assembly.");
355+
350356
for (MCSubRegIterator I(getBaseRegister(), this, /*IncludeSelf=*/true);
351357
I.isValid(); ++I)
352358
Reserved.set(*I);
@@ -403,18 +409,15 @@ bool X86RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
403409
if (!EnableBasePointer)
404410
return false;
405411

406-
// When we need stack realignment and there are dynamic allocas, we can't
407-
// reference off of the stack pointer, so we reserve a base pointer.
408-
//
409-
// This is also true if the function contain MS-style inline assembly. We
410-
// do this because if any stack changes occur in the inline assembly, e.g.,
411-
// "pusha", then any C local variable or C argument references in the
412-
// inline assembly will be wrong because the SP is not properly tracked.
413-
if ((needsStackRealignment(MF) && MFI->hasVarSizedObjects()) ||
414-
MF.hasMSInlineAsm())
415-
return true;
416-
417-
return false;
412+
// When we need stack realignment, we can't address the stack from the frame
413+
// pointer. When we have dynamic allocas or stack-adjusting inline asm, we
414+
// can't address variables from the stack pointer. MS inline asm can
415+
// reference locals while also adjusting the stack pointer. When we can't
416+
// use both the SP and the FP, we need a separate base pointer register.
417+
bool CantUseFP = needsStackRealignment(MF);
418+
bool CantUseSP =
419+
MFI->hasVarSizedObjects() || MFI->hasInlineAsmWithSPAdjust();
420+
return CantUseFP && CantUseSP;
418421
}
419422

420423
bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
2+
3+
; We don't currently support realigning the stack and adjusting the stack
4+
; pointer in inline asm. This commonly happens in MS inline assembly using
5+
; push and pop.
6+
7+
; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly
8+
9+
define i32 @foo() {
10+
entry:
11+
%r = alloca i32, align 16
12+
store i32 -1, i32* %r, align 16
13+
call void asm sideeffect inteldialect "push esi\0A\09xor esi, esi\0A\09mov dword ptr $0, esi\0A\09pop esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r)
14+
%0 = load i32* %r, align 16
15+
ret i32 %0
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
2+
3+
; We don't currently support realigning the stack and adjusting the stack
4+
; pointer in inline asm. This can even happen in GNU asm.
5+
6+
; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly
7+
8+
define i32 @foo() {
9+
entry:
10+
%r = alloca i32, align 16
11+
store i32 -1, i32* %r, align 16
12+
call void asm sideeffect "push %esi\0A\09xor %esi, %esi\0A\09mov %esi, $0\0A\09pop %esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r)
13+
%0 = load i32* %r, align 16
14+
ret i32 %0
15+
}

llvm/test/CodeGen/X86/ms-inline-asm.ll

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ entry:
55
%0 = tail call i32 asm sideeffect inteldialect "mov eax, $1\0A\09mov $0, eax", "=r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32 1) nounwind
66
ret i32 %0
77
; CHECK: t1
8-
; CHECK: movl %esp, %ebp
98
; CHECK: {{## InlineAsm Start|#APP}}
109
; CHECK: .intel_syntax
1110
; CHECK: mov eax, ecx
@@ -19,7 +18,6 @@ entry:
1918
call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
2019
ret void
2120
; CHECK: t2
22-
; CHECK: movl %esp, %ebp
2321
; CHECK: {{## InlineAsm Start|#APP}}
2422
; CHECK: .intel_syntax
2523
; CHECK: mov eax, 1
@@ -34,7 +32,6 @@ entry:
3432
call void asm sideeffect inteldialect "mov eax, DWORD PTR [$0]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %V.addr) nounwind
3533
ret void
3634
; CHECK: t3
37-
; CHECK: movl %esp, %ebp
3835
; CHECK: {{## InlineAsm Start|#APP}}
3936
; CHECK: .intel_syntax
4037
; CHECK: mov eax, DWORD PTR {{[[esp]}}
@@ -56,7 +53,6 @@ entry:
5653
%0 = load i32* %b1, align 4
5754
ret i32 %0
5855
; CHECK: t18
59-
; CHECK: movl %esp, %ebp
6056
; CHECK: {{## InlineAsm Start|#APP}}
6157
; CHECK: .intel_syntax
6258
; CHECK: lea ebx, foo
@@ -76,7 +72,6 @@ entry:
7672
call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(void ()* @t19_helper) nounwind
7773
ret void
7874
; CHECK-LABEL: t19:
79-
; CHECK: movl %esp, %ebp
8075
; CHECK: movl ${{_?}}t19_helper, %eax
8176
; CHECK: {{## InlineAsm Start|#APP}}
8277
; CHECK: .intel_syntax
@@ -95,16 +90,38 @@ entry:
9590
%0 = load i32** %res, align 4
9691
ret i32* %0
9792
; CHECK-LABEL: t30:
98-
; CHECK: movl %esp, %ebp
9993
; CHECK: {{## InlineAsm Start|#APP}}
10094
; CHECK: .intel_syntax
10195
; CHECK: lea edi, dword ptr [{{_?}}results]
10296
; CHECK: .att_syntax
10397
; CHECK: {{## InlineAsm End|#NO_APP}}
10498
; CHECK: {{## InlineAsm Start|#APP}}
10599
; CHECK: .intel_syntax
106-
; CHECK: mov dword ptr [esi], edi
100+
; CHECK: mov dword ptr [esp], edi
101+
; CHECK: .att_syntax
102+
; CHECK: {{## InlineAsm End|#NO_APP}}
103+
; CHECK: movl (%esp), %eax
104+
}
105+
106+
; Stack realignment plus MS inline asm that does *not* adjust the stack is no
107+
; longer an error.
108+
109+
define i32 @t31() {
110+
entry:
111+
%val = alloca i32, align 64
112+
store i32 -1, i32* %val, align 64
113+
call void asm sideeffect inteldialect "mov dword ptr $0, esp", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %val) #1
114+
%sp = load i32* %val, align 64
115+
ret i32 %sp
116+
; CHECK-LABEL: t31:
117+
; CHECK: pushl %ebp
118+
; CHECK: movl %esp, %ebp
119+
; CHECK: andl $-64, %esp
120+
; CHECK: {{## InlineAsm Start|#APP}}
121+
; CHECK: .intel_syntax
122+
; CHECK: mov dword ptr [esp], esp
107123
; CHECK: .att_syntax
108124
; CHECK: {{## InlineAsm End|#NO_APP}}
109-
; CHECK: movl (%esi), %eax
125+
; CHECK: movl (%esp), %eax
126+
; CHECK: ret
110127
}

0 commit comments

Comments
 (0)