Skip to content

Bad quality code for Clone on enum types #69174

@reinerp

Description

@reinerp

For this Rust code, we get some pretty bad assembly:

#[derive(Clone)]
pub enum Foo {
    A(u8),
    B(bool),
}

#[derive(Clone)]
pub enum Bar {
    C(Foo),
    D(u8),
}

pub fn clone_foo(f: &Foo) -> Foo {
    f.clone()
}

pub fn clone_bar(b: &Bar) -> Bar {
    b.clone()
}

(Playground)

Assembly:

playground::clone_bar:
	movb	1(%rdi), %al
	cmpb	$1, (%rdi)
	jne	.LBB1_2
	xorl	%ecx, %ecx
	movl	$1, %edx
	jmp	.LBB1_3

.LBB1_2:
	movzbl	2(%rdi), %edx
	xorl	%ecx, %ecx
	testb	%dl, %dl
	setne	%cl
	cmpb	$1, %al
	sete	%al
	cmovnel	%edx, %ecx
	shll	$16, %ecx
	xorl	%edx, %edx

.LBB1_3:
	orl	%edx, %ecx
	movzbl	%al, %eax
	shll	$8, %eax
	orl	%ecx, %eax
	retq

To see that it's possibly to do better, we can simply add a Copy instance to the types. Then the code even for Clone gets much better:

#[derive(Clone, Copy)]
pub enum Foo {
    A(u8),
    B(bool),
}

#[derive(Clone, Copy)]
pub enum Bar {
    C(Foo),
    D(u8),
}

pub fn clone_foo(f: &Foo) -> Foo {
    f.clone()
}

pub fn clone_bar(b: &Bar) -> Bar {
    b.clone()
}

(Playground)

Assembly:

playground::clone_bar:
	movzwl	(%rdi), %ecx
	movzbl	2(%rdi), %eax
	shll	$16, %eax
	orl	%ecx, %eax
	retq

It's still not perfect (why are there two 2-byte loads instead of a single 4-byte load?) but it's much better.

Metadata

Metadata

Assignees

Labels

A-codegenArea: Code generationC-enhancementCategory: An issue proposing an enhancement or a PR with one.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions