gnu / gcc / 1f16a020acbea0af26209478990b83b1a1ba3a2b / . / gcc / testsuite / gcc.target / s390 / insv-2.c

/* { dg-do compile } */ | |

/* { dg-options "-O3 -march=zEC12 -mzarch" } */ | |

unsigned long | |

foo1 (unsigned long a, unsigned long b) | |

{ | |

return (a << 5) | (b & (((1UL << 5) - 1))); | |

} | |

/* This generates very different RTX than foo1. The output reg (r2) | |

matches the unshifted argument. So it actually is a | |

(set (zero_extract a 59 0) b) */ | |

unsigned long | |

foo2 (unsigned long a, unsigned long b) | |

{ | |

return (b << 5) | (a & (((1UL << 5) - 1))); | |

} | |

/* risbgn cannot be used when less bits are removed with the mask. */ | |

unsigned long | |

foo1b (unsigned long a, unsigned long b) | |

{ | |

return (a << 5) | (b & 1); | |

} | |

unsigned long | |

foo2b (unsigned long a, unsigned long b) | |

{ | |

return (b << 5) | (a & 1); | |

} | |

/* risbgn cannot be used when the masked bits would end up in the | |

result since a real OR is required then. */ | |

unsigned long | |

foo1c (unsigned long a, unsigned long b) | |

{ | |

return (a << 5) | (b & 127); | |

} | |

unsigned long | |

foo2c (unsigned long a, unsigned long b) | |

{ | |

return (b << 5) | (a & 127); | |

} | |

unsigned long | |

foo3 (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (a << 5) | (b >> 59); | |

#else | |

return (a << 5) | (b >> 27); | |

#endif | |

} | |

unsigned long | |

foo4 (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (b << 5) | (a >> 59); | |

#else | |

return (b << 5) | (a >> 27); | |

#endif | |

} | |

/* risbgn can be used also if there are some bits spared in the middle | |

of the two chunks. */ | |

unsigned long | |

foo3b (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (a << 6) | (b >> 59); | |

#else | |

return (a << 6) | (b >> 27); | |

#endif | |

} | |

unsigned long | |

foo4b (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (b << 6) | (a >> 59); | |

#else | |

return (b << 6) | (a >> 27); | |

#endif | |

} | |

/* One bit of overlap so better don't use risbgn. */ | |

unsigned long | |

foo3c (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (a << 4) | (b >> 59); | |

#else | |

return (a << 4) | (b >> 27); | |

#endif | |

} | |

unsigned long | |

foo4c (unsigned long a, unsigned long b) | |

{ | |

#ifdef __s390x__ | |

return (b << 4) | (a >> 59); | |

#else | |

return (b << 4) | (a >> 27); | |

#endif | |

} | |

/* The functions foo3, foo4, foo3b, foo4b no longer use risbgn but rosbg instead | |

which is slightly worse. Combine prefers to use the simpler two insn | |

combinations possible with rosbg instead of the more complicated three insn | |

combinations that result in risbgn. This problem has been introduced with | |

the commit | |

S/390: Add patterns for r<nox>sbg instructions. | |

(3rd of May, 2016). This should be fixed some time in the future, but for | |

now just adapt the expected result: | |

{ dg-final { scan-assembler-times "risbgn" 6 { xfail { *-*-* } } } } | |

{ dg-final { scan-assembler-times "risbgn" 2 } } | |

*/ |