Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -5054,8 +5054,10 @@ 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 the mem offset. So It can not use + edditional regs to present the memory reference. (E.g. omit ``(rip)``, even + though it's PC-relative.) XCore: Index: llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -432,6 +432,8 @@ short BracCount; bool MemExpr; bool OffsetOperator; + bool AttachToOperandIdx; + bool IsPIC; SMLoc OffsetOperatorLoc; AsmTypeInfo CurType; @@ -449,7 +451,8 @@ 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; } @@ -469,9 +472,29 @@ 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 && (!SymName.empty() || 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) { @@ -655,10 +678,8 @@ if (!BaseReg) { BaseReg = TmpReg; } else { - if (IndexReg) { - ErrMsg = "BaseReg/IndexReg already set!"; - return true; - } + if (IndexReg) + return regsUseUpError(ErrMsg); IndexReg = TmpReg; Scale = 0; } @@ -716,10 +737,8 @@ if (!BaseReg) { BaseReg = TmpReg; } else { - if (IndexReg) { - ErrMsg = "BaseReg/IndexReg already set!"; - return true; - } + if (IndexReg) + return regsUseUpError(ErrMsg); IndexReg = TmpReg; Scale = 0; } @@ -777,10 +796,8 @@ 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'. @@ -820,8 +837,20 @@ case IES_INIT: case IES_LBRAC: case IES_LPAREN: - if (setSymRef(SymRef, SymRefName, ErrMsg)) - return true; + // The InineAsm can also be parsed from emitInlineAsm (not from FE) + // which may generate "Sym - BaseSym" for pic-base-offset addressing + // model (e.g. i386-darwin). + // Here we remove "- BaseSym" in inlineasm if it exists. + // TODO(RefineMe): Here is an architecture defect for both FE parser + // and BE emitInlineAsm share the same way to parse the inline asm. + // So the 2 symbol syntax checking may not be always right. + if (isPIC()) { + if (!Sym && setSymRef(SymRef, SymRefName, ErrMsg)) + return true; + } else { + if (setSymRef(SymRef, SymRefName, ErrMsg)) + return true; + } MemExpr = true; State = IES_INTEGER; IC.pushOperand(IC_IMM); @@ -861,10 +890,8 @@ 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)) @@ -945,7 +972,7 @@ BracCount++; return false; } - bool onRBrac() { + bool onRBrac(StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { default: @@ -955,8 +982,10 @@ 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 @@ -964,7 +993,8 @@ if (!BaseReg) { BaseReg = TmpReg; } else { - assert (!IndexReg && "BaseReg/IndexReg already set!"); + if (IndexReg) + return regsUseUpError(ErrMsg); IndexReg = TmpReg; Scale = 0; } @@ -1033,8 +1063,20 @@ case IES_PLUS: case IES_INIT: case IES_LBRAC: - if (setSymRef(Val, ID, ErrMsg)) - return true; + // The InineAsm can also be parsed from emitInlineAsm (not from FE) + // which may generate "Sym - BaseSym" for pic-base-offset addressing + // model (e.g. i386-darwin). + // Here we remove "- BaseSym" in inlineasm if it exists. + // TODO(RefineMe): Here is an architecture defect for both FE parser + // and BE emitInlineAsm share the same way to parse the inline asm. + // So the 2 symbol syntax checking may not be always right. + if (isPIC()) { + if (!Sym && setSymRef(Val, ID, ErrMsg)) + return true; + } else { + if (setSymRef(Val, ID, ErrMsg)) + return true; + } OffsetOperator = true; OffsetOperatorLoc = OffsetLoc; State = IES_OFFSET; @@ -1111,6 +1153,8 @@ 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); @@ -1841,11 +1885,25 @@ 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 @@ -2123,10 +2181,12 @@ 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; Index: llvm/lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- llvm/lib/Target/X86/X86AsmPrinter.cpp +++ llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -362,6 +362,14 @@ 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); @@ -605,11 +613,14 @@ 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; } Index: llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-1.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-1.ll @@ -0,0 +1,95 @@ +; 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} Index: llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-2.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-2.ll @@ -0,0 +1,31 @@ +; 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} Index: llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-3.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ms-inline-asm-variables-x64-3.ll @@ -0,0 +1,104 @@ +; 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} Index: llvm/test/CodeGen/X86/ms-inline-asm-variables-x86-1.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ms-inline-asm-variables-x86-1.ll @@ -0,0 +1,153 @@ +; 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} Index: llvm/test/CodeGen/X86/ms-inline-asm-variables-x86-2.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ms-inline-asm-variables-x86-2.ll @@ -0,0 +1,54 @@ +; 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}