# Strange codegen for type with small union fields

**URL:** <https://discourse.julialang.org/t/strange-codegen-for-type-with-small-union-fields/35773>\
**Category:** Performance\
**Created:** [March 9, 2020, 9:43pm UTC](https://discourse.julialang.org/t/strange-codegen-for-type-with-small-union-fields/35773 "2020-03-09T21:43:00Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Christian\_Rorvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christian_rorvik/32/965_2.png) [@Christian\_Rorvik](https://discourse.julialang.org/u/Christian_Rorvik)\
**Post date:** [March 9, 2020, 9:43pm UTC](https://discourse.julialang.org/t/strange-codegen-for-type-with-small-union-fields/35773/1 "2020-03-09T21:43:00Z")

</div>

## Context

Working on an intrusive containers package, for users (like me) who need allocation free datastructures. Putting together the very beginnings of some expertiments I spotted some strange codegen behavior.

## Julia Version

```julia-auto
Julia Version 1.3.1
Commit 2d5741174c (2019-12-30 21:36 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

```

## Original Experiment

Consider a linked list node, `next` and `prev` are either references or terminal. Going with the canonical `Union{T, Nothing}`, assigning `nothing` to `next` generates unexpected code (assigning `Node` looks fine).

```Julia
module Foo
    mutable struct Node
        next::Union{Node, Nothing}
        prev::Union{Node, Nothing}
        value::Int64
    end
    function setnext!(x::Node, next::Union{Node, Nothing})
        x.next = next
        x
    end
end
code_native(Foo.setnext!, (Foo.Node, Nothing))

```

Outputs:

```julia-auto
; ┌ @ In[97]:8 within `setnext!'
	pushq	%rbp
	movq	%rsp, %rbp
	pushq	%rsi
	subq	$72, %rsp
	movq	%rdx, -40(%rbp)
	movq	(%rdx), %rsi
	movq	%rsi, -32(%rbp)
	movq	$341181352, -24(%rbp) # imm = 0x145603A8
	movq	$jl_system_image_data, -16(%rbp)
	movabsq	$"japi1_setproperty!_18314", %rax
	leaq	-32(%rbp), %rdx
	movl	$jl_system_image_data, %ecx
	movl	$3, %r8d
	callq	*%rax
; │ @ In[97]:9 within `setnext!'
	movq	%rsi, %rax
	addq	$72, %rsp
	popq	%rsi
	popq	%rbp
	retq
	nopl	(%rax)

```

## Adjustment A

Removing the `value` field makes codegen more optimal.

```Julia
module Foo
    mutable struct Node
        next::Union{Node, Nothing}
        prev::Union{Node, Nothing}
    end
    function setnext!(x::Node, next::Union{Node, Nothing})
        x.next = next
        x
    end
end
code_native(Foo.setnext!, (Foo.Node, Nothing))

```

Outputs:

```julia-auto
; ┌ @ In[98]:7 within `setnext!'
	pushq	%rbp
	movq	%rsp, %rbp
	pushq	%rax
	movq	%rdx, -8(%rbp)
	movq	(%rdx), %rax
; │┌ @ Base.jl:21 within `setproperty!'
	movq	$jl_system_image_data, (%rax)
; │└
; │ @ In[98]:8 within `setnext!'
	addq	$8, %rsp
	popq	%rbp
	retq
	nopl	(%rax)

```

## Adjustment B

Replacing the `prev` field, not accessed in the tested function, not altering the size or layout of `Node`, nonetheless yields the same codegen improvement.

```Julia
module Foo
    mutable struct Nil end
    mutable struct Node
        next::Union{Node, Nothing}
        prev::Union{Node, Nil}
        value::Int64
    end
    function setnext!(x::Node, next::Union{Node, Nothing})
        x.next = next
        x
    end
end
code_native(Foo.setnext!, (Foo.Node, Nothing))

```

Outputs:

```julia-auto
; ┌ @ In[99]:9 within `setnext!'
	pushq	%rbp
	movq	%rsp, %rbp
	pushq	%rax
	movq	%rdx, -8(%rbp)
	movq	(%rdx), %rax
; │┌ @ Base.jl:21 within `setproperty!'
	movq	$jl_system_image_data, (%rax)
; │└
; │ @ In[99]:10 within `setnext!'
	addq	$8, %rsp
	popq	%rbp
	retq
	nopl	(%rax)

```

## Question

What’s going on here? I feel like I might have struck upon some brittleness in the optimizer. I’ve validated what looks like strange and suboptimal codegen also suffers poor performance.
