Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate addcarryx/subborrowx wrappers in Go #1006

Merged
merged 2 commits into from
Aug 7, 2021

Conversation

JasonGross
Copy link
Collaborator

This is a partial fix for item 1 of
#949 (comment) also
mentioned at golang/go#40171 (comment)

Unfortunately, we still cast the arguments to uint1 because we don't
have enough information in the right places to relax the casts. We
really want a fused absint/rewriting pass, where we get access to true
bounds information rather than just casts.

cc @Yawning, how does this do performance-wise?

@Yawning
Copy link

Yawning commented Aug 4, 2021

Unfortunately, we still cast the arguments to uint1 because we don't
have enough information in the right places to relax the casts. We
really want a fused absint/rewriting pass, where we get access to true
bounds information rather than just casts.

cc @Yawning, how does this do performance-wise?

So it turns out that I missed testing "wrapper removal" in isolation from "cast removal" in our back and forth in the issue due just copy-pasting my optimized code for the (wrapper removed version), when it was something I really should have done. This commit removes the NOP wall due to the inliner, but the casts are the bulk of the perf penalty.

For this snippet:

	x55, x56 = bits.Add64(x17, x51, uint64(0x0))
	var x57 uint64
	x57, _ = bits.Add64(x18, x53, uint64(uint1(x56)))

With casts:

	0x0273 00627 (curve25519.go:196)	MOVQ	"".x17+248(SP), R15
	0x027b 00635 (curve25519.go:196)	ADDQ	R15, BX
	0x027e 00638 (curve25519.go:196)	SBBQ	R15, R15
	0x0281 00641 (curve25519.go:196)	NEGQ	R15
	0x0284 00644 (curve25519.go:198)	MOVBLZX	R15B, R15
	0x0288 00648 (curve25519.go:198)	NEGL	R15
	0x028b 00651 (curve25519.go:198)	ADCQ	CX, R8

Without casts (uint1 made to an alias of uint64):

	0x0268 00616 (curve25519.go:196)	MOVQ	"".x17+248(SP), R15
	0x0270 00624 (curve25519.go:196)	ADDQ	R15, BX
	0x0273 00627 (curve25519.go:198)	ADCQ	CX, R8

I assume that unilaterally type-casting uint1 to uint64 has a potential correctness impact due to the use of the type for things other than the carry like thus (though there shouldn't be anything in the extra 5-bits?):

	x158 := uint1((x157 >> 51))
	x159 := (x157 & 0x7ffffffffffff)
	x160 := (uint64(x158) + x142)

That said, if defining a type that is only used for carries/borrows is easier than relaxing casts (ie: something like x57, _ = bits.Add64(x18, x53, uint64(carry1(x56))), where the carry type for Go can be a uint64) then that would eliminate the 4 instructions emitted per cast.

Sorry for the oversight when doing the initial round of benchmarks, when HACS goes back to being an in-person thing, remind me that I owe you a beverage of your choice.

This is a partial fix for item 1 of
mit-plv#949 (comment) also
mentioned at golang/go#40171 (comment)

Unfortunately, we still cast the arguments to uint1 because we don't
have enough information in the right places to relax the casts.  We
really want a fused absint/rewriting pass, where we get access to true
bounds information rather than just casts.
For performance reasons.  Note that this is unsound, but having the
carry type be 8 bits rather than 1 bit was already unsound, and this is
no more unsound.  The narrowness of the carry type is not used in
practice in the code, though we should still someday include it in the
proofs.
@JasonGross
Copy link
Collaborator Author

@Yawning I've updated the typedef to be to uint64. Does this code do better?

@Yawning
Copy link

Yawning commented Aug 7, 2021

@Yawning I've updated the typedef to be to uint64. Does this code do better?

name         old time/op  new time/op  delta
CarryMult-8  61.8ns ± 0%  44.6ns ± 0%  -27.77%  (p=0.008 n=5+5)

A quick check of the generated assembly also looks sensible.

@JasonGross JasonGross merged commit 464ebb0 into mit-plv:master Aug 7, 2021
@JasonGross JasonGross deleted the go-inline-add64 branch August 7, 2021 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants