1 /**
2  * Code generation 5
3  *
4  * Handles finding out which blocks need a function prolog / epilog attached
5  *
6  * Compiler implementation of the
7  * $(LINK2 https://www.dlang.org, D programming language).
8  *
9  * Copyright:   Copyright (C) 1995-1998 by Symantec
10  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
11  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
12  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
13  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cod5.d, backend/cod5.d)
14  */
15 module dmd.backend.cod5;
16 
17 import core.stdc.stdio;
18 import core.stdc.string;
19 import core.stdc.time;
20 import dmd.backend.cc;
21 import dmd.backend.el;
22 import dmd.backend.oper;
23 import dmd.backend.code;
24 import dmd.backend.global;
25 import dmd.backend.type;
26 
27 import dmd.backend.cdef;
28 import dmd.backend.dlist;
29 import dmd.backend.ty;
30 
31 nothrow:
32 @safe:
33 
34 
35 /********************************************************
36  * Determine which blocks get the function prolog and epilog
37  * attached to them.
38  */
39 
40 @trusted
41 void cod5_prol_epi()
42 {
43 static if(1)
44 {
45     cod5_noprol();
46 }
47 else
48 {
49     tym_t tym;
50     tym_t tyf;
51     block *b;
52     block *bp;
53     int nepis;
54 
55     tyf = funcsym_p.ty();
56     tym = tybasic(tyf);
57 
58     if (!(config.flags4 & CFG4optimized) ||
59         anyiasm ||
60         Alloca.size ||
61         usednteh ||
62         calledFinally ||
63         tyf & (mTYnaked | mTYloadds) ||
64         tym == TYifunc ||
65         tym == TYmfunc ||       // can't yet handle ECX passed as parameter
66         tym == TYjfunc ||       // can't yet handle EAX passed as parameter
67         config.flags & (CFGalwaysframe | CFGtrace) ||
68 //      config.fulltypes ||
69         (config.wflags & WFwindows && tyfarfunc(tym)) ||
70         need_prolog(startblock)
71        )
72     {   // First block gets the prolog, all return blocks
73         // get the epilog.
74         //printf("not even a candidate\n");
75         cod5_noprol();
76         return;
77     }
78 
79     // Turn on BFLoutsideprolog for all blocks outside the ones needing the prolog.
80 
81     for (b = startblock; b; b = b.Bnext)
82         b.Bflags &= ~BFLoutsideprolog;                 // start with them all off
83 
84     pe_add(startblock);
85 
86     // Look for only one block (bp) that will hold the prolog
87     bp = null;
88     nepis = 0;
89     for (b = startblock; b; b = b.Bnext)
90     {   int mark;
91 
92         if (b.Bflags & BFLoutsideprolog)
93             continue;
94 
95         // If all predecessors are marked
96         mark = 0;
97         assert(b.Bpred);
98         foreach (bl; ListRange(b.Bpred))
99         {
100             if (list_block(bl).Bflags & BFLoutsideprolog)
101             {
102                 if (mark == 2)
103                     goto L1;
104                 mark = 1;
105             }
106             else
107             {
108                 if (mark == 1)
109                     goto L1;
110                 mark = 2;
111             }
112         }
113         if (mark == 1)
114         {
115             if (bp)             // if already have one
116                 goto L1;
117             bp = b;
118         }
119 
120         // See if b is an epilog
121         mark = 0;
122         foreach (bl; ListRange(b.Bsucc))
123         {
124             if (list_block(bl).Bflags & BFLoutsideprolog)
125             {
126                 if (mark == 2)
127                     goto L1;
128                 mark = 1;
129             }
130             else
131             {
132                 if (mark == 1)
133                     goto L1;
134                 mark = 2;
135             }
136         }
137         if (mark == 1 || b.BC == BCret || b.BC == BCretexp)
138         {   b.Bflags |= BFLepilog;
139             nepis++;
140             if (nepis > 1 && config.flags4 & CFG4space)
141                 goto L1;
142         }
143     }
144     if (bp)
145     {   bp.Bflags |= BFLprolog;
146         //printf("=============== prolog opt\n");
147     }
148 }
149 }
150 
151 /**********************************************
152  * No prolog/epilog optimization.
153  */
154 
155 @trusted
156 void cod5_noprol()
157 {
158     block *b;
159 
160     //printf("no prolog optimization\n");
161     startblock.Bflags |= BFLprolog;
162     for (b = startblock; b; b = b.Bnext)
163     {
164         b.Bflags &= ~BFLoutsideprolog;
165         switch (b.BC)
166         {   case BCret:
167             case BCretexp:
168                 b.Bflags |= BFLepilog;
169                 break;
170             default:
171                 b.Bflags &= ~BFLepilog;
172         }
173     }
174 }
175 
176 /*********************************************
177  * Add block b, and its successors, to those blocks outside those requiring
178  * the function prolog.
179  */
180 
181 private void pe_add(block *b)
182 {
183     if (b.Bflags & BFLoutsideprolog ||
184         need_prolog(b))
185         return;
186 
187     b.Bflags |= BFLoutsideprolog;
188     foreach (bl; ListRange(b.Bsucc))
189         pe_add(list_block(bl));
190 }
191 
192 /**********************************************
193  * Determine if block needs the function prolog to be set up.
194  */
195 
196 @trusted
197 private int need_prolog(block *b)
198 {
199     if (b.Bregcon.used & fregsaved)
200         goto Lneed;
201 
202     // If block referenced a param in 16 bit code
203     if (!I32 && b.Bflags & BFLrefparam)
204         goto Lneed;
205 
206     // If block referenced a stack local
207     if (b.Bflags & BFLreflocal)
208         goto Lneed;
209 
210     return 0;
211 
212 Lneed:
213     return 1;
214 }