1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*
* UnSSA - translate the SSA back to normal form.
*
* For now it's done by replacing to set of copies:
* 1) For each phi-node, replace all their phisrc by copies to a common
* temporary.
* 2) Replace all the phi-nodes by copies of the temporaries to the phi-node target.
* This is node to preserve the semantic of the phi-node (they should all "execute"
* simultaneously on entry in the basic block in which they belong).
*
* This is similar to the "Sreedhar method I" except that the copies to the
* temporaries are not placed at the end of the predecessor basic blocks, but
* at the place where the phi-node operands are defined (the same place where the
* phisrc were present).
* Is this a problem?
*
* While very simple this method create a lot more copies that really necessary.
* Ideally, "Sreedhar method III" should be used:
* "Translating Out of Static Single Assignment Form", V. C. Sreedhar, R. D.-C. Ju,
* D. M. Gillies and V. Santhanam. SAS'99, Vol. 1694 of Lecture Notes in Computer
* Science, Springer-Verlag, pp. 194-210, 1999.
*
* Copyright (C) 2005 Luc Van Oostenryck
*/
#include "lib.h"
#include "linearize.h"
#include "allocate.h"
#include <assert.h>
static void remove_phisrc_defines(struct instruction *phisrc)
{
struct instruction *phi;
struct basic_block *bb = phisrc->bb;
FOR_EACH_PTR(phisrc->phi_users, phi) {
remove_pseudo(&bb->defines, phi->target);
} END_FOR_EACH_PTR(phi);
}
static void replace_phi_node(struct instruction *phi)
{
pseudo_t tmp;
tmp = alloc_pseudo(NULL);
tmp->type = phi->target->type;
tmp->ident = phi->target->ident;
tmp->def = NULL; // defined by all the phisrc
// update the current liveness
remove_pseudo(&phi->bb->needs, phi->target);
add_pseudo(&phi->bb->needs, tmp);
phi->opcode = OP_COPY;
phi->src = tmp;
// FIXME: free phi->phi_list;
}
static void rewrite_phi_bb(struct basic_block *bb)
{
struct instruction *insn;
// Replace all the phi-nodes by copies of a temporary
// (which represent the set of all the %phi that feed them).
// The target pseudo doesn't change.
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
if (insn->opcode != OP_PHI)
continue;
replace_phi_node(insn);
} END_FOR_EACH_PTR(insn);
}
static void rewrite_phisrc_bb(struct basic_block *bb)
{
struct instruction *insn;
// Replace all the phisrc by one or several copies to
// the temporaries associated to each phi-node it defines.
FOR_EACH_PTR_REVERSE(bb->insns, insn) {
struct instruction *phi;
int i;
if (!insn->bb)
continue;
if (insn->opcode != OP_PHISOURCE)
continue;
i = 0;
FOR_EACH_PTR(insn->phi_users, phi) {
pseudo_t tmp = phi->src;
pseudo_t src = insn->phi_src;
if (i == 0) { // first phi: we overwrite the phisrc
insn->opcode = OP_COPY;
insn->target = tmp;
insn->src = src;
} else {
struct instruction *copy = __alloc_instruction(0);
copy->bb = bb;
copy->opcode = OP_COPY;
copy->size = insn->size;
copy->pos = insn->pos;
copy->target = tmp;
copy->src = src;
INSERT_CURRENT(copy, insn);
}
// update the liveness info
remove_phisrc_defines(insn);
// FIXME: should really something like add_pseudo_exclusive()
add_pseudo(&bb->defines, tmp);
i++;
} END_FOR_EACH_PTR(phi);
} END_FOR_EACH_PTR_REVERSE(insn);
}
int unssa(struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
rewrite_phi_bb(bb);
} END_FOR_EACH_PTR(bb);
FOR_EACH_PTR(ep->bbs, bb) {
rewrite_phisrc_bb(bb);
} END_FOR_EACH_PTR(bb);
return 0;
}
|