Index: llvm/trunk/docs/BitCodeFormat.rst =================================================================== --- llvm/trunk/docs/BitCodeFormat.rst +++ llvm/trunk/docs/BitCodeFormat.rst @@ -757,6 +757,7 @@ * ``anyregcc``: code 13 * ``preserve_mostcc``: code 14 * ``preserve_allcc``: code 15 + * ``swiftcc`` : code 16 * ``cxx_fast_tlscc``: code 17 * ``x86_stdcallcc``: code 64 * ``x86_fastcallcc``: code 65 Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -427,6 +427,9 @@ - On X86-64 the callee preserves all general purpose registers, except for RDI and RAX. +"``swiftcc``" - This calling convention is used for Swift language. + - On X86-64 RCX and R8 are available for additional integer returns, and + XMM2 and XMM3 are available for additional FP/vector returns. "``cc ``" - Numbered convention Any calling convention may be specified by number, allowing target-specific calling conventions to be used. Target specific Index: llvm/trunk/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLLexer.cpp +++ llvm/trunk/lib/AsmParser/LLLexer.cpp @@ -590,6 +590,7 @@ KEYWORD(x86_64_sysvcc); KEYWORD(x86_64_win64cc); KEYWORD(webkit_jscc); + KEYWORD(swiftcc); KEYWORD(anyregcc); KEYWORD(preserve_mostcc); KEYWORD(preserve_allcc); Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -1610,6 +1610,7 @@ /// ::= 'preserve_mostcc' /// ::= 'preserve_allcc' /// ::= 'ghccc' +/// ::= 'swiftcc' /// ::= 'x86_intrcc' /// ::= 'hhvmcc' /// ::= 'hhvm_ccc' @@ -1644,6 +1645,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: llvm/trunk/lib/AsmParser/LLToken.h =================================================================== --- llvm/trunk/lib/AsmParser/LLToken.h +++ llvm/trunk/lib/AsmParser/LLToken.h @@ -100,6 +100,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: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/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: llvm/trunk/lib/Target/X86/X86CallingConv.td =================================================================== --- llvm/trunk/lib/Target/X86/X86CallingConv.td +++ llvm/trunk/lib/Target/X86/X86CallingConv.td @@ -192,6 +192,24 @@ CCIfType<[i64], CCAssignToReg<[RAX]>> ]>; +def RetCC_X86_64_Swift : CallingConv<[ + // For integers, ECX, R8D can be used as extra return registers. + CCIfType<[i1], CCPromoteToType>, + 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]>>, + + // XMM0, XMM1, XMM2 and XMM3 can be used to return FP values. + CCIfType<[f32], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + CCIfType<[f64], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + CCIfType<[f128], CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>, + + // MMX vector types are returned in XMM0, XMM1, XMM2 and XMM3. + 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 +252,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: llvm/trunk/lib/Target/X86/X86FastISel.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86FastISel.cpp +++ llvm/trunk/lib/Target/X86/X86FastISel.cpp @@ -2852,6 +2852,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: llvm/trunk/test/CodeGen/X86/swift-return.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/swift-return.ll +++ llvm/trunk/test/CodeGen/X86/swift-return.ll @@ -0,0 +1,201 @@ +; 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 + +@var = global i32 0 + +; Test how llvm handles return type of {i16, i8}. The return value will be +; passed in %eax and %dl. +; 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) + +; If we can't pass every return value in register, we will 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) + +; The return value {float, float, float, float} will be returned via registers +; %xmm0, %xmm1, %xmm2, %xmm3. +; CHECK-LABEL: test4: +; CHECK: callq gen4 +; CHECK: addss %xmm1, %xmm0 +; CHECK: addss %xmm2, %xmm0 +; CHECK: addss %xmm3, %xmm0 +; CHECK-O0-LABEL: test4: +; CHECK-O0: callq gen4 +; CHECK-O0: addss %xmm1, %xmm0 +; CHECK-O0: addss %xmm2, %xmm0 +; CHECK-O0: addss %xmm3, %xmm0 +define float @test4(float %key) #0 { +entry: + %key.addr = alloca float, align 4 + store float %key, float* %key.addr, align 4 + %0 = load float, float* %key.addr, align 4 + %call = call swiftcc { float, float, float, float } @gen4(float %0) + + %v3 = extractvalue { float, float, float, float } %call, 0 + %v5 = extractvalue { float, float, float, float } %call, 1 + %v6 = extractvalue { float, float, float, float } %call, 2 + %v7 = extractvalue { float, float, float, float } %call, 3 + + %add = fadd float %v3, %v5 + %add1 = fadd float %add, %v6 + %add2 = fadd float %add1, %v7 + ret float %add2 +} + +declare swiftcc { float, float, float, float } @gen4(float %key) + +; CHECK-LABEL: consume_i1_ret: +; CHECK: callq produce_i1_ret +; CHECK: andb $1, %al +; CHECK: andb $1, %dl +; CHECK: andb $1, %cl +; CHECK: andb $1, %r8b +; CHECK-O0-LABEL: consume_i1_ret: +; CHECK-O0: callq produce_i1_ret +; CHECK-O0: andb $1, %al +; CHECK-O0: andb $1, %dl +; CHECK-O0: andb $1, %cl +; CHECK-O0: andb $1, %r8b +define void @consume_i1_ret() { + %call = call swiftcc { i1, i1, i1, i1 } @produce_i1_ret() + %v3 = extractvalue { i1, i1, i1, i1 } %call, 0 + %v5 = extractvalue { i1, i1, i1, i1 } %call, 1 + %v6 = extractvalue { i1, i1, i1, i1 } %call, 2 + %v7 = extractvalue { i1, i1, i1, i1 } %call, 3 + %val = zext i1 %v3 to i32 + store i32 %val, i32* @var + %val2 = zext i1 %v5 to i32 + store i32 %val2, i32* @var + %val3 = zext i1 %v6 to i32 + store i32 %val3, i32* @var + %val4 = zext i1 %v7 to i32 + store i32 %val4, i32* @var + ret void +} + +declare swiftcc { i1, i1, i1, i1 } @produce_i1_ret()