mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
Take the code generator a big step closer to notes/ALLOCATION.
Estimated hours taken: _____ Take the code generator a big step closer to notes/ALLOCATION. The new code generator emits code that is smaller and faster than the code we used to emit. Nondet liveness is no longer used; nondet live sets are always empty. In code that was being modified anyway, remove its handling. Other uses will be removed later (this keeps this change from being far too big; as it is it is merely too big). Similarly for cont-lives. In several places, clarify the code that gathers several code pieces together. call_gen: Unset the failure continuation and flush the resume vars to their stack slots before nondet calls. Move the code that decides whether a nondet call can be a tailcall to code_info. code_aux: Remove the code to handle resume points, since these are now handled in the specific constructs that need them. Replace it with a sanity check. code_exprn: Add a predicate to place multiple vars. code_gen: Remove the predicate code_gen__generate_forced_goal, since it packaged together some operations that should be executed at different times. Don't unset the failure continuation after every nondet goal; this is now done in the constructs that need it. Modify the handling of negation to use resume point info according to notes/ALLOCATION. Remove the predicate code_gen__ensure_vars_are_saved which was use to save all lives variables to the stack before nondet disjunctions and if-then-elses; we don't do that anymore. code_info: Significantly simplify and document the handling of failure continuations, and make the types involved abstract types. Factor out common code in the handling of det and semi commits. Keep track of "zombies", variables that are dead wrt forward execution but whose values we need because they may be needed at a resume point we can reach. Remove several now unneeded predicates, and introduce new predicates to help other modules. code_util: Add a couple of predicates to check whether ia goal cannot fail before flushing all variables to the stack, and whether a goal cannot flush any variables to the stack. These are used in liveness to decide which entry labels will be needed at resume points. disj_gen: Unify the handling of det and semi disjunctions. Model the code handling of nondet disjunctions on the code handling pruned disjunctions. It is possible that the handling of nondet and pruned disjunctions can also be unified; the new code should make this significantly easier. Make the code conform to notes/ALLOCATION. This means saving only the variables mentioned in the resume_point field, not flushing all live variables to the stack at the start of a nondet disjunction, handling zombies, and using the new method of flushing variables at the ends of branched structures. ite_gen: Unify the handling of det and semi if-then-elses. Model the code handling of nondet if-then-elses on the code handling det/semi if-then-elses. It is possible that the handling of nondet and pruned if-then-elses can also be unified; the new code should make this significantly easier. Make the code conform to notes/ALLOCATION. This means saving only the variables mentioned in the resume_point field, not flushing all live variables to the stack at the start of a nondet if-then-else, handling zombies, and using the new method of flushing variables at the ends of branched structures. Apply the new rules about liveness in if-then-elses, which say that the else part is parallel not to the then part but to the conjunction of the condition and the then part. dense_switch, lookup_switch, string_switch, switch_gen, tag_switch, middle_rec: Use the new method of flushing variables at the ends of branched structures. Don't call remake_with_store map; switch_gen will do so. Fix an old bug in lookup_switch. The code in switch_gen which looked for the special case of a two-way switch used to use a heuristic to decide which one was recursive and which one was a base case. We now check the codes of the cases. hlds_goal: Adjust the structure of the resume_point field to make it easier to use. Add a more convenient access predicate. hlds_out: Don't print the nondet liveness and cont live fields, since they are not used anymore. Comment out the printing of the context field, which is rarely useful. Modify the printing of the resume_point field to conform to its new definition. live_vars: Use the resume_point field, not the nondetlives field, to decide which variables may be needed on backward execution. Remove some code copied from liveness.m. liveness: Put the several pieces of information we thread through the traversal predicates into a single tuple. Don't put variables which are local to one branch of a branched structure into the post-birth sets of other branches. Apply the new rules about liveness in if-then-elses, which say that the else part is parallel not to the then part but to the conjunction of the condition and the then part. Variables that are needed in the else part but not in the condition or the then part now die in at the start of the condition (they will be protected by the resume point on the condition). We now treat pruned and non-pruned disjunctions the same way wrt deadness; the old way was too conservative (it had to be). We still mishandle branches which produce some variables but can't succeed. mercury_compile: Liveness now prints its own progress message with -V; support this. store_alloc: When figuring out what variables need to be saved across calls, make sure that we put in interference arcs between those variables and those that are required by enclosing resume points. Don't compute cont-lives, since they are not used anymore. livemap: Fix the starting comment.
This commit is contained in:
@@ -208,8 +208,10 @@ tag_switch__generate_primary_tag_code(GoalMap, Primary, MaxSecondary, StagLoc,
|
||||
{ StagLoc = none }
|
||||
->
|
||||
( { GoalList = [-1 - Goal] } ->
|
||||
code_gen__generate_forced_goal(CodeModel, Goal,
|
||||
StoreMap, Code)
|
||||
code_gen__generate_goal(CodeModel, Goal, GoalCode),
|
||||
code_info__generate_branch_end(CodeModel, StoreMap,
|
||||
SaveCode),
|
||||
{ Code = tree(GoalCode, SaveCode) }
|
||||
;
|
||||
{ error("more than one goal for non-shared tag") }
|
||||
)
|
||||
@@ -272,8 +274,10 @@ tag_switch__generate_primary_tag_code(GoalMap, Primary, MaxSecondary, StagLoc,
|
||||
tag_switch__generate_secondary_tag_chain([], _SecTagRval, _CodeModel, CanFail,
|
||||
_StoreMap, _EndLabel, FailLabel, Code) -->
|
||||
( { CanFail = can_fail } ->
|
||||
{ Code = node([goto(label(FailLabel))
|
||||
- "secondary tag does not match"]) }
|
||||
{ Code = node([
|
||||
goto(label(FailLabel)) -
|
||||
"secondary tag does not match"
|
||||
]) }
|
||||
;
|
||||
{ Code = empty }
|
||||
).
|
||||
@@ -286,20 +290,28 @@ tag_switch__generate_secondary_tag_chain([Case0 | Cases0], SecTagRval,
|
||||
{ TestCode = node([if_val(binop(ne, SecTagRval,
|
||||
const(int_const(Secondary))),
|
||||
label(ElseLabel)) - "test remote sec tag only"]) },
|
||||
code_gen__generate_forced_goal(CodeModel, Goal, StoreMap,
|
||||
GoalCode),
|
||||
code_gen__generate_goal(CodeModel, Goal, GoalCode),
|
||||
code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
|
||||
{ ElseCode = node([
|
||||
goto(label(EndLabel)) - "skip to end of tag switch",
|
||||
label(ElseLabel) - "handle next secondary tag"]) },
|
||||
{ ThisCode = tree(TestCode, tree(GoalCode, ElseCode)) },
|
||||
goto(label(EndLabel)) -
|
||||
"skip to end of tag switch",
|
||||
label(ElseLabel) -
|
||||
"handle next secondary tag"
|
||||
]) },
|
||||
{ ThisCode =
|
||||
tree(TestCode,
|
||||
tree(GoalCode,
|
||||
tree(SaveCode,
|
||||
ElseCode))) },
|
||||
( { Cases0 = [_|_] } ->
|
||||
code_info__slap_code_info(CodeInfo)
|
||||
;
|
||||
[]
|
||||
)
|
||||
;
|
||||
code_gen__generate_forced_goal(CodeModel, Goal, StoreMap,
|
||||
ThisCode)
|
||||
code_gen__generate_goal(CodeModel, Goal, GoalCode),
|
||||
code_info__generate_branch_end(CodeModel, StoreMap, SaveCode),
|
||||
{ ThisCode = tree(GoalCode, SaveCode) }
|
||||
),
|
||||
tag_switch__generate_secondary_tag_chain(Cases0, SecTagRval,
|
||||
CodeModel, CanFail, StoreMap, EndLabel, FailLabel, OtherCode),
|
||||
@@ -330,26 +342,39 @@ tag_switch__generate_secondary_tag_table(CaseList, CurSecondary, MaxSecondary,
|
||||
{ NextSecondary is CurSecondary + 1 },
|
||||
( { CaseList = [CurSecondary - Goal | CaseList1] } ->
|
||||
code_info__get_next_label(NewLabel),
|
||||
{ LabelCode = node([
|
||||
label(NewLabel) -
|
||||
"start of a case in tag switch"
|
||||
]) },
|
||||
( { CaseList1 = [] } ->
|
||||
code_gen__generate_forced_goal(CodeModel, Goal,
|
||||
StoreMap, GoalCode)
|
||||
code_gen__generate_goal(CodeModel, Goal,
|
||||
GoalCode),
|
||||
code_info__generate_branch_end(CodeModel,
|
||||
StoreMap, SaveCode)
|
||||
;
|
||||
code_info__grab_code_info(CodeInfo),
|
||||
code_gen__generate_forced_goal(CodeModel, Goal,
|
||||
StoreMap, GoalCode),
|
||||
code_gen__generate_goal(CodeModel, Goal,
|
||||
GoalCode),
|
||||
code_info__generate_branch_end(CodeModel,
|
||||
StoreMap, SaveCode),
|
||||
code_info__slap_code_info(CodeInfo)
|
||||
),
|
||||
{ LabelCode = node([label(NewLabel) -
|
||||
"start of a case in tag switch"]) },
|
||||
{ GotoCode = node([goto(label(EndLabel)) -
|
||||
"branch to end of tag switch"]) },
|
||||
{ GotoCode = node([
|
||||
goto(label(EndLabel)) -
|
||||
"branch to end of tag switch"
|
||||
]) },
|
||||
tag_switch__generate_secondary_tag_table(CaseList1,
|
||||
NextSecondary, MaxSecondary, CodeModel,
|
||||
StoreMap, EndLabel, FailLabel, OtherLabels,
|
||||
OtherCode),
|
||||
{ Labels = [NewLabel | OtherLabels] },
|
||||
{ Code = tree(tree(LabelCode, GoalCode),
|
||||
tree(GotoCode, OtherCode)) }
|
||||
{ Code =
|
||||
tree(LabelCode,
|
||||
tree(GoalCode,
|
||||
tree(SaveCode,
|
||||
tree(GotoCode,
|
||||
OtherCode))))
|
||||
}
|
||||
;
|
||||
tag_switch__generate_secondary_tag_table(CaseList,
|
||||
NextSecondary, MaxSecondary, CodeModel,
|
||||
|
||||
Reference in New Issue
Block a user