[llvm] r312130 - [GlobalISel][X86] Support variadic function call.

Igor Breger via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 30 08:10:16 PDT 2017


Author: ibreger
Date: Wed Aug 30 08:10:15 2017
New Revision: 312130

URL: http://llvm.org/viewvc/llvm-project?rev=312130&view=rev
Log:
[GlobalISel][X86] Support variadic function call.

Summary: Support variadic function call. Port the implementation from X86FastISel.

Reviewers: zvi, guyblank, oren_ben_simhon

Reviewed By: guyblank

Subscribers: rovka, kristof.beyls, llvm-commits

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

Modified:
    llvm/trunk/lib/Target/X86/X86CallLowering.cpp
    llvm/trunk/test/CodeGen/X86/GlobalISel/callingconv.ll
    llvm/trunk/test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll

Modified: llvm/trunk/lib/Target/X86/X86CallLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86CallLowering.cpp?rev=312130&r1=312129&r2=312130&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86CallLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86CallLowering.cpp Wed Aug 30 08:10:15 2017
@@ -84,7 +84,7 @@ struct OutgoingValueHandler : public Cal
                        MachineInstrBuilder &MIB, CCAssignFn *AssignFn)
       : ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB), StackSize(0),
         DL(MIRBuilder.getMF().getDataLayout()),
-        STI(MIRBuilder.getMF().getSubtarget<X86Subtarget>()) {}
+        STI(MIRBuilder.getMF().getSubtarget<X86Subtarget>()), NumXMMRegs(0) {}
 
   unsigned getStackAddress(uint64_t Size, int64_t Offset,
                            MachinePointerInfo &MPO) override {
@@ -125,21 +125,27 @@ struct OutgoingValueHandler : public Cal
                  CCValAssign::LocInfo LocInfo,
                  const CallLowering::ArgInfo &Info, CCState &State) override {
 
-    if (!Info.IsFixed)
-      return true; // TODO: handle variadic function
-
     bool Res = AssignFn(ValNo, ValVT, LocVT, LocInfo, Info.Flags, State);
     StackSize = State.getNextStackOffset();
+
+    static const MCPhysReg XMMArgRegs[] = {X86::XMM0, X86::XMM1, X86::XMM2,
+                                           X86::XMM3, X86::XMM4, X86::XMM5,
+                                           X86::XMM6, X86::XMM7};
+    if (!Info.IsFixed)
+      NumXMMRegs = State.getFirstUnallocated(XMMArgRegs);
+
     return Res;
   }
 
   uint64_t getStackSize() { return StackSize; }
+  uint64_t getNumXmmRegs() { return NumXMMRegs; }
 
 protected:
   MachineInstrBuilder &MIB;
   uint64_t StackSize;
   const DataLayout &DL;
   const X86Subtarget &STI;
+  unsigned NumXMMRegs;
 };
 } // End anonymous namespace.
 
@@ -338,6 +344,22 @@ bool X86CallLowering::lowerCall(MachineI
   if (!handleAssignments(MIRBuilder, SplitArgs, Handler))
     return false;
 
+  bool IsFixed = OrigArgs.empty() ? true : OrigArgs.back().IsFixed;
+  if (STI.is64Bit() && !IsFixed && !STI.isCallingConvWin64(CallConv)) {
+    // From AMD64 ABI document:
+    // For calls that may call functions that use varargs or stdargs
+    // (prototype-less calls or calls to functions containing ellipsis (...) in
+    // the declaration) %al is used as hidden argument to specify the number
+    // of SSE registers used. The contents of %al do not need to match exactly
+    // the number of registers, but must be an ubound on the number of SSE
+    // registers used and is in the range 0 - 8 inclusive.
+
+    MIRBuilder.buildInstr(X86::MOV8ri)
+        .addDef(X86::AL)
+        .addImm(Handler.getNumXmmRegs());
+    MIB.addUse(X86::AL, RegState::Implicit);
+  }
+
   // Now we can add the actual call instruction to the correct basic block.
   MIRBuilder.insertInstr(MIB);
 

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/callingconv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/callingconv.ll?rev=312130&r1=312129&r2=312130&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/callingconv.ll (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/callingconv.ll Wed Aug 30 08:10:15 2017
@@ -356,3 +356,77 @@ define void @test_abi_exts_call(i8* %add
   call void @take_char(i8 zeroext %val)
  ret void
 }
+
+declare void @variadic_callee(i8*, ...)
+define void @test_variadic_call_1(i8** %addr_ptr, i32* %val_ptr) {
+; X32-LABEL: test_variadic_call_1:
+; X32:       # BB#0:
+; X32-NEXT:    subl $12, %esp
+; X32-NEXT:  .Lcfi10:
+; X32-NEXT:    .cfi_def_cfa_offset 16
+; X32-NEXT:    movl 16(%esp), %eax
+; X32-NEXT:    movl 20(%esp), %ecx
+; X32-NEXT:    movl (%eax), %eax
+; X32-NEXT:    movl (%ecx), %ecx
+; X32-NEXT:    movl %eax, (%esp)
+; X32-NEXT:    movl %ecx, 4(%esp)
+; X32-NEXT:    calll variadic_callee
+; X32-NEXT:    addl $12, %esp
+; X32-NEXT:    retl
+;
+; X64-LABEL: test_variadic_call_1:
+; X64:       # BB#0:
+; X64-NEXT:    pushq %rax
+; X64-NEXT:  .Lcfi8:
+; X64-NEXT:    .cfi_def_cfa_offset 16
+; X64-NEXT:    movq (%rdi), %rdi
+; X64-NEXT:    movl (%rsi), %esi
+; X64-NEXT:    movb $0, %al
+; X64-NEXT:    callq variadic_callee
+; X64-NEXT:    popq %rax
+; X64-NEXT:    retq
+
+  %addr = load i8*, i8** %addr_ptr
+  %val = load i32, i32* %val_ptr
+  call void (i8*, ...) @variadic_callee(i8* %addr, i32 %val)
+  ret void
+}
+
+define void @test_variadic_call_2(i8** %addr_ptr, double* %val_ptr) {
+; X32-LABEL: test_variadic_call_2:
+; X32:       # BB#0:
+; X32-NEXT:    subl $12, %esp
+; X32-NEXT:  .Lcfi11:
+; X32-NEXT:    .cfi_def_cfa_offset 16
+; X32-NEXT:    movl 16(%esp), %eax
+; X32-NEXT:    movl 20(%esp), %ecx
+; X32-NEXT:    movl (%eax), %eax
+; X32-NEXT:    movl (%ecx), %edx
+; X32-NEXT:    movl 4(%ecx), %ecx
+; X32-NEXT:    movl %eax, (%esp)
+; X32-NEXT:    movl $4, %eax
+; X32-NEXT:    leal (%esp,%eax), %eax
+; X32-NEXT:    movl %edx, 4(%esp)
+; X32-NEXT:    movl %ecx, 4(%eax)
+; X32-NEXT:    calll variadic_callee
+; X32-NEXT:    addl $12, %esp
+; X32-NEXT:    retl
+;
+; X64-LABEL: test_variadic_call_2:
+; X64:       # BB#0:
+; X64-NEXT:    pushq %rax
+; X64-NEXT:  .Lcfi9:
+; X64-NEXT:    .cfi_def_cfa_offset 16
+; X64-NEXT:    movq (%rdi), %rdi
+; X64-NEXT:    movq (%rsi), %rcx
+; X64-NEXT:    movb $1, %al
+; X64-NEXT:    movq %rcx, %xmm0
+; X64-NEXT:    callq variadic_callee
+; X64-NEXT:    popq %rax
+; X64-NEXT:    retq
+
+  %addr = load i8*, i8** %addr_ptr
+  %val = load double, double* %val_ptr
+  call void (i8*, ...) @variadic_callee(i8* %addr, double %val)
+  ret void
+}

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll?rev=312130&r1=312129&r2=312130&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/irtranslator-callingconv.ll Wed Aug 30 08:10:15 2017
@@ -697,3 +697,92 @@ define void @test_abi_exts_call(i8* %add
   ret void
 }
 
+declare void @variadic_callee(i8*, ...)
+define void @test_variadic_call_1(i8** %addr_ptr, i32* %val_ptr) {
+; ALL-LABEL: name:            test_variadic_call_1
+
+; X32:      fixedStack:      
+; X32-NEXT:  - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: 0, 
+; X32-NEXT:      isImmutable: true, isAliased: false, callee-saved-register: '' }
+; X32-NEXT:  - { id: 1, type: default, offset: 0, size: 4, alignment: 16, stack-id: 0, 
+; X32-NEXT:      isImmutable: true, isAliased: false, callee-saved-register: '' }
+; X32:         %2(p0) = G_FRAME_INDEX %fixed-stack.1
+; X32-NEXT:    %0(p0) = G_LOAD %2(p0) :: (invariant load 4 from %fixed-stack.1, align 0)
+; X32-NEXT:    %3(p0) = G_FRAME_INDEX %fixed-stack.0
+; X32-NEXT:    %1(p0) = G_LOAD %3(p0) :: (invariant load 4 from %fixed-stack.0, align 0)
+; X32-NEXT:    %4(p0) = G_LOAD %0(p0) :: (load 4 from %ir.addr_ptr)
+; X32-NEXT:    %5(s32) = G_LOAD %1(p0) :: (load 4 from %ir.val_ptr)
+; X32-NEXT:    ADJCALLSTACKDOWN32 8, 0, 0, implicit-def %esp, implicit-def %eflags, implicit %esp
+; X32-NEXT:    %6(p0) = COPY %esp
+; X32-NEXT:    %7(s32) = G_CONSTANT i32 0
+; X32-NEXT:    %8(p0) = G_GEP %6, %7(s32)
+; X32-NEXT:    G_STORE %4(p0), %8(p0) :: (store 4 into stack, align 0)
+; X32-NEXT:    %9(p0) = COPY %esp
+; X32-NEXT:    %10(s32) = G_CONSTANT i32 4
+; X32-NEXT:    %11(p0) = G_GEP %9, %10(s32)
+; X32-NEXT:    G_STORE %5(s32), %11(p0) :: (store 4 into stack + 4, align 0)
+; X32-NEXT:    CALLpcrel32 @variadic_callee, csr_32, implicit %esp
+; X32-NEXT:    ADJCALLSTACKUP32 8, 0, implicit-def %esp, implicit-def %eflags, implicit %esp
+; X32-NEXT:    RET 0
+  
+; X64:         %0(p0) = COPY %rdi
+; X64-NEXT:    %1(p0) = COPY %rsi
+; X64-NEXT:    %2(p0) = G_LOAD %0(p0) :: (load 8 from %ir.addr_ptr)
+; X64-NEXT:    %3(s32) = G_LOAD %1(p0) :: (load 4 from %ir.val_ptr)
+; X64-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def %rsp, implicit-def %eflags, implicit %rsp
+; X64-NEXT:    %rdi = COPY %2(p0)
+; X64-NEXT:    %esi = COPY %3(s32)
+; X64-NEXT:    %al = MOV8ri 0
+; X64-NEXT:    CALL64pcrel32 @variadic_callee, csr_64, implicit %rsp, implicit %rdi, implicit %esi, implicit %al
+; X64-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def %rsp, implicit-def %eflags, implicit %rsp
+; X64-NEXT:    RET 0
+  
+  %addr = load i8*, i8** %addr_ptr
+  %val = load i32, i32* %val_ptr
+  call void (i8*, ...) @variadic_callee(i8* %addr, i32 %val)
+  ret void
+}
+
+define void @test_variadic_call_2(i8** %addr_ptr, double* %val_ptr) {
+; ALL-LABEL: name:            test_variadic_call_2
+
+; X32:      fixedStack:      
+; X32-NEXT:  - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: 0, 
+; X32-NEXT:      isImmutable: true, isAliased: false, callee-saved-register: '' }
+; X32-NEXT:  - { id: 1, type: default, offset: 0, size: 4, alignment: 16, stack-id: 0, 
+; X32-NEXT:      isImmutable: true, isAliased: false, callee-saved-register: '' }
+; X32:         %2(p0) = G_FRAME_INDEX %fixed-stack.1
+; X32-NEXT:    %0(p0) = G_LOAD %2(p0) :: (invariant load 4 from %fixed-stack.1, align 0)
+; X32-NEXT:    %3(p0) = G_FRAME_INDEX %fixed-stack.0
+; X32-NEXT:    %1(p0) = G_LOAD %3(p0) :: (invariant load 4 from %fixed-stack.0, align 0)
+; X32-NEXT:    %4(p0) = G_LOAD %0(p0) :: (load 4 from %ir.addr_ptr)
+; X32-NEXT:    %5(s64) = G_LOAD %1(p0) :: (load 8 from %ir.val_ptr, align 4)
+; X32-NEXT:    ADJCALLSTACKDOWN32 12, 0, 0, implicit-def %esp, implicit-def %eflags, implicit %esp
+; X32-NEXT:    %6(p0) = COPY %esp
+; X32-NEXT:    %7(s32) = G_CONSTANT i32 0
+; X32-NEXT:    %8(p0) = G_GEP %6, %7(s32)
+; X32-NEXT:    G_STORE %4(p0), %8(p0) :: (store 4 into stack, align 0)
+; X32-NEXT:    %9(p0) = COPY %esp
+; X32-NEXT:    %10(s32) = G_CONSTANT i32 4
+; X32-NEXT:    %11(p0) = G_GEP %9, %10(s32)
+; X32-NEXT:    G_STORE %5(s64), %11(p0) :: (store 8 into stack + 4, align 0)
+; X32-NEXT:    CALLpcrel32 @variadic_callee, csr_32, implicit %esp
+; X32-NEXT:    ADJCALLSTACKUP32 12, 0, implicit-def %esp, implicit-def %eflags, implicit %esp
+; X32-NEXT:    RET 0
+  
+; X64:         %1(p0) = COPY %rsi
+; X64-NEXT:    %2(p0) = G_LOAD %0(p0) :: (load 8 from %ir.addr_ptr)
+; X64-NEXT:    %3(s64) = G_LOAD %1(p0) :: (load 8 from %ir.val_ptr)
+; X64-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def %rsp, implicit-def %eflags, implicit %rsp
+; X64-NEXT:    %rdi = COPY %2(p0)
+; X64-NEXT:    %xmm0 = COPY %3(s64)
+; X64-NEXT:    %al = MOV8ri 1
+; X64-NEXT:    CALL64pcrel32 @variadic_callee, csr_64, implicit %rsp, implicit %rdi, implicit %xmm0, implicit %al
+; X64-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def %rsp, implicit-def %eflags, implicit %rsp
+; X64-NEXT:    RET 0
+  
+  %addr = load i8*, i8** %addr_ptr
+  %val = load double, double* %val_ptr
+  call void (i8*, ...) @variadic_callee(i8* %addr, double %val)
+  ret void
+}




More information about the llvm-commits mailing list