[x32] Fix function indirect calls
authorPavel Chupin <pavel.v.chupin@intel.com>
Wed, 17 Sep 2014 07:09:23 +0000 (07:09 +0000)
committerPavel Chupin <pavel.v.chupin@intel.com>
Wed, 17 Sep 2014 07:09:23 +0000 (07:09 +0000)
Summary: Zero-extend register to 64-bit for callq/jmpq.

Test Plan: 3 tests added

Reviewers: nadav, dschuff

Subscribers: llvm-commits, zinovy.nis

Differential Revision: http://reviews.llvm.org/D5355

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217942 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/x32-function_pointer-1.ll [new file with mode: 0644]
test/CodeGen/X86/x32-function_pointer-2.ll [new file with mode: 0644]
test/CodeGen/X86/x32-function_pointer-3.ll [new file with mode: 0644]
test/CodeGen/X86/x86-64-call.ll

index fa804a707e36464d61807e233a1b653bb7c84d84..c6b9ee0370db92b432e4a5fad1e5f485bde7d8bc 100644 (file)
@@ -3119,6 +3119,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
 
     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy(),
                                          OpFlags);
+  } else if (Subtarget->isTarget64BitILP32() && Callee->getValueType(0) == MVT::i32) {
+    // Zero-extend the 32-bit Callee address into a 64-bit according to x32 ABI
+    Callee = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Callee);
   }
 
   // Returns a chain & a flag for retval copy to use.
diff --git a/test/CodeGen/X86/x32-function_pointer-1.ll b/test/CodeGen/X86/x32-function_pointer-1.ll
new file mode 100644 (file)
index 0000000..2baf92a
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32  | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32 -fast-isel | FileCheck %s
+
+; Test for x32 function pointer tail call
+
+@foo1 = external global void (i8*)*
+@foo2 = external global void (i8*)*
+
+define void @bar(i8* %h) nounwind uwtable {
+entry:
+  %0 = load void (i8*)** @foo1, align 4
+; CHECK: movl  foo1(%rip), %e{{[^,]*}}
+  tail call void %0(i8* %h) nounwind
+; CHECK: callq *%r{{[^,]*}}
+  %1 = load void (i8*)** @foo2, align 4
+; CHECK: movl  foo2(%rip), %e{{[^,]*}}
+  tail call void %1(i8* %h) nounwind
+; CHECK: jmpq  *%r{{[^,]*}}
+  ret void
+}
diff --git a/test/CodeGen/X86/x32-function_pointer-2.ll b/test/CodeGen/X86/x32-function_pointer-2.ll
new file mode 100644 (file)
index 0000000..f727d41
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32 | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32 -fast-isel | FileCheck %s
+
+; Test call function pointer with function argument
+;
+; void bar (void * h, void (*foo) (void *))
+;    {
+;      foo (h);
+;      foo (h);
+;    }
+
+
+define void @bar(i8* %h, void (i8*)* nocapture %foo) nounwind {
+entry:
+  tail call void %foo(i8* %h) nounwind
+; CHECK: mov{{l|q}}    %{{e|r}}si, %{{e|r}}[[REG:.*]]{{d?}}
+; CHECK: callq *%r[[REG]]
+  tail call void %foo(i8* %h) nounwind
+; CHECK: jmpq  *%r{{[^,]*}}
+  ret void
+}
diff --git a/test/CodeGen/X86/x32-function_pointer-3.ll b/test/CodeGen/X86/x32-function_pointer-3.ll
new file mode 100644 (file)
index 0000000..5eaf85d
--- /dev/null
@@ -0,0 +1,30 @@
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32 | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-linux-gnux32 -fast-isel | FileCheck %s
+
+; Test calling function pointer passed in struct
+
+;    The fuction argument `h' in
+
+;    struct foo {
+;      void (*f) (void);
+;      int i;
+;    };
+;    void
+;    bar (struct foo h)
+;    {
+;      h.f ();
+;    }
+
+;    is passed in the 64-bit %rdi register.  The `f' field is in the lower 32
+;    bits of %rdi register and the `i' field is in the upper 32 bits of %rdi
+;    register.  We need to zero-extend %edi to %rdi before branching via %rdi.
+
+define void @bar(i64 %h.coerce) nounwind {
+entry:
+  %h.sroa.0.0.extract.trunc = trunc i64 %h.coerce to i32
+  %0 = inttoptr i32 %h.sroa.0.0.extract.trunc to void ()*
+; CHECK: movl  %edi, %e[[REG:.*]]
+  tail call void %0() nounwind
+; CHECK: jmpq  *%r[[REG]]
+  ret void
+}
index 857779fb4d2ae3afa34fde23aa0c3a3549880476..300f8d1025e58e34d59fceda928b2707a8e6a300 100644 (file)
@@ -6,8 +6,8 @@
 
 define i32 @far() nounwind uwtable {
 entry:
-; CHECK: callq
-; IA32: calll
+; CHECK: callq foo
+; IA32: calll foo
   tail call void @foo() nounwind
   ret i32 0
 }