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

Bit-field sign extension pattern results in redundant shifts #89

Open
michaeljclark opened this Issue Aug 17, 2017 · 1 comment

Comments

Projects
None yet
1 participant
@michaeljclark

michaeljclark commented Aug 17, 2017

See here: https://cx.rv8.io/g/JtEZL6

template <typename T, unsigned B>
inline T signextend(const T x)
{
  struct {T x:B;} s;
  return s.x = x;
}

int sx5(int x) {
  return signextend<signed int,5>(x);
}

expands to

sx5(int):
  slliw a0,a0,3
  slliw a0,a0,24
  sraiw a0,a0,24
  sraiw a0,a0,3

but really should be:

sx5(int):
  slliw a0,a0,27
  sraiw a0,a0,27

should probably be raised as a bug on upstream gcc as it affects x86. It's shifting by 24 then by 3. There must be some target independent logic that splits shifts for bitfield accesses. We can link to this bug in an email, and the gcc developers can raise an upstream bug, if they believe it is a bug, so we can get a fix into a point release.

sx5(int):
  lea eax, [0+rdi*8]
  sar al, 3
  movsx eax, al
  ret
@michaeljclark

This comment has been minimized.

Show comment
Hide comment
@michaeljclark

michaeljclark Aug 18, 2017

This bug appears to be target independent. I've confirmed the same code-gen is present in a Dec 2016 gcc 6.1.0 build. It's almost as if gcc is narrowing to a char as a distinct step.

	.file	"sx.cc"
	.option nopic
	.text
	.align	2
	.globl	_Z3sx5i
	.type	_Z3sx5i, @function
_Z3sx5i:
.LFB1:
	sllw	a0,a0,3
	sllw	a0,a0,24
	sraw	a0,a0,24
	sraw	a0,a0,3
	ret
.LFE1:
	.size	_Z3sx5i, .-_Z3sx5i
	.ident	"GCC: (GNU) 6.1.0"

Hey. It is. It breaks into 'char' or 'short' before doing the remaining shift amount, and it does so on aarch64 aswell. We should probably file a bug in GCC bugzilla:

https://cx.rv8.io/g/h6UJcw

template <typename T, unsigned B>
inline T signextend(const T x)
{
  struct {T x:B;} s;
  return s.x = x;
}

int sx3(int x) { return signextend<signed int,3>(x); }
int sx5(int x) { return signextend<signed int,5>(x); }
int sx11(int x) { return signextend<signed int,11>(x); }
int sx14(int x) { return signextend<signed int,14>(x); }
int sx19(int x) { return signextend<signed int,19>(x); }

michaeljclark commented Aug 18, 2017

This bug appears to be target independent. I've confirmed the same code-gen is present in a Dec 2016 gcc 6.1.0 build. It's almost as if gcc is narrowing to a char as a distinct step.

	.file	"sx.cc"
	.option nopic
	.text
	.align	2
	.globl	_Z3sx5i
	.type	_Z3sx5i, @function
_Z3sx5i:
.LFB1:
	sllw	a0,a0,3
	sllw	a0,a0,24
	sraw	a0,a0,24
	sraw	a0,a0,3
	ret
.LFE1:
	.size	_Z3sx5i, .-_Z3sx5i
	.ident	"GCC: (GNU) 6.1.0"

Hey. It is. It breaks into 'char' or 'short' before doing the remaining shift amount, and it does so on aarch64 aswell. We should probably file a bug in GCC bugzilla:

https://cx.rv8.io/g/h6UJcw

template <typename T, unsigned B>
inline T signextend(const T x)
{
  struct {T x:B;} s;
  return s.x = x;
}

int sx3(int x) { return signextend<signed int,3>(x); }
int sx5(int x) { return signextend<signed int,5>(x); }
int sx11(int x) { return signextend<signed int,11>(x); }
int sx14(int x) { return signextend<signed int,14>(x); }
int sx19(int x) { return signextend<signed int,19>(x); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment