In a Fedora build, it has been seen that Valgrind crashes with illegal instruction when trying to execute the WFLRX instruction: vex s390->IR: specification exception: E700 0008 40C5 ==4036598== valgrind: Unrecognised instruction at address ... See the original bug report: https://bugzilla.redhat.com/show_bug.cgi?id=2035807 WFLRX is a variant of VFLR (vector FP load rounded); it rounds the source vector's first element down from extended format to long format. This variant was introduced with z14.
Created attachment 145141 [details] Fix VFLRX instruction The problem was due to a typo in s390_irgen_VFLR. This fixes the typo.
I've tested this patch with the following source: ----- int main(){ asm("wflrx %v0,%v0,0,0"); return 0 ; } ----- Built with "gcc -march=z14 main.c -o main" and tested with a valgrind build that contains this patch. Now valgrind works correctly and doesn't report "IR: specification exception" anymore. I wanted to do a bit more in-depth testing and I moved to another instruction, so I changed my program to this one: ----- int main(){ asm("vflr %v0,%v0,0,0,0"); return 0 ; } ----- Building and running the same way as the aforementioned, this executable will make that valgrind prints again a specification exception message such as this: vex s390->IR: specification exception: E700 0000 00C5 ==52001== valgrind: Unrecognised instruction at address 0x1000558. Checking s390x opcodes, it feels like s390_irgen_VFLR is missing the case for when m3 == 0 (provided my inline asm is right). I did the same test with VFLL (e700 xxxx xxc4) opcodes with the same result, VFLL instruction makes valgrind report a specification exception, whereas VFLLS/WFLLS/WFLLD instructions work correctly. FTR, this is the link where I checked the opcodes: https://fossies.org/linux/binutils/opcodes/s390-opc.txt
(In reply to Jesus Checa from comment #2) > ... > Checking s390x opcodes, it feels like s390_irgen_VFLR is missing the case > for when m3 == 0 (provided my inline asm is right). Right, m3 == 0 is not a valid format code. The z/Architecture Principle of Operation states: The M3 field specifies the floating-point format. The floating-point format determines the size of the elements within the second operand. If a reserved value is specified, a specification exception is recognized. And then declares the values 3 and 4 as representing the long and extended formats, respectively, and all other values as reserved. So I'd say that Valgrind is correct in raising a SIGILL for m3 == 0.
(In reply to Andreas Arnez from comment #3) > (In reply to Jesus Checa from comment #2) > > ... > > Checking s390x opcodes, it feels like s390_irgen_VFLR is missing the case > > for when m3 == 0 (provided my inline asm is right). > Right, m3 == 0 is not a valid format code. The z/Architecture Principle of > Operation states: > > The M3 field specifies the floating-point format. The floating-point > format determines the size of the elements within the second operand. > If a reserved value is specified, a specification exception is > recognized. > > And then declares the values 3 and 4 as representing the long and extended > formats, respectively, and all other values as reserved. > > So I'd say that Valgrind is correct in raising a SIGILL for m3 == 0. OK, but does that mean that "vflr" isn't a real opcode because it doesn't define on what format it operates? Only "vflrd", "wflrd", which operate on longs, and "wflrx", which operate on extended long, are valid opcodes? If so, then it is slightly surprising gcc/binutils accepts asm("vflr %v0,%v0,0,0,0");
(In reply to Mark Wielaard from comment #4) > OK, but does that mean that "vflr" isn't a real opcode because it doesn't > define on what format it operates? Basically yes. Well, strictly speaking, the opcode only consists of the encoded instruction's (E700000000C5) first and last bytes in this case. So while this byte sequence correctly specifies the vflr instruction, it violates the instruction's specification -- hence the specification exception. On Linux this raises SIGILL, same as if the opcode itself was unrecognized. > Only "vflrd", "wflrd", which operate on longs, and "wflrx", which operate on > extended long, are valid opcodes? > > If so, then it is slightly surprising gcc/binutils accepts asm("vflr > %v0,%v0,0,0,0"); Yeah, it's arguable that it shouldn't. The advantage is that future extensions can be used even without explicit binutils support. Sometimes this comes in handy, and the risk of misuse is fairly low. For instance, if a future extension supported rounding down from long to short format, you could already express this by specifying m3 = 2.
(In reply to Andreas Arnez from comment #3) > Right, m3 == 0 is not a valid format code. The z/Architecture Principle of > Operation states: > > The M3 field specifies the floating-point format. The floating-point > format determines the size of the elements within the second operand. > If a reserved value is specified, a specification exception is > recognized. > > And then declares the values 3 and 4 as representing the long and extended > formats, respectively, and all other values as reserved. > > So I'd say that Valgrind is correct in raising a SIGILL for m3 == 0. Oh, I understand now. Thanks for the clarification!
Since this is a fairly trivial fix and there haven't been any more comments, I've pushed this as 8229569cb8b1d564a -- s390: Fix VFLRX and WFLRX instructions