Skip to content

Commit

Permalink
[X86] Fix register resizings for inline assembly register operands.
Browse files Browse the repository at this point in the history
When replacing a named register input to the appropriately sized
sub/super-register. In the case of a 64-bit value being assigned to a
register in 32-bit mode, match GCC's assignment.

Reviewers: eli.friedman, craig.topper

Subscribers: nickdesaulniers, llvm-commits, hiraditya

Differential Revision: https://reviews.llvm.org/D51502

llvm-svn: 342175
  • Loading branch information
niravhdave committed Sep 13, 2018
1 parent 2060a16 commit 59ad1c8
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 220 deletions.
36 changes: 29 additions & 7 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Expand Up @@ -41219,14 +41219,36 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
Size == 8 ? (is64Bit ? &X86::GR8RegClass : &X86::GR8_NOREXRegClass)
: Size == 16 ? (is64Bit ? &X86::GR16RegClass : &X86::GR16_NOREXRegClass)
: Size == 32 ? (is64Bit ? &X86::GR32RegClass : &X86::GR32_NOREXRegClass)
: &X86::GR64RegClass;
if (RC->contains(DestReg))
Res = std::make_pair(DestReg, RC);
} else {
// No register found/type mismatch.
Res.first = 0;
Res.second = nullptr;
: Size == 64 ? (is64Bit ? &X86::GR64RegClass : nullptr)
: nullptr;
if (Size == 64 && !is64Bit) {
// Model GCC's behavior here and select a fixed pair of 32-bit
// registers.
switch (Res.first) {
case X86::EAX:
return std::make_pair(X86::EAX, &X86::GR32_ADRegClass);
case X86::EDX:
return std::make_pair(X86::EDX, &X86::GR32_DCRegClass);
case X86::ECX:
return std::make_pair(X86::ECX, &X86::GR32_CBRegClass);
case X86::EBX:
return std::make_pair(X86::EBX, &X86::GR32_BSIRegClass);
case X86::ESI:
return std::make_pair(X86::ESI, &X86::GR32_SIDIRegClass);
case X86::EDI:
return std::make_pair(X86::EDI, &X86::GR32_DIBPRegClass);
case X86::EBP:
return std::make_pair(X86::EBP, &X86::GR32_BPSPRegClass);
default:
return std::make_pair(0, nullptr);
}
}
if (RC && RC->contains(DestReg))
return std::make_pair(DestReg, RC);
return Res;
}
// No register found/type mismatch.
return std::make_pair(0, nullptr);
} else if (isFRClass(*Class)) {
// Handle references to XMM physical registers that got mapped into the
// wrong class. This can happen with constraints like {xmm0} where the
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/X86/X86RegisterInfo.td
Expand Up @@ -499,6 +499,16 @@ def LOW32_ADDR_ACCESS_RBP : RegisterClass<"X86", [i32], 32,
def GR32_AD : RegisterClass<"X86", [i32], 32, (add EAX, EDX)>;
def GR64_AD : RegisterClass<"X86", [i64], 64, (add RAX, RDX)>;

// Classes to support the 64-bit assembler constraint tied to a fixed
// register in 32-bit mode. The second register is always the next in
// the list. Wrap around causes an error.
def GR32_DC : RegisterClass<"X86", [i32], 32, (add EDX, ECX)>;
def GR32_CB : RegisterClass<"X86", [i32], 32, (add ECX, EBX)>;
def GR32_BSI : RegisterClass<"X86", [i32], 32, (add EBX, ESI)>;
def GR32_SIDI : RegisterClass<"X86", [i32], 32, (add ESI, EDI)>;
def GR32_DIBP : RegisterClass<"X86", [i32], 32, (add EDI, EBP)>;
def GR32_BPSP : RegisterClass<"X86", [i32], 32, (add EBP, ESP)>;

// Scalar SSE2 floating point registers.
def FR32 : RegisterClass<"X86", [f32], 32, (sequence "XMM%u", 0, 15)>;

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/X86/atomic_mi.ll
Expand Up @@ -2245,11 +2245,11 @@ define void @fadd_array(i64* %arg, double %arg1, i64 %arg2) {
; X32-NEXT: .cfi_offset %edi, -16
; X32-NEXT: .cfi_offset %ebx, -12
; X32-NEXT: movl 20(%ebp), %esi
; X32-NEXT: movl 8(%ebp), %edi
; X32-NEXT: xorl %eax, %eax
; X32-NEXT: xorl %edx, %edx
; X32-NEXT: xorl %ecx, %ecx
; X32-NEXT: xorl %ebx, %ebx
; X32-NEXT: movl 8(%ebp), %edi
; X32-NEXT: lock cmpxchg8b (%edi,%esi,8)
; X32-NEXT: movl %edx, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
Expand Down
160 changes: 80 additions & 80 deletions llvm/test/CodeGen/X86/avx512-regcall-Mask.ll

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions llvm/test/CodeGen/X86/physreg-pairs-error.ll
@@ -0,0 +1,12 @@
; RUN: not llc -mtriple=i386-unknown-linux-gnu -o - %s 2>&1 | FileCheck %s

; CHECK: error: couldn't allocate input reg for constraint '{esp}'
define dso_local i64 @test_esp(i64 %in) local_unnamed_addr nounwind {
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{esp},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

165 changes: 165 additions & 0 deletions llvm/test/CodeGen/X86/physreg-pairs.ll
@@ -0,0 +1,165 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=i386-unknown-linux-gnu -o - %s | FileCheck %s

; To match GCC's behavior in assigning 64-bit values to a 32-bit
; register, we bind the a subsequence of 2 registers starting with the
; explicitly given register from the following sequence: EAX, EDX,
; ECX, EBX, ESI, EDI, EBP, ESP, to the value. There is no wrapping
; from the sequence, so this will fail given ESP.

define dso_local i64 @test_eax(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_eax:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl $-1985229329, %eax # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %edx # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %eax, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{eax},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_edx(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_edx:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl $-1985229329, %edx # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %ecx # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %edx, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{edx},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_ecx(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_ecx:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushl %ebx
; CHECK-NEXT: movl $-1985229329, %ecx # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %ebx # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: popl %ebx
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{ecx},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_ebx(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_ebx:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushl %ebx
; CHECK-NEXT: pushl %esi
; CHECK-NEXT: movl $-1985229329, %ebx # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %esi # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %ebx, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: popl %esi
; CHECK-NEXT: popl %ebx
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{ebx},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_esi(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_esi:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushl %edi
; CHECK-NEXT: pushl %esi
; CHECK-NEXT: movl $-1985229329, %esi # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %edi # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %esi, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: popl %esi
; CHECK-NEXT: popl %edi
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{esi},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_edi(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_edi:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushl %ebp
; CHECK-NEXT: pushl %edi
; CHECK-NEXT: movl $-1985229329, %edi # imm = 0x89ABCDEF
; CHECK-NEXT: movl $19088743, %ebp # imm = 0x1234567
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: popl %edi
; CHECK-NEXT: popl %ebp
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{edi},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

define dso_local i64 @test_ebp(i64 %in) local_unnamed_addr nounwind {
; CHECK-LABEL: test_ebp:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushl %ebp
; CHECK-NEXT: movl $19088743, %esp # imm = 0x1234567
; CHECK-NEXT: movl $-1985229329, %ebp # imm = 0x89ABCDEF
; CHECK-NEXT: #APP
; CHECK-NEXT: movl %ebp, %eax
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: addl $3, %eax
; CHECK-NEXT: movl %eax, %edx
; CHECK-NEXT: sarl $31, %edx
; CHECK-NEXT: popl %ebp
; CHECK-NEXT: retl
entry:
%0 = tail call i64 asm sideeffect "mov $1, $0", "=r,{ebp},~{dirflag},~{fpsr},~{flags}"(i64 81985529216486895)
%conv = trunc i64 %0 to i32
%add = add nsw i32 %conv, 3
%conv1 = sext i32 %add to i64
ret i64 %conv1
}

0 comments on commit 59ad1c8

Please sign in to comment.