Picaud Vincent
Picaud Vincent

Reputation: 10982

Julia: how to mimic some "typedef/using" we use in C++ (and without perfs penalty)?

Basically, I want to provide some type information in a struct A that will be used later to define the return type of the foo_1 function.

Here is the Julia code I have so far:

struct A
    type::DataType
end

foo_1(a::A)::a.type = 2018

Usage example:

julia> a=A(Float64)
julia> foo_1(a)
2018.0

-> This work as expected: 2018 is converted into a.type type, here a Float64

However, my problem/interrogation come from that fact that, when compared with the function foo_2 that do basically the same thing without using x.type

foo_2(a::A)::Float64 = 2018

there is an important difference in the generated code:

julia> @code_native foo_2(a)
    .text
Filename: REPL[4]
    pushq   %rbp
    movq    %rsp, %rbp
    movabsq $139943184603960, %rax  # imm = 0x7F470FCE9B38
Source line: 1
    movsd   (%rax), %xmm0           # xmm0 = mem[0],zero
    popq    %rbp
    retq
    nopw    %cs:(%rax,%rax)

-> This is OK

However for foo_1(a::A)::a.type function:

julia> @code_native foo_1(a)
    .text
Filename: REPL[3]
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %r15
    pushq   %r14
    pushq   %rbx
    subq    $56, %rsp
    movq    %rdi, %r14
    movq    %fs:0, %r15
    addq    $-10888, %r15           # imm = 0xD578
    leaq    -48(%rbp), %rdi
    xorps   %xmm0, %xmm0
    movups  %xmm0, -48(%rbp)
    movq    $0, -32(%rbp)
    movq    $8, -72(%rbp)
    movq    (%r15), %rax
    movq    %rax, -64(%rbp)
    leaq    -72(%rbp), %rax
    movq    %rax, (%r15)
    movq    $0, -56(%rbp)
Source line: 1
    movq    (%r14), %rax
    movabsq $139943153507008, %rcx  # imm = 0x7F470DF41AC0
    leaq    634701288(%rcx), %rdx
    movq    %rdx, -48(%rbp)
    movq    %rax, -40(%rbp)
    movq    %rcx, -32(%rbp)
    movabsq $jl_apply_generic, %rax
    movl    $3, %esi
    callq   *%rax
    movq    %rax, %rbx
    movq    %rbx, -56(%rbp)
    movq    (%r14), %rsi
    movabsq $jl_typeassert, %rax
    movq    %rbx, %rdi
    callq   *%rax
    movq    -64(%rbp), %rax
    movq    %rax, (%r15)
    movq    %rbx, %rax
    addq    $56, %rsp
    popq    %rbx
    popq    %r14
    popq    %r15
    popq    %rbp
    retq

-> I am surprised that Julia JIT is not able to generate an optimized function. IMHO it has all the required information at the call site foo_1(a) to do so.

--> I fear that the difference in generated code is so big that I will get bad performance if I use the approach with a.type.

So my questions are:


Note: I could have written

struct B{T}
end

foo_3{T}(b::B{T})::T  = 2018

That works (in the sense that native code of foo_3 is the same as foo_2), however this is an awkward solution to define several types:

struct B{T1,T2,T3,...}
end

C++ equivalent would be, without "parasite" template parameters:

struct B {
    using T1 = ...;
    using T2 = ...;
    using T3 = ...;
    ...
};

Upvotes: 2

Views: 480

Answers (1)

mbauman
mbauman

Reputation: 31362

The key is simply that Julia doesn't know what type A.type is beyond the fact that it's just some DataType. You can use a parametric type to provide this information:

julia> struct A{T}
           typ::Type{T}
       end
       foo_1(a::A)::a.typ = 2018
foo_1 (generic function with 1 method)

julia> foo_1(A(Float64))
2018.0

julia> @code_native foo_1(A(Float64))
    .section    __TEXT,__text,regular,pure_instructions
; Function foo_1 {
; Location: REPL[9]:5
    movabsq $4572864984, %rax       ## imm = 0x1109061D8
    movsd   (%rax), %xmm0           ## xmm0 = mem[0],zero
    retq
    nop
;}

Upvotes: 2

Related Questions