Skip to content

cmd/compile: unsafe.Pointer arithmetic causes insertion of redundant nil checks #27180

Closed
@FlorianUekermann

Description

@FlorianUekermann

Most testing done using go version go1.10.1 linux/amd64
I have tried a bunch of releases, from 1.7, to 1.10.3

Caveat: I may just be confused about something, but I have spent quite some time trying to come up with reasons why the generated code makes sense and the mailing list didn't provide an answer either.

The pointer arithmetic pattern described in the unsafe documentation seems to cause the compiler to emit assembly to calculate and dereference the same pointer twice. The simplest way to reproduce this is:

func getElement1(a unsafe.Pointer) (r uint64) {
	return *(*uint64)(unsafe.Pointer(uintptr(a) + 8))
}

Looking at the (shortened) Go assembly we see this:

MOVQ    "".a(SP), AX
LEAQ    8(AX), CX
TESTB   AX, (CX)
MOVQ    8(AX), AX
MOVQ    AX, "".r+8(SP)

I would have expected something like this function (which I have tested and it seems to have the same behavior):

// func getElement1Asm(a unsafe.Pointer) (r uint64)
TEXT ·getElement1Asm(SB),NOSPLIT,$0
	MOVQ    a+8(SP), R8  // Why 8 instead of 0 like above?
	MOVQ	8(R8), R8
	MOVQ    R8, r+16(SP)
	RET

I have tried to come up with explanations for what the LEAQ, TESTB sequence is good for, but failed. It seems like the compiler is inserting the equivalent of _ = *(*uint64)(unsafe.Pointer(uintptr(a) + 8)) before the return statement.
I have tested countless variants of similar and not so similar functions containing pointer arithmetic and the result is always that both address calculation and dereference are duplicated, if an address is changed by a non-zero amount (*(*uint64)(unsafe.Pointer(uintptr(a) + 0)) doesn't have this issue).

I realize that this technically doesn't violate the spec or documented behavior, but the situation seems unfortunate (yes, I benchmarked the impact on less contrived examples).

ssa.html.log (renamed to make github happy)

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performance

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions