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
Writing to one structure element clobbers another #803
Comments
Original Redmine Comment I'm on a 64 bit machine, but it looks like IData is a 32 bit value, so that shouldn't matter. |
Original Redmine Comment This might be #�, please try the version in git. |
Original Redmine Comment
The result is:
It I make the shift amount non-const, it prints 8. Using the -S flag to compile both forms to assembly, I can see that my compiler skips emitting the shift instruction and just leaves an uninitialized result when it knows the shift amount is too big. So, I still think it is necessary to mask the shift amount within a word. This:
Should be:
|
Original Redmine Comment The following change fixes the problem for me. However, this area of the code is fairly complex and I don't fully understand it, so I suspect this may not handle every case correctly.
|
Original Redmine Comment V3Premit should be taking care of the overshifting, the V3Expand fix might be incomplete and in other cases redundant speed wise. Can you provide a verilog complete verilog example that breaks? BTW as to your C example that's how x86 does shifts, the upper bits are ignored, unlike PowerPC for example. Thanks |
Original Redmine Comment Sorry, I don't think I've described the issue very well. :) Unfortunately, all my attempts to reduce my program to a simple test case usually mask the issue, because of the way the compiler (LLVM) generates code. This is definitely compiler specific. I didn't quite understand your last comment, but, at the risk of repeating something that may already be clear to you, I'll try to give a more detail. As described earlier, I augmented the generated code that handles the delayed assignment to add a printf as follows. It is shifting a single bit the amount described by __Vdlyvlsb__v__DOT__core0__DOT__l2_cache_interface__DOT__store_buffer__DOT__pending_stores__v69 (which is 611).
When I run this program, it prints:
Right away, it's clear that something is wrong because shifting a single bit shoudn't ever produce 0x5f1d1f28. If I compile this to assembly, I see the following:
A few things to note here:
Now I modify the right side of the shift statement to bitwise AND with 31 so it looks like this:
...And I get the following code. Note that esi is now properly initialized to 8:
The LLVM blog does explicitly state (in the section 'oversize shift amounts') that they treat this as undefined, which hints that they have coded it this way explicitly (which is what I was also demonstrating in my previous C program): http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html |
Original Redmine Comment It's not clear to me how this could be fixed in V3Premit. The V3Premit pass occurs before V3Expand, and the latter appears to be where the AstSel node is converted to shifts/array/logical operations. If the value were masked in V3Premit, the array index would be wrong. |
Original Redmine Comment Okay, I managed to create a minimal program that reproduces the issue:
Output:
|
Original Redmine Comment Attached proper regression test cases (for the test_regress/t) that reproduce the issue. |
Original Redmine Comment Attached a patch for this issue with regression test cases. After studying the code for a while, I believe this is the right way to fix the problem. You had some objections about this previously, so I will attempt to clarify why I think this is correct. Before the expansion, the problematic area is a legal node ASSIGNSEL(varlsb,wide,1bit), with a non-constant shift amount. As the ASSIGNSEL is legal, it is not possible to address the issue before the expand pass. The expand function converts it into a combination of WORDSEL/OR/LEFTSHIFT. At that point, we know the shift amount (lsb) can be more than 32. We also know that using the left shift operator with a number greater than 32 is undefined, so we should mask it. Note that the patch only changes the case where:
After the expandpass, the context is lost and it just looks like a leftshift node, so the issue cannot be remedied after that. |
Original Redmine Comment One other note: when I run the regression tests on master@fe5bf01b, there are six failures on my machine. I re-ran all tests with this patch and confirmed it didn't add any new ones. |
Original Redmine Comment I'm convinced. Thanks much for the research and patch. BTW I'd be curious what the other regression failures are since they all pass for me, if you would be willing to file another bug and debug them that would help the next person, thanks. Fixed in git towards 3.863. |
Original Redmine Comment I'm on a mac and they appear to be platform issues (a few can't find gdb, one not handling LD flags correctly). |
Original Redmine Comment In 3.864. |
Author Name: Jeff Bush (@jbush001)
Original Redmine Issue: 803 from https://www.veripool.org
Original Date: 2014-07-13
Original Assignee: Jeff Bush (@jbush001)
I found an issue where I do a nonblocking assignment to one structure member, followed by another (the former is multiple bits and the latter is only one bit), and the first member I assigned is clobbered. This seems to be due to a value larger than 32 being passed into the left shift operator (The _Vdlyvllsb variable is larger than 32 and is not masked). If I manually edit the generated code to mask this value (bitwise and with 31), the code works correctly.
The issue appears to occur where the nonblocking store is applied. Here is the generated code:
Note that __Vdlyvlsb__v__DOT__core0__DOT__l2_cache_interface__DOT__store_buffer__DOT__pending_stores__v69 in this case is 611. At the very end of the last expression, it is the shift amount to create the one bit value. Technically, I think the C spec says the result is undefined, but I'd expect it to mask off the value. I printed the value of that array element before and after this assignment and multiple bits have been set.
Just for yucks, I added a printf at the top of this clause:
It prints this out:
Which seems totally bizarre to me. So, it appears the processor or compiler is doing something very odd with this. I'm using MacOS 10.9.3 with Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn).
At any rate, it would probably be more proper to mask the shift value when generating structure assignments.
The text was updated successfully, but these errors were encountered: