Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -589,6 +589,7 @@ KEYWORD(x86_64_sysvcc); KEYWORD(x86_64_win64cc); KEYWORD(webkit_jscc); + KEYWORD(swiftcc); KEYWORD(anyregcc); KEYWORD(preserve_mostcc); KEYWORD(preserve_allcc); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1549,6 +1549,7 @@ /// ::= 'preserve_mostcc' /// ::= 'preserve_allcc' /// ::= 'ghccc' +/// ::= 'swiftcc' /// ::= 'x86_intrcc' /// ::= 'hhvmcc' /// ::= 'hhvm_ccc' @@ -1583,6 +1584,7 @@ case lltok::kw_preserve_mostcc:CC = CallingConv::PreserveMost; break; case lltok::kw_preserve_allcc: CC = CallingConv::PreserveAll; break; case lltok::kw_ghccc: CC = CallingConv::GHC; break; + case lltok::kw_swiftcc: CC = CallingConv::Swift; break; case lltok::kw_x86_intrcc: CC = CallingConv::X86_INTR; break; case lltok::kw_hhvmcc: CC = CallingConv::HHVM; break; case lltok::kw_hhvm_ccc: CC = CallingConv::HHVM_C; break; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -99,6 +99,7 @@ kw_spir_kernel, kw_spir_func, kw_x86_64_sysvcc, kw_x86_64_win64cc, kw_webkit_jscc, kw_anyregcc, + kw_swiftcc, kw_preserve_mostcc, kw_preserve_allcc, kw_ghccc, kw_x86_intrcc, Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -315,6 +315,7 @@ case CallingConv::X86_64_Win64: Out << "x86_64_win64cc"; break; case CallingConv::SPIR_FUNC: Out << "spir_func"; break; case CallingConv::SPIR_KERNEL: Out << "spir_kernel"; break; + case CallingConv::Swift: Out << "swiftcc"; break; case CallingConv::X86_INTR: Out << "x86_intrcc"; break; case CallingConv::HHVM: Out << "hhvmcc"; break; case CallingConv::HHVM_C: Out << "hhvm_ccc"; break; Index: lib/Target/ARM/ARMFastISel.cpp =================================================================== --- lib/Target/ARM/ARMFastISel.cpp +++ lib/Target/ARM/ARMFastISel.cpp @@ -1839,6 +1839,7 @@ default: llvm_unreachable("Unsupported calling convention"); case CallingConv::Fast: + case CallingConv::Swift: if (Subtarget->hasVFP2() && !isVarArg) { if (!Subtarget->isAAPCS_ABI()) return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); @@ -3005,6 +3006,7 @@ case CallingConv::ARM_AAPCS_VFP: case CallingConv::ARM_AAPCS: case CallingConv::ARM_APCS: + case CallingConv::Swift: break; } Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -1388,6 +1388,7 @@ else return CallingConv::ARM_AAPCS; case CallingConv::Fast: + case CallingConv::Swift: case CallingConv::CXX_FAST_TLS: if (!Subtarget->isAAPCS_ABI()) { if (Subtarget->hasVFP2() && !Subtarget->isThumb1Only() && !isVarArg) Index: lib/Target/X86/X86CallingConv.td =================================================================== --- lib/Target/X86/X86CallingConv.td +++ lib/Target/X86/X86CallingConv.td @@ -192,6 +192,20 @@ CCIfType<[i64], CCAssignToReg<[RAX]>> ]>; +def RetCC_X86_64_Swift : CallingConv<[ + CCIfType<[i8] , CCAssignToReg<[AL, DL, CL, R8B]>>, + CCIfType<[i16], CCAssignToReg<[AX, DX, CX, R8W]>>, + CCIfType<[i32], CCAssignToReg<[EAX, EDX, ECX, R8D]>>, + CCIfType<[i64], CCAssignToReg<[RAX, RDX, RCX, R8]>>, + + CCIfType<[f32], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + CCIfType<[f64], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + + // MMX vector types are always returned in XMM0. + CCIfType<[x86mmx], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + CCDelegateTo +]>; + // X86-64 AnyReg return-value convention. No explicit register is specified for // the return-value. The register allocator is allowed and expected to choose // any free register. @@ -234,6 +248,9 @@ CCIfCC<"CallingConv::WebKit_JS", CCDelegateTo>, CCIfCC<"CallingConv::AnyReg", CCDelegateTo>, + // Handle Swift calls. + CCIfCC<"CallingConv::Swift", CCDelegateTo>, + // Handle explicit CC selection CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo>, CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo>, Index: lib/Target/X86/X86FastISel.cpp =================================================================== --- lib/Target/X86/X86FastISel.cpp +++ lib/Target/X86/X86FastISel.cpp @@ -2851,6 +2851,7 @@ case CallingConv::C: case CallingConv::Fast: case CallingConv::WebKit_JS: + case CallingConv::Swift: case CallingConv::X86_FastCall: case CallingConv::X86_64_Win64: case CallingConv::X86_64_SysV: Index: test/CodeGen/ARM/swift-ios.ll =================================================================== --- test/CodeGen/ARM/swift-ios.ll +++ test/CodeGen/ARM/swift-ios.ll @@ -0,0 +1,73 @@ +; RUN: llc -mtriple=armv7-apple-ios < %s | FileCheck %s + +define swiftcc float @t1(float %a, float %b) { +entry: +; CHECK: t1 +; CHECK-NOT: vmov +; CHECK: vadd.f32 + %a.addr = alloca float, align 4 + %b.addr = alloca float, align 4 + store float %a, float* %a.addr, align 4 + store float %b, float* %b.addr, align 4 + %0 = load float, float* %a.addr, align 4 + %1 = load float, float* %b.addr, align 4 + %add = fadd float %0, %1 + ret float %add +} + +define swiftcc double @t2(double %a, double %b) { +entry: +; CHECK: t2 +; CHECK-NOT: vmov +; CHECK: vadd.f64 + %a.addr = alloca double, align 8 + %b.addr = alloca double, align 8 + store double %a, double* %a.addr, align 8 + store double %b, double* %b.addr, align 8 + %0 = load double, double* %a.addr, align 8 + %1 = load double, double* %b.addr, align 8 + %add = fadd double %0, %1 + ret double %add +} + +define swiftcc double @t9(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, float %a, float %b) { +entry: +; CHECK-LABEL: t9: +; CHECK-NOT: vmov +; CHECK: vldr + %add = fadd float %a, %b + %conv = fpext float %add to double + ret double %conv +} + +define swiftcc double @t10(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %a, float %b, double %c) { +entry: +; CHECK-LABEL: t10: +; CHECK-NOT: vmov +; CHECK: vldr + %add = fadd double %a, %c + ret double %add +} + +define swiftcc float @t11(double %d0, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, float %a, double %b, float %c) { +entry: +; CHECK-LABEL: t11: +; CHECK: vldr + %add = fadd float %a, %c + ret float %add +} + +define swiftcc double @t12(double %a, double %b) { +entry: +; CHECK-LABEL: t12: +; CHECK: vstr + %add = fadd double %a, %b + %sub = fsub double %a, %b + %call = tail call swiftcc double @x(double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double 0.000000e+00, double %add, float 0.000000e+00, double %sub) + ret double %call +} + +declare swiftcc double @x(double, double, double, double, double, double, double, float, double) + +attributes #0 = { readnone } +attributes #1 = { readonly } Index: test/CodeGen/ARM/swift-return.ll =================================================================== --- test/CodeGen/ARM/swift-return.ll +++ test/CodeGen/ARM/swift-return.ll @@ -0,0 +1,130 @@ +; RUN: llc -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=armv7k-apple-ios8.0 -mcpu=cortex-a7 -verify-machineinstrs < %s -O0 | FileCheck --check-prefix=CHECK-O0 %s + +; RUN: llc -mtriple=armv7-apple-ios -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=armv7-apple-ios -verify-machineinstrs < %s -O0 | FileCheck --check-prefix=CHECK-O0 %s + +; Test how llvm handles return type of {i16, i8}. The return value will be passed in %r0 and %r1. +; CHECK-LABEL: test: +; CHECK: bl {{.*}}gen +; CHECK: sxth {{.*}}, r0 +; CHECK: sxtab r0, {{.*}}, r1 +; CHECK-O0-LABEL: test: +; CHECK-O0: bl {{.*}}gen +; CHECK-O0: sxth r0, r0 +; CHECK-O0: sxtb r1, r1 +; CHECK-O0: add r0, r0, r1 +define i16 @test(i32 %key) { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i16, i8 } @gen(i32 %0) + %v3 = extractvalue { i16, i8 } %call, 0 + %v1 = sext i16 %v3 to i32 + %v5 = extractvalue { i16, i8 } %call, 1 + %v2 = sext i8 %v5 to i32 + %add = add nsw i32 %v1, %v2 + %conv = trunc i32 %add to i16 + ret i16 %conv +} + +declare swiftcc { i16, i8 } @gen(i32) + +; We can't pass every return value in register, instead, pass everything in memroy. +; The caller provides space for the return value and passes the address in %r0. +; The first input argument will be in %r1. +; CHECK-LABEL: test2: +; CHECK: mov r1, r0 +; CHECK: mov r0, sp +; CHECK: bl {{.*}}gen2 +; CHECK-DAG: add +; CHECK-DAG: ldr {{.*}}, [sp, #16] +; CHECK-DAG: add +; CHECK-DAG: add +; CHECK-DAG: add +; CHECK-O0-LABEL: test2: +; CHECK-O0: str r0 +; CHECK-O0: mov r0, sp +; CHECK-O0: bl {{.*}}gen2 +; CHECK-O0-DAG: ldr {{.*}}, [sp] +; CHECK-O0-DAG: ldr {{.*}}, [sp, #4] +; CHECK-O0-DAG: ldr {{.*}}, [sp, #8] +; CHECK-O0-DAG: ldr {{.*}}, [sp, #12] +; CHECK-O0-DAG: ldr {{.*}}, [sp, #16] +; CHECK-O0-DAG: add +; CHECK-O0-DAG: add +; CHECK-O0-DAG: add +; CHECK-O0-DAG: add +define i32 @test2(i32 %key) #0 { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %0) + + %v3 = extractvalue { i32, i32, i32, i32, i32 } %call, 0 + %v5 = extractvalue { i32, i32, i32, i32, i32 } %call, 1 + %v6 = extractvalue { i32, i32, i32, i32, i32 } %call, 2 + %v7 = extractvalue { i32, i32, i32, i32, i32 } %call, 3 + %v8 = extractvalue { i32, i32, i32, i32, i32 } %call, 4 + + %add = add nsw i32 %v3, %v5 + %add1 = add nsw i32 %add, %v6 + %add2 = add nsw i32 %add1, %v7 + %add3 = add nsw i32 %add2, %v8 + ret i32 %add3 +} + +; The address of the return value is passed in %r0. +; CHECK-LABEL: gen2: +; CHECK-DAG: str r1, [r0] +; CHECK-DAG: str r1, [r0, #4] +; CHECK-DAG: str r1, [r0, #8] +; CHECK-DAG: str r1, [r0, #12] +; CHECK-DAG: str r1, [r0, #16] +; CHECK-O0-LABEL: gen2: +; CHECK-O0-DAG: str r1, [r0] +; CHECK-O0-DAG: str r1, [r0, #4] +; CHECK-O0-DAG: str r1, [r0, #8] +; CHECK-O0-DAG: str r1, [r0, #12] +; CHECK-O0-DAG: str r1, [r0, #16] +define swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %key) { + %Y = insertvalue { i32, i32, i32, i32, i32 } undef, i32 %key, 0 + %Z = insertvalue { i32, i32, i32, i32, i32 } %Y, i32 %key, 1 + %Z2 = insertvalue { i32, i32, i32, i32, i32 } %Z, i32 %key, 2 + %Z3 = insertvalue { i32, i32, i32, i32, i32 } %Z2, i32 %key, 3 + %Z4 = insertvalue { i32, i32, i32, i32, i32 } %Z3, i32 %key, 4 + ret { i32, i32, i32, i32, i32 } %Z4 +} + +; The return value {i32, i32, i32, i32} will be returned via registers %r0, %r1, %r2, %r3. +; CHECK-LABEL: test3: +; CHECK: bl {{.*}}gen3 +; CHECK: add r0, r0, r1 +; CHECK: add r0, r0, r2 +; CHECK: add r0, r0, r3 +; CHECK-O0-LABEL: test3: +; CHECK-O0: bl {{.*}}gen3 +; CHECK-O0: add r0, r0, r1 +; CHECK-O0: add r0, r0, r2 +; CHECK-O0: add r0, r0, r3 +define i32 @test3(i32 %key) #0 { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i32, i32, i32, i32 } @gen3(i32 %0) + + %v3 = extractvalue { i32, i32, i32, i32 } %call, 0 + %v5 = extractvalue { i32, i32, i32, i32 } %call, 1 + %v6 = extractvalue { i32, i32, i32, i32 } %call, 2 + %v7 = extractvalue { i32, i32, i32, i32 } %call, 3 + + %add = add nsw i32 %v3, %v5 + %add1 = add nsw i32 %add, %v6 + %add2 = add nsw i32 %add1, %v7 + ret i32 %add2 +} + +declare swiftcc { i32, i32, i32, i32 } @gen3(i32 %key) Index: test/CodeGen/X86/swift-return.ll =================================================================== --- test/CodeGen/X86/swift-return.ll +++ test/CodeGen/X86/swift-return.ll @@ -0,0 +1,135 @@ +; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-unknown-unknown | FileCheck %s +; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-unknown-unknown -O0 | FileCheck --check-prefix=CHECK-O0 %s + +; Test how llvm handles return type of {i16, i8}. The return value will be passed in %eax and %dl. +; clang actually returns i32 instead of {i16, i8}. +; CHECK-LABEL: test: +; CHECK: movl %edi +; CHECK: callq gen +; CHECK: movsbl %dl +; CHECK: addl %{{.*}}, %eax +; CHECK-O0-LABEL: test +; CHECK-O0: movl %edi +; CHECK-O0: callq gen +; CHECK-O0: movswl %ax +; CHECK-O0: movsbl %dl +; CHECK-O0: addl +; CHECK-O0: movw %{{.*}}, %ax +define i16 @test(i32 %key) { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i16, i8 } @gen(i32 %0) + %v3 = extractvalue { i16, i8 } %call, 0 + %v1 = sext i16 %v3 to i32 + %v5 = extractvalue { i16, i8 } %call, 1 + %v2 = sext i8 %v5 to i32 + %add = add nsw i32 %v1, %v2 + %conv = trunc i32 %add to i16 + ret i16 %conv +} + +declare swiftcc { i16, i8 } @gen(i32) + +; We can't pass every return value in register, instead, pass everything in memroy. +; The caller provides space for the return value and passes the address in %rdi. +; The first input argument will be in %rsi. +; CHECK-LABEL: test2: +; CHECK: leaq (%rsp), %rdi +; CHECK: movl %{{.*}}, %esi +; CHECK: callq gen2 +; CHECK: movl (%rsp) +; CHECK-DAG: addl 4(%rsp) +; CHECK-DAG: addl 8(%rsp) +; CHECK-DAG: addl 12(%rsp) +; CHECK-DAG: addl 16(%rsp) +; CHECK-O0-LABEL: test2: +; CHECK-O0-DAG: leaq (%rsp), %rdi +; CHECK-O0-DAG: movl {{.*}}, %esi +; CHECK-O0: callq gen2 +; CHECK-O0-DAG: movl (%rsp) +; CHECK-O0-DAG: movl 4(%rsp) +; CHECK-O0-DAG: movl 8(%rsp) +; CHECK-O0-DAG: movl 12(%rsp) +; CHECK-O0-DAG: movl 16(%rsp) +; CHECK-O0: addl +; CHECK-O0: addl +; CHECK-O0: addl +; CHECK-O0: addl +; CHECK-O0: movl %{{.*}}, %eax +define i32 @test2(i32 %key) #0 { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %0) + + %v3 = extractvalue { i32, i32, i32, i32, i32 } %call, 0 + %v5 = extractvalue { i32, i32, i32, i32, i32 } %call, 1 + %v6 = extractvalue { i32, i32, i32, i32, i32 } %call, 2 + %v7 = extractvalue { i32, i32, i32, i32, i32 } %call, 3 + %v8 = extractvalue { i32, i32, i32, i32, i32 } %call, 4 + + %add = add nsw i32 %v3, %v5 + %add1 = add nsw i32 %add, %v6 + %add2 = add nsw i32 %add1, %v7 + %add3 = add nsw i32 %add2, %v8 + ret i32 %add3 +} + +; The address of the return value is passed in %rdi. +; On return, %rax will contain the adddress that has been passed in by the caller in %rdi. +; CHECK-LABEL: gen2: +; CHECK: movl %esi, 16(%rdi) +; CHECK: movl %esi, 12(%rdi) +; CHECK: movl %esi, 8(%rdi) +; CHECK: movl %esi, 4(%rdi) +; CHECK: movl %esi, (%rdi) +; CHECK: movq %rdi, %rax +; CHECK-O0-LABEL: gen2: +; CHECK-O0-DAG: movl %esi, 16(%rdi) +; CHECK-O0-DAG: movl %esi, 12(%rdi) +; CHECK-O0-DAG: movl %esi, 8(%rdi) +; CHECK-O0-DAG: movl %esi, 4(%rdi) +; CHECK-O0-DAG: movl %esi, (%rdi) +; CHECK-O0-DAG: movq %rdi, %rax +define swiftcc { i32, i32, i32, i32, i32 } @gen2(i32 %key) { + %Y = insertvalue { i32, i32, i32, i32, i32 } undef, i32 %key, 0 + %Z = insertvalue { i32, i32, i32, i32, i32 } %Y, i32 %key, 1 + %Z2 = insertvalue { i32, i32, i32, i32, i32 } %Z, i32 %key, 2 + %Z3 = insertvalue { i32, i32, i32, i32, i32 } %Z2, i32 %key, 3 + %Z4 = insertvalue { i32, i32, i32, i32, i32 } %Z3, i32 %key, 4 + ret { i32, i32, i32, i32, i32 } %Z4 +} + +; The return value {i32, i32, i32, i32} will be returned via registers %eax, %edx, %ecx, %r8d. +; CHECK-LABEL: test3: +; CHECK: callq gen3 +; CHECK: addl %edx, %eax +; CHECK: addl %ecx, %eax +; CHECK: addl %r8d, %eax +; CHECK-O0-LABEL: test3: +; CHECK-O0: callq gen3 +; CHECK-O0: addl %edx, %eax +; CHECK-O0: addl %ecx, %eax +; CHECK-O0: addl %r8d, %eax +define i32 @test3(i32 %key) #0 { +entry: + %key.addr = alloca i32, align 4 + store i32 %key, i32* %key.addr, align 4 + %0 = load i32, i32* %key.addr, align 4 + %call = call swiftcc { i32, i32, i32, i32 } @gen3(i32 %0) + + %v3 = extractvalue { i32, i32, i32, i32 } %call, 0 + %v5 = extractvalue { i32, i32, i32, i32 } %call, 1 + %v6 = extractvalue { i32, i32, i32, i32 } %call, 2 + %v7 = extractvalue { i32, i32, i32, i32 } %call, 3 + + %add = add nsw i32 %v3, %v5 + %add1 = add nsw i32 %add, %v6 + %add2 = add nsw i32 %add1, %v7 + ret i32 %add2 +} + +declare swiftcc { i32, i32, i32, i32 } @gen3(i32 %key)