-
Notifications
You must be signed in to change notification settings - Fork 317
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
[MooreToCore] Properly deal with OOB access in dyn_extract #8201
base: main
Are you sure you want to change the base?
Conversation
The array slice case is not fixed yet. I couldn't really find a part in the SV standard about signed/unsigned indexing. I assume always interpreting the index operand as unsigned is fine.
rewriter.replaceOpWithNewOp<hw::ArraySliceOp>(op, resultType, | ||
adaptor.getInput(), idx); | ||
return success(); | ||
} | ||
|
||
rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(op, adaptor.getInput(), idx); | ||
Value size = rewriter.create<hw::ConstantOp>( | ||
op.getLoc(), adaptor.getLowBit().getType(), arrType.getNumElements()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That can cause problems if the lowBit bitwidth is too small to hold the array size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. In that case we might be guaranteed to always access in bounds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes 👍
But I need to make sure this IR is not built in that case because the pass would crash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
rewriter.replaceOpWithNewOp<hw::ArraySliceOp>(op, resultType, | ||
adaptor.getInput(), idx); | ||
return success(); | ||
} | ||
|
||
rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(op, adaptor.getInput(), idx); | ||
Value size = rewriter.create<hw::ConstantOp>( | ||
op.getLoc(), adaptor.getLowBit().getType(), arrType.getNumElements()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. In that case we might be guaranteed to always access in bounds?
Value access = | ||
rewriter.create<hw::ArrayGetOp>(op.getLoc(), adaptor.getInput(), idx); | ||
int64_t bw = hw::getBitWidth(arrType.getElementType()); | ||
if (bw < 0) | ||
return failure(); | ||
|
||
Value zeroValueRaw = | ||
rewriter.create<hw::ConstantOp>(op.getLoc(), APInt(bw, 0)); | ||
Value zeroValue = rewriter.createOrFold<hw::BitcastOp>( | ||
op.getLoc(), arrType.getElementType(), zeroValueRaw); | ||
rewriter.replaceOpWithNewOp<comb::MuxOp>(op, isOOB, zeroValue, access); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks reasonable assuming that hw::ArrayGetOp
has undefined behaviour (or undefined result) for out-of-bounds accesses. I don't remember off the top of my head whether out-of-bounds index in ArrayGetOp
causes a potential segfault in the lowered LLVM IR… But it might be nice if hw::ArrayGetOp
just produce an undefined result, but don't cause arbitrary undefined behaviour such as crashing the simulator. Then we can just do exactly what you did here: read the value and then discard it with a mux if it's out of bounds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation of the HW aggregate ops is generally a bit sparse, but I'd say a OOB hw.array_get
produces an undefined result, but no immediate UB. The HWToLLVM lowering currently does not take this into account. I'll create an issue for that.
I have a question about the unsigned index, for example:
Maybe |
@hailongSun2000 I think in your example ImportVerilog would lower this to an access index 0, because -1 is the "address" of the least significant bit. During conversion, the accessed index gets remapped from the range |
That sounds great! All bit rang are converted into little endian, and LSB is always 0. Could you tell me where the implementation is? I'm interested to it. Thanks in advance! 😃 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🥳
I think @maerhart added this
|
As a little side-note: the example above would be lowered to an Even though all ranges are converted to little endian starting at 0, the index could still be a negative signed value in SV. bit [31:0] arr;
bit [31:0] idx = -1;
arr[$signed(idx)]; What index does this actually access? -1 or 4,294,967,295? I couldn't really find an answer to this question in the standard, so let me know if you know more 😄 bit [4294967295:0] arr; // let's say all bits are 1
bit [31:0] idx = -1;
arr[$signed(idx)]; Should this now return 0 or 1? Does SV even support such big arrays (if it doesn't the same still applies but with smaller integers)? |
Since SV allows you to have negative indices on array declarations, like Since this only involves addition/subtraction which are identical in signed/unsigned arithmetic, I think we can just ignore the issue altogether: if you subtract the lower index of the declaration (-8) from the accessed index (-2), you'll automatically remap all valid negative indices to positive bit positions. Anything below the lowest bit address would overflow and be out of bounds immediately. If I recall correctly, array index expressions have a self-determined type, not a type inferred from context. That would suggest in your example that the index |
The array slice case is not fixed yet. I couldn't really find a part in the SV standard about signed/unsigned indexing. I assume always interpreting the index operand as unsigned is fine.