-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: cmd/go: add build tags for 32-bit and 64-bit architectures #33388
Comments
We do this in the runtime:
You could do a similar thing with int/uint and then write your
|
For what it's worth, we can see 32-bit vs. 64-bit in runtime/lfstack_32bit.go vs. runtime/lfstack_64bit.go and in runtime/hash32.go vs. runtime/hash64.go. |
I'm not against this proposal, but the given example doesn't motivate me. With build tags you have to write each function twice. With appropriate constants you only have to write them once. |
Also see #29982, which saves you from computing the sizes yourself. |
@randall77 My point here is that writing an optimised function twice might be exactly what you're after. Using a type-specific constant could be a possible solution, but might not always work. @smasher164 That's a good suggestion. It's a bit unfortunate that the proposal wasn't considered yet, but Let me see if I can come up with an example where constants won't work. |
If you have a constant you can always write two different implementations if you want. Either:
or
Either way if |
Unfortunately, this does not apply to numeric literals: package main
import "testing"
const intSize = 4 + (^uint(0)>>63) * 4
func TestInt(t *testing.T) {
var v []int
if intSize == 8 {
v = []int{ -0x7ffffffffffffffe, 0x7ffffffffffffffe, -0x7fffffffffffffff, 0x7fffffffffffffff }
} else {
v = []int{ -0x7ffffffe, 0x7ffffffe, -0x7fffffff, 0x7fffffff }
}
t.Logf("intSize=%d v[0]=%d", intSize, v[0])
} will produce the following, when compiled on 32bit:
|
@onitake, the way to avoid that issue is typically to write constants like intSize that serve as masks and then mask the values. Or in this case: const maxInt = 1<<(intSize*8-1) - 1 It's not ideal but it doesn't come up too often and is much lower complexity to maintain than separate files with separate build tags. |
🤔 Hmmmmm... I suppose I can do it this way. I still think it's overly cryptic and counter-intuitive, though. |
Issue #28538 suggested adding math.MaxInt etc and was accepted but never implemented for Go 1.13. It is still open and can be implemented for Go 1.14. Assuming that does happen, then the solution to #33388 (comment) is to use those named constants. Given the multiple (and usually much better) ways to write 32- or 64-bit specific code, it seems like adding build tags is heavy-weight and redundant. It seems like we should decline adding build tags based on architecture size. Any thoughts? |
It might depend on the perspective, but 32/64 bit build tags don't seem particularly "heavy-weight" to me... |
For the reasons in the past two comments, in the absence of a common use case where the build tag is the best way to engineer the split, this issue seems to be a likely decline. Leaving open for a week for final comments. |
Marked this last week as likely decline w/ call for last comments (#33388 (comment)). |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Unknown
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I'm working on a slightly specialised math utility library that exports functions similiar to
math.Abs
, but for various data types and with certain close-to-hardware optimisations.Since Go makes no special conventions for the generic
int
anduint
integer types, it is difficult to provide universal implementations for all supported GOARCHs.It is also very hard to provide unit tests that work across architectures, leading to tests limited to specific architectures, on top of the impossibility to make them future-proof.
As an example, consider the optimised code for calculating the absolute value of an
int64
described here: http://cavaliercoder.com/blog/optimized-abs-for-int64-in-go.htmlSuch an implementation will work well for well-defined data types like
int32
andint64
, but notint
.What did you expect to see?
Go should make it very easy to separate code into 32-bit architecture and 64-bit architecture code path by using some sort of generic build tag:
What did you see instead?
There is no such build tag, leading to ugly hacks such as using
unsafe.SizeOf(int)
to separate code paths or limiting optimised code to only specific GOARCHs:// +build 386 arm armbe mips mipsle ppc s390 sparc
// +build amd64 amd64p32 arm64 arm64be ppc64 ppc64le mips64 mips64le mips64p32 mips64p32le s390x sparc64
The text was updated successfully, but these errors were encountered: