-
Notifications
You must be signed in to change notification settings - Fork 64
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
[gen] implementation of Ifetch annotation #703
Conversation
Thanks @hugookeeffe. I haven't looked at the code yet, but looking a bit at the examples in this PR, I think that the post-condition of the 2 test is a little confusing.
Can't we simply write:
Otherwise, I think it would be better to have a uniform view of the old value in |
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.
Some comments on the code.
gen/cycle.ml
Outdated
end ; | ||
(* ensure Instr read is followed or preceded by plain read to same location*) | ||
if E.is_ifetch m.edge.E.a1 && m.evt.dir = Some R && not | ||
(is_read_same_nonfetch m.next m || |
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.
Isn't this check redundant? I think find_node_prev (in the next line) will get to m.next, won't it?
5c68020
to
5ad16ed
Compare
@relokin in reference to your comment:
the issue with using We could implement support for this, but I think that this would need quite a bit more code. As there are not many cases like this, my preference would be to check for the value that is currently there (so in this case B .+12) and change the code of the test to have this as well. What do you think? |
37da7f4
to
8646407
Compare
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! Adding two supernitpick-y comments, I don't consider them blocking.
gen/AArch64Arch_gen.ml
Outdated
@@ -795,6 +802,7 @@ include | |||
| _ -> false | |||
|
|||
let pp_reg = pp_reg | |||
let pp_i n = pp_i n |
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.
let pp_i n = pp_i n | |
let pp_i = pp_i |
As a matter of nitpicking, could it be defined like this?
gen/BellArch_gen.ml
Outdated
@@ -271,6 +271,7 @@ include | |||
let is_symbolic _ = false | |||
|
|||
let pp_reg = pp_reg | |||
let pp_i _ = "instr:\"NOP\"" |
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.
let pp_i _ = "instr:\"NOP\"" | |
let pp_i _ = assert false |
Does this function need to have an implementation for non-AArch64? My hunch is that it should never be called unless this is an error.
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.
I agree with Artem, pp_i
should be implemented as `let pp_i _ = assert false" for all *Arch_gen.ml other than AArch64Arch_gen.ml.
gen/BellArch_gen.ml
Outdated
@@ -271,6 +271,7 @@ include | |||
let is_symbolic _ = false | |||
|
|||
let pp_reg = pp_reg | |||
let pp_i _ = "instr:\"NOP\"" |
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.
I agree with Artem, pp_i
should be implemented as `let pp_i _ = assert false" for all *Arch_gen.ml other than AArch64Arch_gen.ml.
Warn.user_error "Ambiguous Data/Code location es [%s] => [%s]" | ||
(str_node p) (str_node m) | ||
end ; | ||
(* ensure Instr read is followed or preceded by plain read to same location*) |
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.
Can I check with you that I understand the need for this? Here you're checking that if there is a LDR from a location P0:Lself0 then there will be a label P0:Lself0, or in other words an instruction (fetch) at P0:Lself?
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, exactly. The plain read to a code location is what creates the label in the body of the code, so if we don't have this then a Instr read will read from a non-existent label
gen/cycle.ml
Outdated
if E.is_ifetch m.edge.E.a1 && m.evt.dir = Some R && not | ||
(try | ||
ignore (find_node_prev (fun n -> is_read_same_nonfetch n m) m); | ||
true | ||
with Not_found -> false) | ||
then | ||
Warn.user_error "Instruction read followed by ifetch to different location [%s] => [%s]" | ||
(str_node p) (str_node m); |
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.
A suggestion that I think will help simplify this:
if E.is_ifetch m.edge.E.a1 && m.evt.dir = Some R && not | |
(try | |
ignore (find_node_prev (fun n -> is_read_same_nonfetch n m) m); | |
true | |
with Not_found -> false) | |
then | |
Warn.user_error "Instruction read followed by ifetch to different location [%s] => [%s]" | |
(str_node p) (str_node m); | |
if E.is_ifetch m.edge.E.a1 && m.evt.dir = Some R then begin | |
try | |
ignore (find_node_prev (fun n -> is_read_same_nonfetch) m) | |
with Not_found -> | |
Warn.user_error "Reading from label that doesn't exist [%s]" (str_node m) | |
end |
(Please check the indentation of the above)
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, that makes it a lot better. As i needed to use this sequence multiple times in order to fix a bug, I have moved it into the is_read_same_nonfetch function.
Thank you!
gen/cycle.ml
Outdated
match m.edge.E.edge, p.edge.E.edge, m.evt.loc with | ||
| E.Irf _,_,_ | _, E.Ifr _,_-> () | ||
| _,_,Code.Code _ -> if m.evt.dir = Some W && not (E.is_ifetch m.edge.E.a1) then | ||
Warn.user_error "Plain annotation on write to code location not possible"; | ||
| _ -> (); |
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.
Wouldn't something like this work?
match m.edge.E.edge, p.edge.E.edge, m.evt.loc with | |
| E.Irf _,_,_ | _, E.Ifr _,_-> () | |
| _,_,Code.Code _ -> if m.evt.dir = Some W && not (E.is_ifetch m.edge.E.a1) then | |
Warn.user_error "Plain annotation on write to code location not possible"; | |
| _ -> (); | |
match m.evt.loc, m.evt.dir with | |
| Code.Code _,Some W when not (E.is_ifetch m.edge.E.a1) -> | |
Warn.user_error "Plain annotation on write to code location not possible"; | |
| _ -> | |
() ; |
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.
ah, thank you for the suggestion. I have implemented this.
I will make the changes to get Irf, Ifr changed in my next patch
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.
@relokin I have made the changes to make Irf/Ifr to be translated to Rf/Fr in the patch I have just pushed
gen/top_gen.ml
Outdated
match n.C.prev.C.edge.E.edge, n.C.edge.E.edge, E.is_ifetch n.C.prev.C.edge.E.a2, E.is_ifetch n.C.edge.E.a1 with | ||
|E.Rf _,_,true,_| _,E.Fr _,_,true -> F.add_final (A.get_friends st) p o n finals | ||
|_,E.Po _,_,true -> F.add_final (A.get_friends st) p o n finals | ||
| _,_,_,_-> begin |
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.
don't you need to enclose this in begin ... end?
match n.C.prev.C.edge.E.edge, n.C.edge.E.edge, E.is_ifetch n.C.prev.C.edge.E.a2, E.is_ifetch n.C.edge.E.a1 with | |
|E.Rf _,_,true,_| _,E.Fr _,_,true -> F.add_final (A.get_friends st) p o n finals | |
|_,E.Po _,_,true -> F.add_final (A.get_friends st) p o n finals | |
| _,_,_,_-> begin | |
match n.C.prev.C.edge.E.edge, n.C.edge.E.edge with | |
| E.Rf _, _ when E.is_ifetch n.C.prev.C.edge.E.a2 -> | |
F.add_final (A.get_friends st) p o n finals | |
| _, E.Po _ | _, E.Fr _ when E.is_ifetch n.C.prev.C.edge.E.a1 -> | |
F.add_final (A.get_friends st) p o n finals | |
| _, _-> begin |
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.
I don't think we need to enclose it in begin ... end, it seems to be working as it is. Do you think it would be more legible with it implemented?
Thank you for the suggested change! I have implemented it.
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.
I cannot add a comment to line 66, but ideally I think we should remove Irf
and Ifr
from the definition of type tedge
after all with the new annotations can't we just use Rf
and Fr
?
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.
We could do that, but I thought we wanted to keep the ability to parse it in case it was in use by others at the moment?
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 we do, a user should be able to specify the relaxation Irf
or using this PR RfIP
. But these two are equivalent, aren't they? Shouldn't we have just one implementation? Internally we don't need to have a special case for Irf
in type tedge
because this is just a case of Rf
. Does this make sense?
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 makes sense, however, the issue with this is that annotations are architecture-specific in the code, whereas the edge type is not. To have Irf be read by the tool as RfIP, we would have to implement the I
annotation for all other architectures. We could do this but I'm not sure it would simplify the code much by doing so.
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.
I am afraid I don't understand what you mean. Irf
/Ifr
is only implemented for AArch64
isn't it? When I do:
$> diyone7 -arch X86_64 -variant self PodWW Rfe PodRR Ifre
I get:
diyone7: Fatal error: Test A [PodWW Rfe PodRR Ifre] failed:
No code location for X86_64
Is there any other architecture, Ifre
is implemented for?
Why would you have to implement the new annotations for all other architectures? When I do:
$> diyone7 -arch X86_64 -variant self PodWW Rfe PodRR FrePI
I get:
diyone7: Fatal error: Bad relax: FrePI
Which for the end user this means the same thing as the previous error message. The feature is not implemented for X86_64
. And I am not suggesting that you change this. All I am saying is that the user can either do:
$> diyone7 -arch AArch64 -variant self PodWW Rfe PodRR Ifre
or
$> diyone7 -arch AArch64 -variant self PodWW Rfe PodRR FrePI
and get the same test. Why have should we have different implementations? I would expect that the only support we need for Ifre
, is in the parser. We would parse FrePI
and Ifre
using the same internal representation. Then we use the same code to generate the test which you've implemented already and completely get rid of the code that implements Ifre
.
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.
Whilst Ifr/Irf is only implemented for AArch64, it is implemented generally at the level of the parser (with the code location fail only happening later). When we are parsing for the type tedge, we go through the function do_pp_edge
, which is a general function.
Currently, the way that my patch treats “Irf” and “Ifr” strings is that they get parsed as Irf/Ifr of type tedge and are then converted to the desired Rf/Fr representation when building the cycle (this can be seen in the function convert_ins in cycle.ml). This means that the same internal logic is used when the tests are being built and the same tests should be generated regardless of which syntax is used.
If we wanted the string Irf and Ifr to be converted to Rf and Fr at the point of parsing, we would need to implement architecture specific functions to return the appropriate annotations in the function do_pp_edge. However, for this we would need to implement such a function into all architectures.
Keeping Irf/ifr in tedge seems like the simpler solution here, as it reduces the amount of extra functions needed to be written into other architectures. And as Irf/Ifr are converted to Rf/Fr early on, the logic to generate the test should be the same.
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.
I agree, it's not straightforward but it's better than having two separate implementations for "Ifr" and "Irf". I took a stub at it and the patch is here: relokin@184e12c . If you're happy with it, please cherry pick it in your PR.
Otherwise, I am happy with the PR, please rebase and squash your commits into 1 and I will then merge.
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.
If all worked well, I have now rebased and squashed my commits into 1, with your commit cherry-picked. Thank you very much for the help and let me know if I did anything wrong or you would like me to do something else
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.
@hugookeeffe, I think something went wrong, the PR is not rebased on top of the latest master and it doesn't compile:
sh ./version-gen.sh ~/.local
dune build -j 8 --profile release
File "gen/cycle.ml", line 952, characters 33-43:
952 | let to_com_rmw n0 = not (is_com_rmw n0.prev) && is_com_rmw n0 in
^^^^^^^^^^
Error: Unbound value is_com_rmw
make: *** [build] Error 1
Can you have a look please?
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's strange. I've tried rebasing again, and it works for me now. I think I must have not pushed the rebase properly. Does it work for you now?
5bf551f
to
b0e6227
Compare
@@ -38,8 +38,8 @@ let num = digit+ | |||
|
|||
rule coms = parse | |||
| space+ { coms lexbuf } | |||
| "Fr"|"Iff"|"Irf" { Fr :: coms lexbuf } |
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.
I'm a little worried about this, can you check if it is a problem? That is generate a test with Irf and use litmus7 to run it. I think it's not problem because diyone7 will not print Irf but Rf instead but just to make sure.
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.
I have just done that with the following test,
diyone7 -arch AArch64 -variant self "PodWW Irfe PodRR Ifre" -moreedges true
AArch64 A
"PodWWII RfeIP PodRR FrePI"
Generator=diyone7 (version 7.56+03)
Com=Rf Fr
Orig=PodWWII RfeIP PodRR FrePI
{
0:X0=instr:"NOP"; 0:X1=P1:Lself00; 0:X2=P1:Lself01;
}
P0 | P1 ;
STR W0,[X1] | Lself01: ;
STR W0,[X2] | B .+12 ;
| MOV W0,#2 ;
| B .+8 ;
| MOV W0,#1 ;
| Lself00: ;
| B .+12 ;
| MOV W1,#2 ;
| B .+8 ;
| MOV W1,#1 ;
exists (1:X0=2 /\ 1:X1=1)
and it has run with no issue with litmus7. As you suggested, diyone7 doesn't print Irf anyway so it doesn't create a problem
b0e6227
to
8f74c9e
Compare
I will be doing a final check and planning to merge this tomorrow. Please let me know if you need more time to review this or have any objections. |
8f74c9e
to
7458fc7
Compare
Looks good to me. Thanks @hugookeeffe I am going to merge this now. |
This PR implements a new syntax for generating Ifetch tests, using a new annotation. The I annotation is used to represent explicit memory events to instruction locations (i.e. LDR and STR of an instruction stored at a location identified by a label). This PR also introduces the possibility of generating explicit reads of an instruction. With this new implementation, Ifetch sequences are generated by using the plain annotation with a read to a Code location.
example tests: