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