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