the operand. (The behavior for relocatable symbol expressions is a
target-specific behavior for this typically target-independent modifier)
- ``H``: Print a memory reference with additional offset +8.
-- ``P``: Print a memory reference or operand for use as the argument of a call
- instruction. (E.g. omit ``(rip)``, even though it's PC-relative.)
+- ``P``: Print a memory reference used as the argument of a call instruction or
+ used with explicit base reg and index reg as its offset. So it can not use
+ additional regs to present the memory reference. (E.g. omit ``(rip)``, even
+ though it's PC-relative.)
XCore:
short BracCount;
bool MemExpr;
bool OffsetOperator;
+ bool AttachToOperandIdx;
+ bool IsPIC;
SMLoc OffsetOperatorLoc;
AsmTypeInfo CurType;
IntelExprStateMachine()
: State(IES_INIT), PrevState(IES_ERROR), BaseReg(0), IndexReg(0),
TmpReg(0), Scale(0), Imm(0), Sym(nullptr), BracCount(0),
- MemExpr(false), OffsetOperator(false) {}
+ MemExpr(false), OffsetOperator(false), AttachToOperandIdx(false),
+ IsPIC(false) {}
void addImm(int64_t imm) { Imm += imm; }
short getBracCount() const { return BracCount; }
bool isValidEndState() const {
return State == IES_RBRAC || State == IES_INTEGER;
}
+
+ // Is the intel expression appended after an operand index.
+ // [OperandIdx][Intel Expression]
+ // This is neccessary for checking if it is an independent
+ // intel expression at back end when parse inline asm.
+ void setAppendAfterOperand() { AttachToOperandIdx = true; }
+
+ bool isPIC() const { return IsPIC; }
+ void setPIC() { IsPIC = true; }
+
bool hadError() const { return State == IES_ERROR; }
const InlineAsmIdentifierInfo &getIdentifierInfo() const { return Info; }
+ bool regsUseUpError(StringRef &ErrMsg) {
+ // This case mostly happen in inline asm, e.g. Arr[BaseReg + IndexReg]
+ // can not intruduce additional register in inline asm in PIC model.
+ if (IsPIC && AttachToOperandIdx)
+ ErrMsg = "Don't use 2 or more regs for mem offset in PIC model!";
+ else
+ ErrMsg = "BaseReg/IndexReg already set!";
+ return true;
+ }
+
void onOr() {
IntelExprState CurrState = State;
switch (State) {
if (!BaseReg) {
BaseReg = TmpReg;
} else {
- if (IndexReg) {
- ErrMsg = "BaseReg/IndexReg already set!";
- return true;
- }
+ if (IndexReg)
+ return regsUseUpError(ErrMsg);
IndexReg = TmpReg;
Scale = 0;
}
if (!BaseReg) {
BaseReg = TmpReg;
} else {
- if (IndexReg) {
- ErrMsg = "BaseReg/IndexReg already set!";
- return true;
- }
+ if (IndexReg)
+ return regsUseUpError(ErrMsg);
IndexReg = TmpReg;
Scale = 0;
}
case IES_MULTIPLY:
// Index Register - Scale * Register
if (PrevState == IES_INTEGER) {
- if (IndexReg) {
- ErrMsg = "BaseReg/IndexReg already set!";
- return true;
- }
+ if (IndexReg)
+ return regsUseUpError(ErrMsg);
State = IES_REGISTER;
IndexReg = Reg;
// Get the scale and replace the 'Scale * Register' with '0'.
State = IES_INTEGER;
if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) {
// Index Register - Register * Scale
- if (IndexReg) {
- ErrMsg = "BaseReg/IndexReg already set!";
- return true;
- }
+ if (IndexReg)
+ return regsUseUpError(ErrMsg);
IndexReg = TmpReg;
Scale = TmpInt;
if (checkScale(Scale, ErrMsg))
BracCount++;
return false;
}
- bool onRBrac() {
+ bool onRBrac(StringRef &ErrMsg) {
IntelExprState CurrState = State;
switch (State) {
default:
case IES_OFFSET:
case IES_REGISTER:
case IES_RPAREN:
- if (BracCount-- != 1)
+ if (BracCount-- != 1) {
+ ErrMsg = "unexpected bracket encountered";
return true;
+ }
State = IES_RBRAC;
if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) {
// If we already have a BaseReg, then assume this is the IndexReg with
if (!BaseReg) {
BaseReg = TmpReg;
} else {
- assert (!IndexReg && "BaseReg/IndexReg already set!");
+ if (IndexReg)
+ return regsUseUpError(ErrMsg);
IndexReg = TmpReg;
Scale = 0;
}
InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedOperand, SMLoc &End,
bool IsParsingOffsetOperator = false);
+ void tryParseOperandIdx(AsmToken::TokenKind PrevTK,
+ IntelExprStateMachine &SM);
bool ParseMemOperand(unsigned SegReg, const MCExpr *Disp, SMLoc StartLoc,
SMLoc EndLoc, OperandVector &Operands);
return true;
}
+// Check if current intel expression append after an operand.
+// Like: [Operand][Intel Expression]
+void X86AsmParser::tryParseOperandIdx(AsmToken::TokenKind PrevTK,
+ IntelExprStateMachine &SM) {
+ if (PrevTK != AsmToken::RBrac)
+ return;
+
+ SM.setAppendAfterOperand();
+}
+
bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
MCAsmParser &Parser = getParser();
StringRef ErrMsg;
AsmToken::TokenKind PrevTK = AsmToken::Error;
+
+ if (getContext().getObjectFileInfo()->isPositionIndependent())
+ SM.setPIC();
+
bool Done = false;
while (!Done) {
// Get a fresh reference on each loop iteration in case the previous
case AsmToken::LBrac:
if (SM.onLBrac())
return Error(Tok.getLoc(), "unexpected bracket encountered");
+ tryParseOperandIdx(PrevTK, SM);
break;
case AsmToken::RBrac:
- if (SM.onRBrac())
- return Error(Tok.getLoc(), "unexpected bracket encountered");
+ if (SM.onRBrac(ErrMsg)) {
+ return Error(Tok.getLoc(), ErrMsg);
+ }
break;
case AsmToken::LParen: SM.onLParen(); break;
case AsmToken::RParen: SM.onRParen(); break;
BaseReg.getReg() == X86::RIP)
HasBaseReg = false;
+ // If we really just want to print out displacement.
+ bool HasIndexReg = IndexReg.getReg() != 0;
+ if (Modifier && (DispSpec.isGlobal() || DispSpec.isSymbol()) &&
+ !strcmp(Modifier, "disp-only")) {
+ HasBaseReg = false;
+ HasIndexReg = false;
+ }
+
// If this has a segment register, print it.
if (SegReg.getReg()) {
PrintOperand(MI, OpNo + X86::AddrSegmentReg, O);
PrintMemReference(MI, OpNo, O, "H");
}
return false;
- case 'P': // Don't print @PLT, but do print as memory.
+ // Print memory only with displacement. The Modifer 'P' is used in inline
+ // asm to present a call symbol or a global symbol which can not use base
+ // reg or index reg.
+ case 'P':
if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
- PrintIntelMemReference(MI, OpNo, O, "no-rip");
+ PrintIntelMemReference(MI, OpNo, O, "disp-only");
} else {
- PrintMemReference(MI, OpNo, O, "no-rip");
+ PrintMemReference(MI, OpNo, O, "disp-only");
}
return false;
}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64-unknown-unknown -relocation-model=pic %s -o - | FileCheck %s
+
+; Tests come from "clang/test/CodeGen/ms-inline-asm-variables.c"
+; int gVar;
+; void t1() {
+; __asm add eax, dword ptr gVar[rax]
+; __asm add dword ptr [rax+gVar], eax
+; __asm add ebx, dword ptr gVar[271 - 82 + 81 + rbx]
+; __asm add dword ptr [rbx + gVar + 828], ebx
+; gVar = 3;
+; }
+;
+; void t2(void) {
+; int lVar;
+; __asm mov eax, dword ptr lVar[rax]
+; __asm mov dword ptr [rax+lVar], eax
+; __asm mov ebx, dword ptr lVar[271 - 82 + 81 + rbx]
+; __asm mov dword ptr [rbx + lVar + 828], ebx
+; __asm mov 5 + 8 + 13 + 21[lVar + rbx], eax
+; lVar = 2;
+; }
+
+@gVar = global i32 0, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t1() #0 {
+; CHECK-LABEL: t1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: pushq %rbp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset %rbp, -16
+; CHECK-NEXT: movq %rsp, %rbp
+; CHECK-NEXT: .cfi_def_cfa_register %rbp
+; CHECK-NEXT: pushq %rbx
+; CHECK-NEXT: .cfi_offset %rbx, -24
+; CHECK-NEXT: movq gVar@GOTPCREL(%rip), %rcx
+; CHECK-NEXT: #APP
+; CHECK-EMPTY:
+; CHECK-NEXT: addl (%rcx,%rax), %eax
+; CHECK-NEXT: addl %eax, (%rcx,%rax)
+; CHECK-NEXT: addl 270(%rcx,%rbx), %ebx
+; CHECK-NEXT: addl %ebx, 828(%rcx,%rbx)
+; CHECK-EMPTY:
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: movq gVar@GOTPCREL(%rip), %rax
+; CHECK-NEXT: movl $3, (%rax)
+; CHECK-NEXT: popq %rbx
+; CHECK-NEXT: popq %rbp
+; CHECK-NEXT: .cfi_def_cfa %rsp, 8
+; CHECK-NEXT: retq
+entry:
+ call void asm sideeffect inteldialect "add eax, dword ptr $2[rax]\0A\09add dword ptr $0[rax], eax\0A\09add ebx, dword ptr $3[rbx + $$270]\0A\09add dword ptr $1[rbx + $$828], ebx", "=*m,=*m,*m,*m,~{eax},~{ebx},~{flags},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar) #1
+ store i32 3, i32* @gVar, align 4
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t2() #0 {
+; CHECK-LABEL: t2:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: pushq %rbp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset %rbp, -16
+; CHECK-NEXT: movq %rsp, %rbp
+; CHECK-NEXT: .cfi_def_cfa_register %rbp
+; CHECK-NEXT: pushq %rbx
+; CHECK-NEXT: .cfi_offset %rbx, -24
+; CHECK-NEXT: #APP
+; CHECK-EMPTY:
+; CHECK-NEXT: movl -12(%rbp,%rax), %eax
+; CHECK-NEXT: movl %eax, -12(%rbp,%rax)
+; CHECK-NEXT: movl 258(%rbp,%rbx), %ebx
+; CHECK-NEXT: movl %ebx, 816(%rbp,%rbx)
+; CHECK-NEXT: movl %eax, 35(%rbp,%rbx)
+; CHECK-EMPTY:
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: movl $2, -12(%rbp)
+; CHECK-NEXT: popq %rbx
+; CHECK-NEXT: popq %rbp
+; CHECK-NEXT: .cfi_def_cfa %rsp, 8
+; CHECK-NEXT: retq
+entry:
+ %lVar = alloca i32, align 4
+ call void asm sideeffect inteldialect "mov eax, dword ptr $3[rax]\0A\09mov dword ptr $0[rax], eax\0A\09mov ebx, dword ptr $4[rbx + $$270]\0A\09mov dword ptr $1[rbx + $$828], ebx\0A\09mov $2[rbx + $$47], eax", "=*m,=*m,=*m,*m,*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar) #1
+ store i32 2, i32* %lVar, align 4
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
--- /dev/null
+; RUN: not llc -mtriple=x86_64-unknown-unknown -relocation-model=pic %s -o /dev/null 2>&1 | FileCheck %s
+
+; Tests come from "clang/test/CodeGen/ms-inline-asm-variables.c"
+;
+; int gVar;
+; void t1() {
+; __asm add ecx, dword ptr gVar[4590 + rax + rcx*4]
+; __asm add dword ptr [gVar + rax + 45 + 23 - 53 + 60 - 2 + rcx*8], ecx
+; __asm add 1 + 1 + 2 + 3[gVar + rcx + rbx], eax
+; gVar = 3;
+; }
+
+@gVar = global i32 0, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t1() #0 {
+; CHECK: error: Don't use 2 or more regs for mem offset in PIC model
+; CHECK: error: Don't use 2 or more regs for mem offset in PIC model
+; CHECK: error: Don't use 2 or more regs for mem offset in PIC model
+entry:
+ call void asm sideeffect inteldialect "add ecx, dword ptr ${2:P}[rax + rcx * $$4 + $$4590]\0A\09add dword ptr ${0:P}[rcx + rcx * $$8 + $$73], ecx\0A\09add ${1:P}[rcx + rbx + $$7], eax", "=*m,=*m,*m,~{ecx},~{flags},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar)
+ store i32 3, i32* @gVar, align 4
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64-unknown-unknown %s -o - | FileCheck %s
+
+; Tests similar with "clang/test/CodeGen/ms-inline-asm-variables.c"
+; // clang -fasm-blocks -target x86_64-unknown-unknown -S
+
+; int gVar;
+; void t1() {
+; __asm add eax, dword ptr gVar[rax]
+; __asm add dword ptr [rax+gVar], eax
+; __asm add ebx, dword ptr gVar[271 - 82 + 81 + rbx]
+; __asm add dword ptr [rbx + gVar + 828], ebx
+; __asm add ecx, dword ptr gVar[4590 + rcx + rcx*4]
+; __asm add dword ptr [gVar + rcx + 45 + 23 - 53 + 60 - 2 + rcx*8], ecx
+; __asm add 1 + 1 + 2 + 3[gVar + rcx + rbx], eax
+;
+; gVar += 2;
+; }
+;
+; void t2(void) {
+; int lVar;
+; __asm mov eax, dword ptr lVar[rax]
+; __asm mov dword ptr [rax+lVar], eax
+; __asm mov ebx, dword ptr lVar[271 - 82 + 81 + rbx]
+; __asm mov dword ptr [rbx + lVar + 828], ebx
+; __asm mov 5 + 8 + 13 + 21[lVar + rbx], eax
+; }
+
+@gVar = dso_local global i32 0, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @t1() #0 {
+; CHECK-LABEL: t1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: pushq %rbp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset %rbp, -16
+; CHECK-NEXT: movq %rsp, %rbp
+; CHECK-NEXT: .cfi_def_cfa_register %rbp
+; CHECK-NEXT: pushq %rbx
+; CHECK-NEXT: .cfi_offset %rbx, -24
+; CHECK-NEXT: #APP
+; CHECK-EMPTY:
+; CHECK-NEXT: addl gVar(,%rax), %eax
+; CHECK-NEXT: addl %eax, gVar(,%rax)
+; CHECK-NEXT: addl gVar+270(,%rbx), %ebx
+; CHECK-NEXT: addl %ebx, gVar+828(,%rbx)
+; CHECK-NEXT: addl gVar+4590(%rcx,%rcx,4), %ecx
+; CHECK-NEXT: addl %ecx, gVar+73(%rcx,%rcx,8)
+; CHECK-NEXT: addl %eax, gVar+7(%rcx,%rbx)
+; CHECK-EMPTY:
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: movl gVar, %eax
+; CHECK-NEXT: addl $2, %eax
+; CHECK-NEXT: movl %eax, gVar
+; CHECK-NEXT: popq %rbx
+; CHECK-NEXT: popq %rbp
+; CHECK-NEXT: .cfi_def_cfa %rsp, 8
+; CHECK-NEXT: retq
+entry:
+ call void asm sideeffect inteldialect "add eax, dword ptr $4[rax]\0A\09add dword ptr $0[rax], eax\0A\09add ebx, dword ptr $5[rbx + $$270]\0A\09add dword ptr $1[rbx + $$828], ebx\0A\09add ecx, dword ptr ${6:P}[rcx + rcx * $$4 + $$4590]\0A\09add dword ptr ${2:P}[rcx + rcx * $$8 + $$73], ecx\0A\09add ${3:P}[rcx + rbx + $$7], eax", "=*m,=*m,=*m,=*m,*m,*m,*m,~{eax},~{ebx},~{ecx},~{flags},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar) #1
+ %0 = load i32, i32* @gVar, align 4
+ %add = add nsw i32 %0, 2
+ store i32 %add, i32* @gVar, align 4
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @t2() #0 {
+; CHECK-LABEL: t2:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: pushq %rbp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset %rbp, -16
+; CHECK-NEXT: movq %rsp, %rbp
+; CHECK-NEXT: .cfi_def_cfa_register %rbp
+; CHECK-NEXT: pushq %rbx
+; CHECK-NEXT: .cfi_offset %rbx, -24
+; CHECK-NEXT: #APP
+; CHECK-EMPTY:
+; CHECK-NEXT: movl -12(%rbp,%rax), %eax
+; CHECK-NEXT: movl %eax, -12(%rbp,%rax)
+; CHECK-NEXT: movl 258(%rbp,%rbx), %ebx
+; CHECK-NEXT: movl %ebx, 816(%rbp,%rbx)
+; CHECK-NEXT: movl %eax, 35(%rbp,%rbx)
+; CHECK-EMPTY:
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: popq %rbx
+; CHECK-NEXT: popq %rbp
+; CHECK-NEXT: .cfi_def_cfa %rsp, 8
+; CHECK-NEXT: retq
+entry:
+ %lVar = alloca i32, align 4
+ call void asm sideeffect inteldialect "mov eax, dword ptr $3[rax]\0A\09mov dword ptr $0[rax], eax\0A\09mov ebx, dword ptr $4[rbx + $$270]\0A\09mov dword ptr $1[rbx + $$828], ebx\0A\09mov $2[rbx + $$47], eax", "=*m,=*m,=*m,*m,*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar) #1
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"uwtable", i32 2}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=i386-unknown-unknown %s -o - | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=i386-unknown-unknown -relocation-model=pic %s -o -| FileCheck --check-prefix=X86PIC %s
+
+; Tests come from clang/test/CodeGen/ms-inline-asm-variables.c
+;
+; int gVar;
+; void t1() {
+; __asm add eax, dword ptr gVar[eax]
+; __asm add dword ptr [eax+gVar], eax
+; __asm add ebx, dword ptr gVar[271 - 82 + 81 + ebx]
+; __asm add dword ptr [ebx + gVar + 828], ebx
+; gVar = 3;
+; }
+;
+; void t2(void) {
+; int lVar;
+; __asm mov eax, dword ptr lVar[eax]
+; __asm mov dword ptr [eax+lVar], eax
+; __asm mov ebx, dword ptr lVar[271 - 82 + 81 + ebx]
+; __asm mov dword ptr [ebx + lVar + 828], ebx
+; __asm mov 5 + 8 + 13 + 21[lVar + ebx], eax
+; lVar = 2;
+; }
+
+@gVar = global i32 0, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t1() #0 {
+; X86-LABEL: t1:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: .cfi_offset %ebp, -8
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: .cfi_def_cfa_register %ebp
+; X86-NEXT: pushl %ebx
+; X86-NEXT: .cfi_offset %ebx, -12
+; X86-NEXT: #APP
+; X86-EMPTY:
+; X86-NEXT: addl gVar(%eax), %eax
+; X86-NEXT: addl %eax, gVar(%eax)
+; X86-NEXT: addl gVar+270(%ebx), %ebx
+; X86-NEXT: addl %ebx, gVar+828(%ebx)
+; X86-EMPTY:
+; X86-NEXT: #NO_APP
+; X86-NEXT: movl $3, gVar
+; X86-NEXT: popl %ebx
+; X86-NEXT: popl %ebp
+; X86-NEXT: .cfi_def_cfa %esp, 4
+; X86-NEXT: retl
+;
+; X86PIC-LABEL: t1:
+; X86PIC: # %bb.0: # %entry
+; X86PIC-NEXT: pushl %ebp
+; X86PIC-NEXT: .cfi_def_cfa_offset 8
+; X86PIC-NEXT: .cfi_offset %ebp, -8
+; X86PIC-NEXT: movl %esp, %ebp
+; X86PIC-NEXT: .cfi_def_cfa_register %ebp
+; X86PIC-NEXT: pushl %ebx
+; X86PIC-NEXT: .cfi_offset %ebx, -12
+; X86PIC-NEXT: calll .L0$pb
+; X86PIC-NEXT: .L0$pb:
+; X86PIC-NEXT: popl %ecx
+; X86PIC-NEXT: .Ltmp0:
+; X86PIC-NEXT: addl $_GLOBAL_OFFSET_TABLE_+(.Ltmp0-.L0$pb), %ecx
+; X86PIC-NEXT: movl gVar@GOT(%ecx), %edx
+; X86PIC-NEXT: #APP
+; X86PIC-EMPTY:
+; X86PIC-NEXT: addl (%edx,%eax), %eax
+; X86PIC-NEXT: addl %eax, (%edx,%eax)
+; X86PIC-NEXT: addl 270(%edx,%ebx), %ebx
+; X86PIC-NEXT: addl %ebx, 828(%edx,%ebx)
+; X86PIC-EMPTY:
+; X86PIC-NEXT: #NO_APP
+; X86PIC-NEXT: movl gVar@GOT(%ecx), %eax
+; X86PIC-NEXT: movl $3, (%eax)
+; X86PIC-NEXT: popl %ebx
+; X86PIC-NEXT: popl %ebp
+; X86PIC-NEXT: .cfi_def_cfa %esp, 4
+; X86PIC-NEXT: retl
+entry:
+ call void asm sideeffect inteldialect "add eax, dword ptr $2[eax]\0A\09add dword ptr $0[eax], eax\0A\09add ebx, dword ptr $3[ebx + $$270]\0A\09add dword ptr $1[ebx + $$828], ebx", "=*m,=*m,*m,*m,~{eax},~{ebx},~{flags},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar)
+ store i32 3, i32* @gVar, align 4
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t2() #0 {
+; X86-LABEL: t2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: .cfi_offset %ebp, -8
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: .cfi_def_cfa_register %ebp
+; X86-NEXT: pushl %ebx
+; X86-NEXT: pushl %eax
+; X86-NEXT: .cfi_offset %ebx, -12
+; X86-NEXT: #APP
+; X86-EMPTY:
+; X86-NEXT: movl -8(%ebp,%eax), %eax
+; X86-NEXT: movl %eax, -8(%ebp,%eax)
+; X86-NEXT: movl 262(%ebp,%ebx), %ebx
+; X86-NEXT: movl %ebx, 820(%ebp,%ebx)
+; X86-NEXT: movl %eax, 39(%ebp,%ebx)
+; X86-EMPTY:
+; X86-NEXT: #NO_APP
+; X86-NEXT: movl $2, -8(%ebp)
+; X86-NEXT: addl $4, %esp
+; X86-NEXT: popl %ebx
+; X86-NEXT: popl %ebp
+; X86-NEXT: .cfi_def_cfa %esp, 4
+; X86-NEXT: retl
+;
+; X86PIC-LABEL: t2:
+; X86PIC: # %bb.0: # %entry
+; X86PIC-NEXT: pushl %ebp
+; X86PIC-NEXT: .cfi_def_cfa_offset 8
+; X86PIC-NEXT: .cfi_offset %ebp, -8
+; X86PIC-NEXT: movl %esp, %ebp
+; X86PIC-NEXT: .cfi_def_cfa_register %ebp
+; X86PIC-NEXT: pushl %ebx
+; X86PIC-NEXT: pushl %eax
+; X86PIC-NEXT: .cfi_offset %ebx, -12
+; X86PIC-NEXT: #APP
+; X86PIC-EMPTY:
+; X86PIC-NEXT: movl -8(%ebp,%eax), %eax
+; X86PIC-NEXT: movl %eax, -8(%ebp,%eax)
+; X86PIC-NEXT: movl 262(%ebp,%ebx), %ebx
+; X86PIC-NEXT: movl %ebx, 820(%ebp,%ebx)
+; X86PIC-NEXT: movl %eax, 39(%ebp,%ebx)
+; X86PIC-EMPTY:
+; X86PIC-NEXT: #NO_APP
+; X86PIC-NEXT: movl $2, -8(%ebp)
+; X86PIC-NEXT: addl $4, %esp
+; X86PIC-NEXT: popl %ebx
+; X86PIC-NEXT: popl %ebp
+; X86PIC-NEXT: .cfi_def_cfa %esp, 4
+; X86PIC-NEXT: retl
+entry:
+ %lVar = alloca i32, align 4
+ call void asm sideeffect inteldialect "mov eax, dword ptr $3[eax]\0A\09mov dword ptr $0[eax], eax\0A\09mov ebx, dword ptr $4[ebx + $$270]\0A\09mov dword ptr $1[ebx + $$828], ebx\0A\09mov $2[ebx + $$47], eax", "=*m,=*m,=*m,*m,*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar, i32* elementtype(i32) %lVar)
+ store i32 2, i32* %lVar, align 4
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"NumRegisterParameters", i32 0}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=i386-unknown-unknown %s -o - | FileCheck --check-prefix=X86 %s
+; RUN: not llc -mtriple=i386-unknown-unknown -relocation-model=pic %s -o /dev/null 2>&1 | FileCheck --check-prefix=X86PIC %s
+
+; Tests come from "clang/test/CodeGen/ms-inline-asm-variables.c"
+;
+; int gVar;
+; void t1() {
+; __asm add ecx, dword ptr gVar[4590 + eax + ecx*4]
+; __asm add dword ptr [gVar + eax + 45 + 23 - 53 + 60 - 2 + ecx*8], ecx
+; __asm add 1 + 1 + 2 + 3[gVar + ecx + ebx], eax
+;
+; gVar = 3;
+; }
+
+@gVar = global i32 0, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @t1() #0 {
+; X86-LABEL: t1:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: .cfi_def_cfa_offset 8
+; X86-NEXT: .cfi_offset %ebp, -8
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: .cfi_def_cfa_register %ebp
+; X86-NEXT: #APP
+; X86-EMPTY:
+; X86-NEXT: addl gVar+4590(%eax,%ecx,4), %ecx
+; X86-NEXT: addl %ecx, gVar+73(%eax,%ecx,8)
+; X86-NEXT: addl %eax, gVar+7(%ecx,%ebx)
+; X86-EMPTY:
+; X86-NEXT: #NO_APP
+; X86-NEXT: movl $3, gVar
+; X86-NEXT: popl %ebp
+; X86-NEXT: .cfi_def_cfa %esp, 4
+; X86-NEXT: retl
+
+; X86PIC: error: Don't use 2 or more regs for mem offset in PIC model
+; X86PIC: error: Don't use 2 or more regs for mem offset in PIC model
+; X86PIC: error: Don't use 2 or more regs for mem offset in PIC model
+
+entry:
+ call void asm sideeffect inteldialect "add ecx, dword ptr ${2:P}[eax + ecx * $$4 + $$4590]\0A\09add dword ptr ${0:P}[eax + ecx * $$8 + $$73], ecx\0A\09add ${1:P}[ecx + ebx + $$7], eax", "=*m,=*m,*m,~{eax},~{ecx},~{flags},~{dirflag},~{fpsr},~{flags}"(i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar, i32* elementtype(i32) @gVar) #1
+ store i32 3, i32* @gVar, align 4
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nounwind }
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 1, !"NumRegisterParameters", i32 0}