Changeset c28ea4e
- Timestamp:
- Nov 4, 2020, 2:56:30 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- eeb5023
- Parents:
- 4b30e8cc (diff), a3f5208a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 21 added
- 101 edited
- 4 moved
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/FullBuild
r4b30e8cc rc28ea4e 17 17 18 18 parallel ( 19 clang_x86: { trigger_build( 'gcc-8', 'x86' ) },20 gcc_ 5_x86: { trigger_build( 'gcc-7', 'x86' ) },19 gcc_8_x86: { trigger_build( 'gcc-8', 'x86' ) }, 20 gcc_7_x86: { trigger_build( 'gcc-7', 'x86' ) }, 21 21 gcc_6_x86: { trigger_build( 'gcc-6', 'x86' ) }, 22 22 gcc_9_x64: { trigger_build( 'gcc-9', 'x64' ) }, -
Jenkinsfile
r4b30e8cc rc28ea4e 127 127 } 128 128 129 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} --quiet --prefix=${BuildDir}" 129 ast = Settings.NewAST ? "--enable-new-ast" : "--disable-new-ast" 130 131 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} ${ast} --quiet --prefix=${BuildDir}" 130 132 131 133 // Configure libcfa … … 359 361 public final CC_Desc Compiler 360 362 public final Arch_Desc Architecture 363 public final Boolean NewAST 361 364 public final Boolean RunAllTests 362 365 public final Boolean RunBenchmark … … 410 413 411 414 this.IsSandbox = (branch == "jenkins-sandbox") 415 this.NewAST = param.NewAST 412 416 this.RunAllTests = param.RunAllTests 413 417 this.RunBenchmark = param.RunBenchmark … … 470 474 ], \ 471 475 [$class: 'BooleanParameterDefinition', \ 476 description: 'If true, build compiler using new AST', \ 477 name: 'NewAST', \ 478 defaultValue: false, \ 479 ], \ 480 [$class: 'BooleanParameterDefinition', \ 472 481 description: 'If false, only the quick test suite is ran', \ 473 482 name: 'RunAllTests', \ 474 483 defaultValue: false, \ 475 ], \484 ], 476 485 [$class: 'BooleanParameterDefinition', \ 477 486 description: 'If true, jenkins also runs benchmarks', \ -
configure.ac
r4b30e8cc rc28ea4e 28 28 # New AST toggling support 29 29 AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast]) 30 DEFAULT_NEW_AST="False" 30 31 AC_ARG_ENABLE(new-ast, 31 32 [ --enable-new-ast whether or not to use new ast as the default AST algorithm], 32 33 [case "${enableval}" in 33 yes) newast=true ; ;34 no) newast=false ;;34 yes) newast=true ; DEFAULT_NEW_AST="True" ;; 35 no) newast=false; DEFAULT_NEW_AST="False" ;; 35 36 *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;; 36 37 esac],[newast=false]) 37 38 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast) 39 AC_SUBST(DEFAULT_NEW_AST) 38 40 39 41 #============================================================================== -
doc/papers/concurrency/mail2
r4b30e8cc rc28ea4e 1 1 2 Date: Wed, 26 Jun 2019 20:12:38 +0000 2 3 From: Aaron Thomas <onbehalfof@manuscriptcentral.com> … … 1074 1075 Software: Practice and Experience Editorial Office 1075 1076 1077 1078 1079 Date: Thu, 15 Oct 2020 13:48:52 +0000 1080 From: Richard Jones <onbehalfof@manuscriptcentral.com> 1081 Reply-To: R.E.Jones@kent.ac.uk 1082 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca 1083 Subject: Software: Practice and Experience - Decision on Manuscript ID 1084 SPE-19-0219.R3 1085 1086 15-Oct-2020 1087 1088 Dear Dr Buhr, 1089 1090 It is a pleasure to accept your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" in its current form for publication in Software: Practice and Experience. 1091 1092 Please note although the manuscript is accepted the files will now be checked to ensure that everything is ready for publication, and you may be contacted if final versions of files for publication are required. 1093 1094 Your article cannot be published until the publisher has received the appropriate signed license agreement. Within the next few days the corresponding author will receive an email from Wiley's Author Services system which will ask them to log in and will present them with the appropriate license for completion. 1095 1096 Thank you for your fine contribution. 1097 1098 Sincerely, 1099 Richard 1100 1101 Prof. Richard Jones 1102 Editor, Software: Practice and Experience 1103 R.E.Jones@kent.ac.uk 1104 1105 P.S. - You can help your research get the attention it deserves! Check out Wiley's free Promotion Guide for best-practice recommendations for promoting your work at www.wileyauthors.com/eeo/guide. And learn more about Wiley Editing Services which offers professional video, design, and writing services to create shareable video abstracts, infographics, conference posters, lay summaries, and research news stories for your research at www.wileyauthors.com/eeo/promotion. 1106 1107 This journal accepts artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. For more information, including artwork guidelines, pricing, and submission details, please visit the Journal Cover Image page at www.wileyauthors.com/eeo/covers. If you want help creating an image, Wiley Editing Services offers a professional cover image design service that creates eye-catching images, ready to be showcased on the journal cover at www.wileyauthors.com/eeo/design. 1108 1109 1110 1111 Date: Fri, 16 Oct 2020 12:44:42 +0000 1112 From: Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> 1113 Reply-To: speoffice@wiley.com 1114 To: pabuhr@uwaterloo.ca 1115 Subject: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1116 1117 16-Oct-2020 1118 1119 Dear Dr. Buhr, 1120 1121 Manuscript id: SPE-19-0219.R3 1122 Manuscript title: Advanced Control-flow and Concurrency in Cforall 1123 1124 Although your manuscript has been accepted for publication it is now being returned to your author center for you to review and make any final adjustments or corrections prior to production and publication. 1125 1126 Any special instructions will be listed below: 1127 1) Funding Information added in ScholorOne but missing in main document, Kindly add the Funding information in main document. 1128 2) Please provide the clean version of the manuscript without any highlights or tracked changes. 1129 3) Kindly check and make sure citations for all figures and Tables are present in the main document 1130 1131 Please now log back into your Scholar One Author Center and click on the "Manuscripts Accepted for First Look" queue. In order to update the submission, click on the "submit updated manuscript" link in the "Actions" column and follow the steps as you would during a manuscript submission process. 1132 1133 On the File Upload screen please upload the FINAL versions of all the files, including print quality image files. For information about image quality requirements, please refer to the guidelines at https://authorservices.wiley.com/asset/photos/electronic_artwork_guidelines.pdf. 1134 1135 Instructions for uploading replacement files: 1136 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace. 1137 2. In the "Upload a later version" section, browse to locate the replacement final version. 1138 3. Add any comments concerning the replacement (e.g. "high res image"). 1139 4. Select whether the new file is a minor or major version (we suggest you select minor version) 1140 5. Click upload. 1141 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful. 1142 1143 Please submit your updates within the next 7 days to ensure there are no unnecessary delays in production. 1144 1145 Sincerely, 1146 Software: Practice and Experience Editorial Office 1147 1148 1149 1150 From: SPE Office <speoffice@wiley.com> 1151 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca> 1152 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1153 Date: Mon, 19 Oct 2020 17:04:24 +0000 1154 1155 Dear Dr. Buhr, 1156 1157 Thank you very much for contacting the Editorial Office. 1158 1159 I would like to let you know that the files has been found in order and moved to production. 1160 1161 Plesae let me know for further assistance in this regard. 1162 1163 Best Regards 1164 1165 Mayank Roy Chowdhury 1166 Editorial Assistant 1167 Software practice and Experience 1168 ________________________________ 1169 From: Peter A. Buhr <pabuhr@uwaterloo.ca> 1170 Sent: Sunday, October 18, 2020 2:00 PM 1171 To: SPE Office <speoffice@wiley.com> 1172 Cc: Thierry Delisle <tdelisle@uwaterloo.ca> 1173 Subject: Re: Manuscript Accepted - Please submit final updates to SPE-19-0219.R3 [email ref: ENR-AW-1-c] 1174 1175 This is an external email. 1176 1177 Mayank Roy Chowdhury <onbehalfof@manuscriptcentral.com> writes: 1178 1179 Instructions for uploading replacement files: 1180 1. On the "File Upload" step, click on the "edit" button for the file you wish to replace. 1181 2. In the "Upload a later version" section, browse to locate the replacement final version. 1182 3. Add any comments concerning the replacement (e.g. "high res image"). 1183 4. Select whether the new file is a minor or major version (we suggest you select minor version) 1184 5. Click upload. 1185 6. Click 'Submit' when all the files have been uploaded and you will receive an automated email to say that submission is successful. 1186 1187 There was no "edit" button on the "File Upload" page, so I just upload the 1188 final version of the PDF and source files using the mechanism on the "File 1189 Upload" page and submitted that. 1190 1191 1192 1193 Date: Tue, 20 Oct 2020 13:28:37 +0530 1194 To: "Dr. Peter Buhr" <pabuhr@uwaterloo.ca> 1195 From: jpcms@spi-global.com 1196 Subject: Information: Production Editor Contact Software:Practice and Experience | Advanced Control-flow and Concurrency in C A 1197 1198 Dear Dr. Peter Buhr, 1199 1200 We are in the process of preparing "Advanced Control-flow and Concurrency in C A" for publication. Your production editor, Joel Pacaanas, will support you and your article throughout the process. 1201 1202 Please get in touch with your Production Editor at SPEproofs@wiley.com;EllaMae.Navor@spi-global.com if you have any questions. 1203 1204 Sincerely, 1205 Booking-in Team, 1206 On behalf of Wiley 1207 1208 Article ID: SPE_2925 1209 Article DOI: 10.1002/SPE.2925 1210 1211 1212 1213 Date: Tue, 20 Oct 2020 10:33:04 +0000 1214 From: <cs-author@wiley.com> 1215 To: <pabuhr@uwaterloo.ca> 1216 Subject: In Production: Your article accepted in Software: Practice and Experience 1217 1218 Dear Peter Buhr, 1219 1220 Article ID: SPE2925 1221 Article DOI: 10.1002/spe.2925 1222 Internal Article ID: 16922213 1223 Article: Advanced Control-flow and Concurrency in C A 1224 Journal: Software: Practice and Experience 1225 1226 Congratulations on the acceptance of your article for publication in Software: Practice and Experience. 1227 1228 Your article has been received and the production process is now underway. We look forward to working with you and publishing your article. Using Wiley Author Services, you can track your article's progress. 1229 1230 Please click below to login - if you are using a different email address than this one, you will need to manually assign this article to your Dashboard (see https://hub.wiley.com/docs/support/assigning-a-missing-article-to-my-dashboard-DOC-11871?utm_source=new%20user%20invitation&utm_medium=email How do I assign a missing article to My Dashboard?): 1231 1232 https://authorservices.wiley.com/index.html#login?campaign=email_invitation-new 1233 1234 If applicable, a list of available actions will appear below - check out your Author Services Dashboard for all actions related to your articles. 1235 1236 Sign your license agreement (REQUIRED) -- you will receive an email when this task is ready on your dashboard. Track your article's progress to publicationAccess your published articleInvite colleagues to view your published article 1237 If you need any assistance, please click http://www.wileyauthors.com/help?utm_source=new%20user%20invitation&utm_medium=email here to view our Help section. 1238 1239 Sincerely, 1240 Wiley Author Services 1241 1242 P.S. - Some journals accept artwork submissions for Cover Images. This is an optional service you can use to help increase article exposure and showcase your research. Pricing and placement options vary by journal. For more information, including artwork guidelines, pricing, and submission details, please visit the https://authorservices.wiley.com/author-resources/Journal-Authors/Promotion/journal-cover-image.html?utm_source=as&utm_medium=email&utm_term=invitation_msg&utm_content=covers&utm_campaign=2019feb?campaign=email_invitation-new" target=_blank">Journal Cover Image page. If you want help creating an image, Wiley Editing Services offers a professional https://wileyeditingservices.com/en/article-promotion/cover-image-design.html?utm_source=as&utm_medium=email&utm_term=ie&utm_content=cid&utm_campaign=prodops" target=_blank">Cover Image Design service that creates eye-catching images, ready to be showcased on the journal cover. 1243 1244 1245 1246 Date: Thu, 22 Oct 2020 20:21:49 +0000 1247 From: <cs-author@wiley.com> 1248 To: <pabuhr@uwaterloo.ca> 1249 Subject: You have actions to complete in Author Services 1250 1251 Dear Peter Buhr, 1252 1253 Article ID: SPE2925 1254 Article DOI: 10.1002/spe.2925 1255 Internal Article ID: 16922213 1256 Article: Advanced Control-flow and Concurrency in C A 1257 Journal: Software: Practice and Experience 1258 1259 For the above article, you have the following open tasks: 1260 1261 Sign your license agreement in order to publish your article. Simply click the Sign License button on your https://authorservices.wiley.com?campaign=email_license-notice1">Wiley Author Services Dashboard. 1262 1263 Need any help? Please visit our https://authorsupport.wiley.com/s/">Author Support Center. 1264 1265 Sincerely, 1266 Wiley Author Services 1267 1268 1269 1270 Date: Thu, 22 Oct 2020 23:13:07 +0000 1271 From: <cs-author@wiley.com> 1272 To: <pabuhr@uwaterloo.ca> 1273 Subject: License was successfully submitted! Thank you! 1274 1275 Dear Peter Buhr, 1276 1277 Article ID: SPE2925 1278 Article DOI: 10.1002/spe.2925 1279 Internal Article ID: 16922213 1280 Article: Advanced Control-flow and Concurrency in C A 1281 Journal: Software: Practice and Experience 1282 1283 You've successfully completed license signing for your article - thank you! You can view your signed agreement at any time by visiting your https://authorservices.wiley.com?campaign=email_license-confirm">Wiley Author Services Dashboard. 1284 1285 Sincerely, 1286 1287 Wiley Author Services -
doc/proposals/vtable.md
r4b30e8cc rc28ea4e 512 512 possibly like the one used to create the assertion. 513 513 514 ### Extension: Associated Types Use 515 If the `associated_types.md` proposal is accepted the following trait could 516 be added: 517 518 trait is_virtual(dtype T) { 519 dtype table; 520 // An example assertion: 521 const table & get_virtual_table(T &); 522 } 523 524 There may be more assertions but there has to be at least one way to find 525 the (possibly default) virtual table. It is required to construct instances 526 of the type. 527 528 Without the assotiated type it would look like this: 529 530 trait is_virtual(dtype T, dtype table) { 531 const table & get_virtual_table(T &); 532 } 533 534 Which is just a little bit longer to use but becomes more problematic if the 535 user has to explicately provide the table's name as it doesn't really have its 536 own type name. If it does it is probably mangled. 537 514 538 ### Virtual Tables as Types 515 539 Here we consider encoding plus the implementation of functions on it to be a -
doc/theses/andrew_beach_MMath/thesis-frontpgs.tex
r4b30e8cc rc28ea4e 5 5 % TITLE PAGE 6 6 %---------------------------------------------------------------------- 7 8 % Slowly generalizing. 9 \ethesissetup{ 10 author=Pat Neugraad,% 11 title={University of Waterloo E-Thesis Template for \LaTeX}, 12 degree=phd,% 13 program=Zoology,% 14 } 7 15 8 16 \pagestyle{empty} … … 15 23 \vspace*{1.0cm} 16 24 17 \Huge 18 {\bf University of Waterloo E-Thesis Template for \LaTeX } 19 20 \vspace*{1.0cm} 21 22 \normalsize 25 {\Huge\bf \eprint{title}} 26 27 \vspace*{1.0cm} 28 23 29 by \\ 24 30 25 31 \vspace*{1.0cm} 26 32 27 \Large 28 Pat Neugraad \\ 33 {\Large \eprint{author}} \\ 29 34 30 35 \vspace*{3.0cm} 31 36 32 \normalsize33 37 A thesis \\ 34 38 presented to the University of Waterloo \\ 35 39 in fulfillment of the \\ 36 40 thesis requirement for the degree of \\ 37 Doctor of Philosophy\\41 \eprint{degree} \\ 38 42 in \\ 39 Zoology\\43 \eprint{program} \\ 40 44 41 45 \vspace*{2.0cm} … … 45 49 \vspace*{1.0cm} 46 50 47 \copyright \ Pat Neugraad2017 \\51 \copyright{} \eprint{author} 2017 \\ 48 52 \end{center} 49 53 \end{titlepage} -
doc/theses/andrew_beach_MMath/uw-ethesis.cls
r4b30e8cc rc28ea4e 19 19 % 20 20 % Exported Names: 21 % \ethesissetup{<key-value-pairs>} 22 % Preforms set-up (or a reconfiguration) of the document class. See the 23 % Set-Up Keys section for the keys that may be passed in. Use commas to 24 % seperate key-value-pairs. 25 % 21 26 % \ifformat{<format>}{<true>}{<false>} 22 27 % If the document's format is <format> than expands to <true> otherwise … … 27 32 % initial setup depends on the document format but they can be overriden 28 33 % with options in <setup> (set hyperref's \hypersetup for details). 34 % 35 % \eprint{<key>} 36 % Expands to a human readable value tracked by the ethesis class. This 37 % can be used to retreave and format values set during set up. 38 % 39 % Set-Up Keys: 40 % author=<text> 41 % title=<text> 42 % program=<text> 43 % subject=<text> 44 % keywords=<text> 45 % degree=masters|phd 46 % faculty=ahs|arts|eng|env|math|sci 29 47 \NeedsTeXFormat{LaTeX2e} 30 \ProvidesClass{uw-ethesis}[2020/ 03/24 v0.1UW-eThesis Template Document Class]48 \ProvidesClass{uw-ethesis}[2020/10/25 v0.2 UW-eThesis Template Document Class] 31 49 32 50 \RequirePackage{etoolbox} 51 \RequirePackage{xkeyval} 33 52 34 53 % Requested Format: 35 \newrobustcmd*{\ethesis@ format}{digital}36 \DeclareOption{print}{\renewrobustcmd*{\ethesis@ format}{print}}37 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@ format}{digital}}54 \newrobustcmd*{\ethesis@@format}{digital} 55 \DeclareOption{print}{\renewrobustcmd*{\ethesis@@format}{print}} 56 \DeclareOption{digital}{\renewrobustcmd*{\ethesis@@format}{digital}} 38 57 39 58 \ProcessOptions\relax … … 81 100 % a recto page. This will often require an empty verso (left-hand side) page 82 101 % that should not have the page number printed on it. 83 \let\ origdoublepage\cleardoublepage102 \let\ethesis@origdoublepage\cleardoublepage 84 103 \newcommand{\clearemptydoublepage}{% 85 \clearpage{\pagestyle{empty}\ origdoublepage}}104 \clearpage{\pagestyle{empty}\ethesis@origdoublepage}} 86 105 \let\cleardoublepage\clearemptydoublepage 87 106 … … 89 108 \renewcommand*{\bibname}{References} 90 109 91 % Configurations 92 \def\setThesisTitle#1{\newrobustcmd*{\ethesis@title}{#1}} 93 \def\setThesisAuthor#1{\newrobustcmd*{\ethesis@author}{#1}} 94 \def\setThesisSubject#1{\newrobustcmd*{\ethesis@subject}{#1}} 95 \def\setThesisKeywords#1{\newrobustcmd*{\ethesis@keywords}{#1}} 110 \newrobustcmd*\ethesissetup[1]{\setkeys{ethesis}{#1}} 111 112 \define@cmdkeys{ethesis}[ethesis@@]{% 113 author,title,program,subject,keywords} 114 115 \define@choicekey{ethesis}{degree}{masters,phd}{\def\ethesis@@degree{#1}} 116 \define@choicekey{ethesis}{faculty}{ahs,arts,eng,env,math,sci}% 117 {\def\ethesis@@faculty{#1}} 118 119 \newrobustcmd*\eprint[1]{ 120 \ifcsdef{ethesis@long#1}{\csuse{ethesis@long#1}}{% 121 \ifcsdef{ethesis@@#1}{\csuse{ethesis@@#1}}{% 122 % ERROR: (Check for a way to emit an actual error.) 123 [UW-eThesis doesn't know how to print: #1 ] 124 } 125 } 126 } 127 128 \newrobustcmd*\ethesis@longdegree{% 129 \ifdefstring{\ethesis@@degree}{phd}{Doctor of Philosophy}{Masters}} 96 130 97 131 % Includes the hyperref package loading a number of defaults. … … 106 140 pdfstartview={FitH}, % Fits the width of the page to the window. 107 141 } 108 \ifdef{\ethesis@ title}{\hypersetup{pdftitle={\ethesis@title}}}{}109 \ifdef{\ethesis@ author}{\hypersetup{pdfauthor={\ethesis@author}}}{}110 \ifdef{\ethesis@ subject}{\hypersetup{pdfsubject={\ethesis@subject}}}{}111 \ifdef{\ethesis@ keywords}{\hypersetup{pdfkeywords={\ethesis@keywords}}}{}142 \ifdef{\ethesis@@title}{\hypersetup{pdftitle={\ethesis@@title}}}{} 143 \ifdef{\ethesis@@author}{\hypersetup{pdfauthor={\ethesis@@author}}}{} 144 \ifdef{\ethesis@@subject}{\hypersetup{pdfsubject={\ethesis@@subject}}}{} 145 \ifdef{\ethesis@@keywords}{\hypersetup{pdfkeywords={\ethesis@@keywords}}}{} 112 146 \ifformat{print}{ 113 147 \hypersetup{ -
doc/theses/thierry_delisle_PhD/comp_II/presentation.tex
r4b30e8cc rc28ea4e 36 36 \miniframeson 37 37 } 38 \section{\CFA and Concurrency} 38 \section{Concurrency and \CFA} 39 \begin{frame}{Project} 40 \begin{center} 41 {\large Produce a scheduler for \CFA that is simple for programmers to understand and offers good general performance.} 42 \end{center} 43 \end{frame} 44 %------------------------------ 39 45 \begin{frame}{\CFA} 46 \CFA is a modern extension of C. 47 It adds to C : overloading, constructors/destructors, polymorphism, and much more. 48 49 ~\newline 50 For this project, the relevant aspects are: 51 \begin{itemize} 52 \item Fast and safe system language. 53 \item Threading. 54 \item Manual memory management. 55 \end{itemize} 40 56 41 57 \end{frame} … … 104 120 \begin{frame}{Priority Scheduling} 105 121 \begin{center} 106 {\large122 {\large 107 123 Runs all ready threads in group \textit{A} before any ready threads in group \textit{B}. 108 124 } … … 136 152 137 153 Processors begin busy for long periods can mean starvation. 154 \end{frame} 155 %------------------------------ 156 \begin{frame}{Scheduling in Practice: Summary} 157 \begin{columns} 158 \begin{column}{0.5\textwidth} 159 \textbf{Feedback Scheduling} 160 \newline 161 162 \begin{itemize} 163 \item Inappropriate for short lived threads. 164 \item Overkill for cooperating threads.\newline 165 \end{itemize} 166 \end{column} 167 \begin{column}{0.5\textwidth} 168 \textbf{Priority Scheduling} 169 \newline 170 171 \begin{itemize} 172 \item Allows lasting starvation.\newline 173 \item Hard to reason about.\newline~\newline 174 \end{itemize} 175 \end{column} 176 \end{columns} 177 178 ~\newline 179 ~\newline 180 \CFA would benefit from something different. 138 181 \end{frame} 139 182 %============================== … … 190 233 \begin{itemize} 191 234 \item Acquire for reading for normal scheduling operations. 192 \item Acquire for rightwhen resizing the array and creating/deleting internal queues.235 \item Acquire for writing when resizing the array and creating/deleting internal queues. 193 236 \end{itemize} 194 237 \end{frame} … … 314 357 Runtime system and scheduling are still open topics. 315 358 \newline 359 \newline 316 360 317 361 This work offers a novel runtime and scheduling package. 362 \newline 318 363 \newline 319 364 … … 336 381 337 382 %------------------------------ 338 \begin{frame}{ Timeline}383 \begin{frame}{} 339 384 \begin{center} 340 385 {\large Questions?} -
doc/theses/thierry_delisle_PhD/comp_II/presentationstyle.sty
r4b30e8cc rc28ea4e 20 20 \setbeamertemplate{blocks}[rounded][shadow=false] 21 21 \newcommand\xrowht[2][0]{\addstackgap[.5\dimexpr#2\relax]{\vphantom{#1}}} 22 \setbeamertemplate{sections/subsections in toc}{\inserttocsectionnumber.~\inserttocsection} 22 23 23 24 %============================== … … 36 37 \setbeamercolor{palette primary}{bg=colbg} 37 38 \setbeamercolor{palette tertiary}{fg=red} 39 \setbeamercolor{section in toc}{fg=white} 40 \setbeamercolor{subsection in toc}{fg=gray} 38 41 39 42 %============================== -
doc/theses/thierry_delisle_PhD/thesis/Makefile
r4b30e8cc rc28ea4e 15 15 front \ 16 16 intro \ 17 existing \ 17 18 runtime \ 18 19 core \ … … 27 28 base \ 28 29 empty \ 30 system \ 29 31 } 30 32 … … 37 39 ## Define the documents that need to be made. 38 40 all: thesis.pdf 39 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex 41 thesis.pdf: ${TEXTS} ${FIGURES} ${PICTURES} glossary.tex local.bib 40 42 41 43 DOCUMENT = thesis.pdf -
doc/theses/thierry_delisle_PhD/thesis/fig/system.fig
r4b30e8cc rc28ea4e 1 #FIG 3.2 Produced by xfig version 3.2. 5c1 #FIG 3.2 Produced by xfig version 3.2.7b 2 2 Landscape 3 3 Center … … 36 36 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 3600 15 15 4500 3600 4515 3615 37 37 -6 38 6 3225 4125 4650 442539 6 4350 4200 4650 435040 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 429041 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 429042 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 429043 -644 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 442545 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 442546 -647 6 6675 4125 7500 442548 6 7200 4200 7500 435049 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 429050 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 429051 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 429052 -653 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 442554 -655 38 6 6675 3525 8025 3975 56 39 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2 … … 79 62 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850 80 63 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775 81 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 48 6064 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4830 82 65 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805 83 66 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600 84 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800 85 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875 67 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4625 4838 100 100 4625 4838 4725 4838 86 68 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5 87 69 2400 4200 2400 3750 1950 3750 1950 4200 2400 4200 … … 153 135 1 1 1.00 45.00 90.00 154 136 7875 3750 7875 2325 7200 2325 7200 2550 137 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5 138 6975 4950 6750 4950 6750 4725 6975 4725 6975 4950 155 139 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5 156 140 5850 4950 5850 4725 5625 4725 5625 4950 5850 4950 157 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5 158 6975 4950 6750 4950 6750 4725 6975 4725 6975 4950 159 4 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001 160 4 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001 161 4 1 -1 0 0 0 10 0.0000 2 150 870 4200 3975 Ready Tasks\001 162 4 1 -1 0 0 0 10 0.0000 2 135 1095 7350 1725 Other Cluster(s)\001 163 4 1 -1 0 0 0 10 0.0000 2 105 840 4650 1725 User Cluster\001 164 4 1 -1 0 0 0 10 0.0000 2 150 615 2175 3675 Manager\001 165 4 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001 166 4 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001 167 4 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 generator/coroutine\001 168 4 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001 169 4 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001 170 4 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001 171 4 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001 141 4 1 -1 0 0 0 10 0.0000 2 135 900 5550 4425 Processors\001 142 4 1 -1 0 0 0 10 0.0000 2 165 1170 4200 3975 Ready Threads\001 143 4 1 -1 0 0 0 10 0.0000 2 165 1440 7350 1725 Other Cluster(s)\001 144 4 1 -1 0 0 0 10 0.0000 2 135 1080 4650 1725 User Cluster\001 145 4 1 -1 0 0 0 10 0.0000 2 165 630 2175 3675 Manager\001 146 4 1 -1 0 0 0 10 0.0000 2 135 1260 2175 3525 Discrete-event\001 147 4 1 -1 0 0 0 10 0.0000 2 150 900 2175 4350 preemption\001 148 4 0 -1 0 0 0 10 0.0000 2 135 630 7050 4875 cluster\001 149 4 1 -1 0 0 0 10 0.0000 2 135 1350 4200 3225 Blocked Threads\001 150 4 0 -1 0 0 0 10 0.0000 2 135 540 4800 4875 thread\001 151 4 0 -1 0 0 0 10 0.0000 2 120 810 5925 4875 processor\001 152 4 0 -1 0 0 0 10 0.0000 2 165 1710 2325 4875 generator/coroutine\001 -
doc/theses/thierry_delisle_PhD/thesis/glossary.tex
r4b30e8cc rc28ea4e 1 1 \makeglossaries 2 3 % ---------------------------------- 4 % Acronyms 5 \newacronym{api}{API}{Application Programming Interface} 6 \newacronym{fifo}{FIFO}{First-In, First-Out} 7 \newacronym{io}{I/O}{Input and Output} 8 \newacronym{numa}{NUMA}{Non-Uniform Memory Access} 9 \newacronym{raii}{RAII}{Resource Acquisition Is Initialization} 10 \newacronym{tls}{TLS}{Thread Local Storage} 11 12 % ---------------------------------- 13 % Definitions 14 15 \longnewglossaryentry{thrd} 16 {name={thread}} 17 { 18 Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system. 19 20 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.} 21 } 22 23 \longnewglossaryentry{proc} 24 {name={processor}} 25 { 26 27 } 28 29 \longnewglossaryentry{rQ} 30 {name={ready-queue}} 31 { 32 33 } 34 35 \longnewglossaryentry{uthrding} 36 {name={user-level threading}} 37 { 38 39 40 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.} 41 } 42 43 % ---------------------------------- 2 44 3 45 \longnewglossaryentry{hthrd} 4 46 {name={hardware thread}} 5 47 { 6 Threads representing the underlying hardware directly .48 Threads representing the underlying hardware directly, \eg the CPU core, or hyper-thread if the hardware supports multiple threads of execution per core. The number of hardware threads is considered to be always fixed to a specific number determined by the hardware. 7 49 8 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.} 9 } 10 11 \longnewglossaryentry{thrd} 12 {name={threads}} 13 { 14 Threads created and managed inside user-space. Each thread has its own stack and its own thread of execution. User-level threads are invisible to the underlying operating system. 15 16 \textit{Synonyms : User threads, Lightweight threads, Green threads, Virtual threads, Tasks.} 50 \textit{Synonyms : } 17 51 } 18 52 … … 57 91 } 58 92 59 \longnewglossaryentry{proc}60 {name={virtual processor}}61 {62 93 63 }64 65 \longnewglossaryentry{Q}66 {name={work-queue}}67 {68 69 }70 94 71 95 \longnewglossaryentry{at} … … 131 155 } 132 156 133 134 \newacronym{tls}{TLS}{Thread Local Storage}135 \newacronym{api}{API}{Application Program Interface}136 \newacronym{raii}{RAII}{Resource Acquisition Is Initialization}137 \newacronym{numa}{NUMA}{Non-Uniform Memory Access} -
doc/theses/thierry_delisle_PhD/thesis/text/core.tex
r4b30e8cc rc28ea4e 1 1 \chapter{Scheduling Core}\label{core} 2 2 3 This chapter addresses the need of scheduling on a somewhat ideal scenario 3 Before discussing scheduling in general, where it is important to address systems that are changing states, this document discusses scheduling in a somewhat ideal scenerio, where the system has reached a steady state. For this purpose, a steady state is loosely defined as a state where there are always \glspl{thrd} ready to run and but the system has the ressources necessary to accomplish the work. In short, the system is neither overloaded or underloaded. 4 4 5 \section{Existing Schedulers} 6 \subsection{Feedback Scheduling} 5 I believe it is important to discuss the steady state first because it is the easiest case to handle and, relatedly, the case in which the best performance is to be expected. As such, when the system is either overloaded or underloaded, a common approach is to try to adapt the system to the new load and return to the steady state. Flaws in the scheduling in the steady state tend therefore to be pervasive in all states. 7 6 8 \subsection{Priority Scheduling}\label{priority} 7 \section{Design Goals} 8 As with most of the design decisions behind \CFA, the main goal is to match the expectation of the programmer, according to their probable mental model. To match these expectations, the design must offer the programmers sufficient guarantees so that, as long as the programmer respects the mental model, the system will also respect this model. 9 9 10 \subsection{Work Stealing} 10 For threading, a simple and common mental model is the ``Ideal multi-tasking CPU'' : 11 12 \begin{displayquote}[Linux CFS\cit{https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt}] 13 {[The]} ``Ideal multi-tasking CPU'' is a (non-existent :-)) CPU that has 100\% physical power and which can run each task at precise equal speed, in parallel, each at [an equal fraction of the] speed. For example: if there are 2 tasks running, then it runs each at 50\% physical power --- i.e., actually in parallel. 14 \end{displayquote} 15 16 Applied to threads, this model states that every ready \gls{thrd} immediately runs in parallel with all other ready \glspl{thrd}. While a strict implementation of this model is not feasible, programmers still have expectations about scheduling that come from this model. 17 18 In general, the expectation at the center of this model is that ready \glspl{thrd} do not interfere with eachother but simply share the hardware. This makes it easier to reason about threading because ready \glspl{thrd} can be taken in isolation and the effect of the scheduler can be virtually ignored. This expectation of \gls{thrd} independence means the scheduler is expected to offer 2 guarantees: 19 \begin{enumerate} 20 \item A fairness guarantee: a \gls{thrd} that is ready to run will not be prevented to do so by another thread. 21 \item A performance guarantee: a \gls{thrd} that wants to start or stop running will not be slowed down by other threads wanting to do the same. 22 \end{enumerate} 23 24 It is important to note that these guarantees are expected only up to a point. \Glspl{thrd} that are ready to run should not be prevented to do so, but they still need to share a limited amount of hardware. Therefore, the guarantee is considered respected if a \gls{thrd} gets access to a \emph{fair share} of the hardware, even if that share is very small. 25 26 Similarly the performance guarantee, the lack of interferance between threads is only relevant op to a point. Ideally the cost of running and blocking would be constant regardless of contention, but the guarantee is considered satisfied if the cost is not \emph{too high} with or without contention. How much is an acceptable cost is obviously highly variable. For this document the performance experimentation will attempt to show that the cost of scheduling is not a major factor in application performance. This demonstration can be made by comparing application built in \CFA to applications built with other languages or other models. If the performance of an application built in \CFA is not meaningfully different than one built with a different runtime, then the scheduler has a negigeable impact on performance, \ie its impact can be ignored. Recall from a few paragraphs ago that the expectation of programmers is that the impact of the scheduler can be ignored. Therefore, if the cost of scheduling is not a significant portion of the runtime of several different application, I will consider the guarantee achieved. 27 28 \todo{This paragraph should be moved later} 29 % The next step is then to decide what is considered a \emph{fair share}, \ie what metric is used to measure fairness. Since \CFA is intended to allow numerous short lived threads, I decided to avoid total CPU time as the measure of fairness. Total CPU time inherently favors new \glspl{thrd} over older ones which isn't necessarily a good thing. Instead, fairness is measured in terms of opportunities to run. This metric is more appropriate for a mix of short and long lived \glspl{thrd}. 11 30 12 31 \section{Design} 13 While avoiding the pitfalls of Feedback Scheduling is fairly easy, scheduling does not innately require feedback, avoiding prioritization of \glspl{thrd} is more difficult because of implicitly priorities, see Subsection~\ref{priority}. 32 While avoiding the pitfalls of Feedback Scheduling is fairly easy, scheduling does not innately require feedback, avoiding prioritization of \glspl{thrd} is more difficult because of implicitly priorities, see Subsection~\ref{priority}. A strictly \glsxtrshort{fifo} rea 14 33 15 34 \subsection{Sharding} … … 19 38 \input{base.pstex_t} 20 39 \end{center} 21 \caption{Relaxed FIFO list at the base of the scheduler: an array of strictly FIFO lists. 22 The timestamp is in all nodes and cell arrays.} 40 \caption{Relaxed FIFO list} 23 41 \label{fig:base} 42 List at the base of the scheduler: an array of strictly FIFO lists. 43 The timestamp is in all nodes and cell arrays. 24 44 \end{figure} 25 45 … … 28 48 Indeed, if the number of \glspl{thrd} does not far exceed the number of queues, it is probable that several of these queues are empty. 29 49 Figure~\ref{fig:empty} shows an example with 2 \glspl{thrd} running on 8 queues, where the chances of getting an empty queue is 75\% per pick, meaning two random picks yield a \gls{thrd} only half the time. 30 This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses.31 32 Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme.33 34 \paragraph{Dense Information}35 36 37 38 50 39 51 … … 42 54 \input{empty.pstex_t} 43 55 \end{center} 44 \caption{``More empty'' state of the queue: the array contains many empty cells.}56 \caption{``More empty'' Relaxed FIFO list} 45 57 \label{fig:empty} 58 Emptier state of the queue: the array contains many empty cells, that is strictly FIFO lists containing no elements. 46 59 \end{figure} 60 61 This can lead to performance problems since picks that do not yield a \gls{thrd} are not useful and do not necessarily help make more informed guesses. 62 63 Solutions to this problem can take many forms, but they ultimately all have to encode where the threads are in some form. My results show that the density and locality of this encoding is generally the dominating factor in these scheme. 64 65 \paragraph{Dense Information} -
doc/theses/thierry_delisle_PhD/thesis/text/front.tex
r4b30e8cc rc28ea4e 184 184 \phantomsection % allows hyperref to link to the correct page 185 185 186 % TODOs and missing citations 187 % ----------------------------- 186 188 \listofcits 187 189 \listoftodos 190 \cleardoublepage 191 \phantomsection % allows hyperref to link to the correct page 188 192 189 193 -
doc/theses/thierry_delisle_PhD/thesis/text/intro.tex
r4b30e8cc rc28ea4e 1 \chapter{Introduction} 1 \chapter*{Introduction}\label{intro} 2 \todo{A proper intro} 3 4 The C programming language\cit{C} 5 6 The \CFA programming language\cite{cfa:frontpage,cfa:typesystem} which extends the C programming language to add modern safety and productiviy features while maintaining backwards compatibility. Among it's productiviy features, \CFA introduces support for threading\cit{CFA Concurrency}, to allow programmers to write modern concurrent and parallel programming. 7 While previous work on the concurrent package of \CFA focused on features and interfaces, this thesis focuses on performance, introducing \glsxtrshort{api} changes only when required by performance considerations. More specifically, this thesis concentrates on scheduling and \glsxtrshort{io}. Prior to this work, the \CFA runtime used a strictly \glsxtrshort{fifo} \gls{rQ}. 8 9 This work exclusively concentrates on Linux as it's operating system since the existing \CFA runtime and compiler does not already support other operating systems. Furthermore, as \CFA is yet to be released, supporting version of Linux older that the latest version is not a goal of this work. -
doc/theses/thierry_delisle_PhD/thesis/text/io.tex
r4b30e8cc rc28ea4e 1 \chapter{I/O} 1 \chapter{User Level \glsxtrshort{io}} 2 As mentionned in Section~\ref{prev:io}, User-Level \glsxtrshort{io} requires multiplexing the \glsxtrshort{io} operations of many \glspl{thrd} onto fewer \glspl{proc} using asynchronous \glsxtrshort{io} operations. Various operating systems offer various forms of asynchronous operations and as mentioned in Chapter~\ref{intro}, this work is exclusively focuesd on Linux. 2 3 3 4 \section{Existing options} 5 Since \glsxtrshort{io} operations are generally handled by the 4 6 5 7 \subsection{\texttt{epoll}, \texttt{poll} and \texttt{select}} … … 7 9 \subsection{Linux's AIO} 8 10 11 12 13 \begin{displayquote} 14 AIO is a horrible ad-hoc design, with the main excuse being "other, 15 less gifted people, made that design, and we are implementing it for 16 compatibility because database people - who seldom have any shred of 17 taste - actually use it". 18 19 But AIO was always really really ugly. 20 21 \begin{flushright} 22 -- Linus Torvalds\cit{https://lwn.net/Articles/671657/} 23 \end{flushright} 24 \end{displayquote} 25 26 Interestingly, in this e-mail answer, Linus goes on to describe 27 ``a true \textit{asynchronous system call} interface'' 28 that does 29 ``[an] arbitrary system call X with arguments A, B, C, D asynchronously using a kernel thread'' 30 in 31 ``some kind of arbitrary \textit{queue up asynchronous system call} model''. 32 This description is actually quite close to the interface of the interface described in the next section. 33 9 34 \subsection{\texttt{io\_uring}} 35 A very recent addition to Linux, \texttt{io\_uring}\cit{io\_uring} is a framework that aims to solve many of the problems listed with the above mentioned solutions. 10 36 11 \subsection{Extra Kernel Threads} 37 \subsection{Extra Kernel Threads}\label{io:morethreads} 38 Finally, if the operating system does not offer any satisfying forms of asynchronous \glsxtrshort{io} operations, a solution is to fake it by creating a pool of \glspl{kthrd} and delegating operations to them in order to avoid blocking \glspl{proc}. 12 39 13 40 \subsection{Discussion} -
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex
r4b30e8cc rc28ea4e 2 2 The scheduling algorithm discribed in Chapter~\ref{core} addresses scheduling in a stable state. 3 3 However, it does not address problems that occur when the system changes state. 4 Indeed the \CFA runtime, supports expanding and shrinking 5 6 the number of KTHREAD\_place 7 8 , both manually and, to some extent automatically. 4 Indeed the \CFA runtime, supports expanding and shrinking the number of KTHREAD\_place \todo{add kthrd to glossary}, both manually and, to some extent automatically. 9 5 This entails that the scheduling algorithm must support these transitions. 10 6 -
doc/theses/thierry_delisle_PhD/thesis/text/runtime.tex
r4b30e8cc rc28ea4e 1 1 \chapter{\CFA Runtime} 2 This chapter offers an overview of the capabilities of the \CFA runtime prior to this work. 2 3 3 \section{M:N Threading} 4 Threading in \CFA offers is based on \Gls{uthrding}, where \glspl{thrd} are the representation of a unit of work. As such, \CFA programmers should expect these units to be fairly inexpensive, that is: programmers should be able to create a large number of \glspl{thrd} and switch between \glspl{thrd} liberally without many concerns for performance. 5 6 \section{M:N Threading}\label{prev:model} 7 8 C traditionnally uses a 1:1 threading model. This model uses \glspl{kthrd} to achive parallelism and concurrency. In this model, every thread of computation maps to an object in the kernel. The kernel then has the responsibility of managing these threads, \eg creating, scheduling, blocking. This also entails that the kernel has a perfect view of every thread executing in the system\footnote{This is not completly true due to primitives like \texttt{futex}es, which have a significant portion of their logic in user space.}. 9 10 By contrast \CFA uses an M:N threading models, where concurrency is achieved using many user-level threads mapped onto fewer \glspl{kthrd}. The user-level threads have the same semantic meaning as a \glspl{kthrd} in the 1:1 model, they represent an independant thread of execution with it's on stack. The difference is that user-level threads do not have a corresponding object in the kernel, they are handled by the runtime in user space and scheduled onto \glspl{kthrd}, referred to as \glspl{proc} in this document. \Glspl{proc} run a \gls{thrd} until it context switches out, it then choses a different \gls{thrd} to run. 4 11 5 12 \section{Clusters} 13 \begin{figure} 14 \begin{center} 15 \input{system.pstex_t} 16 \end{center} 17 \caption{Overview of the \CFA runtime} 18 \label{fig:system} 19 \Glspl{thrd} are scheduled inside a particular cluster, where it only runs on the \glspl{proc} which belong to the cluster. The discrete-event manager, which handles preemption and timeout, is a \gls{kthrd} which lives outside any cluster and does not run \glspl{thrd}. 20 \end{figure} 21 \CFA allows the option to group user-level threading, in the form of clusters. Both \glspl{thrd} and \glspl{proc} belong to a specific cluster. \Glspl{thrd} will only be scheduled onto \glspl{proc} in the same cluster and scheduling is done independantly of other clusters. Figure~\ref{fig:system} shows an overview if this system. This allows programmers to control more tightly parallelism. It also opens the door to handling effects like NUMA, by pining clusters to specific NUMA node\footnote{This is not currently implemented in \CFA, but the only hurdle left is creating a generic interface for cpu masks.}. 22 23 \section{Scheduling} 24 The \CFA runtime was previously using a strictly \glsxtrshort{fifo} ready queue with a single lock. This setup offers perfect fairness in terms of opportunities to run/ However, it offers poor scalability, since the performance of the ready queue can never be improved by adding more \glspl{hthrd}, but the contention can cause significant performance degradation. 25 26 \section{\glsxtrshort{io}}\label{prev:io} 27 Prior to this work, the \CFA runtime did not add any particular support for \glsxtrshort{io} operations. \CFA being built on C, this means that, while all the operations available in C are available in \CFA, \glsxtrshort{io} operations are designed for the POSIX threading model\cit{pthreads}. Using these operations in a M:N threading model, when they are built for 1:1 threading, means that operations block \glspl{proc} instead of \glspl{thrd}. While this can work in certain cases, it limits the number of concurrent operations to the number of \glspl{proc} rather than \glspl{thrd}. This also means that deadlocks can occur because all \glspl{proc} are blocked even if at least one \gls{thrd} is ready to run. A simple example of this type of deadlock would be as follows: 28 29 Given a simple network program with 2 \glspl{thrd} and a single \gls{proc}, one \gls{thrd} sends network requests to a server and the other \gls{thrd} waits for response from the server. If the second \gls{thrd} races ahead, it may wait for responses to requests that have not been sent yet. In theory, this should not be a problem, even if the second \gls{thrd} waits, the first \gls{thrd} is still ready to run and should just be able to get CPU time and send the request. In practice with M:N threading, while the first \gls{thrd} is ready, the lone \gls{proc} in this example will \emph{not} try to run the first \gls{thrd} if it is blocked in the \glsxtrshort{io} operation of the second \gls{thrd}. If this happen, the system is effectively deadlocked\footnote{In this example, the deadlocked could be resolved if the server sends unprompted messages to the client. However, this solution is not general and may not be appropriate even in this simple case.}. 30 31 One of the objective of this work, is to introduce \emph{User-Level \glsxtrshort{io}} which, as a parallel to \glslink{uthrding}{User-Level \emph{Threading}}, blocks \glspl{thrd} rather than \glspl{proc} when doing \glsxtrshort{io} operations. This entails multiplexing the \glsxtrshort{io} operations of many \glspl{thrd} onto fewer \glspl{proc}. This multiplexing requires that a single \gls{proc} be able to execute multiple operations in parallel. This cannot be done with operations that block \glspl{proc}, \ie \glspl{kthrd}, since the first operation would prevent starting new operations for its duration. Executing operations in parallel requires \emph{asynchronous} \glsxtrshort{io}, sometimes referred to as \emph{non-blocking}, since the \gls{kthrd} is not blocked. 6 32 7 33 \section{Interoperating with \texttt{C}} 34 While \glsxtrshort{io} operations are the classical example of operations that block \glspl{kthrd}, the challenges mentioned in the previous section do not require \glsxtrshort{io} to be involved. These challenges are a product of blocking system calls rather than \glsxtrshort{io}. C offers no tools to identify whether or not a librairy function will lead to a blocking system call. This fact means interoperatability with C becomes a challenge in a M:N threading model. 35 36 Languages like Go and Java, which have strict interoperatability with C\cit{JNI, GoLang with C}, can control operations in C by ``sandboxing'' them. They can, for example, delegate C operations to \glspl{kthrd} that are not \glspl{proc}. Sandboxing may help towards guaranteeing that the deadlocks mentioned in the previous section do not occur. 37 38 As mentioned in Section~\cit{\CFA intro}, \CFA is binary compatible with C and, as such, trivially supports calls to and from C librairies. Furthermore, interoperatability can happen within a single library, through inline code or simply C and \CFA translation units archived together. The fine-grained interoperatability between C and \CFA has two consequences: 39 \begin{enumerate} 40 \item Precisely identifying C calls that could block is difficult. 41 \item Introducing code where interoperatability occurs could have a significant impact on general performance. 42 \end{enumerate} 43 44 Because of these consequences, this work does not attempt to ``sandbox'' calls to C. It is possible that conflicting calls to C could lead to deadlocks on \CFA's M:N threading model where they would not in the traditionnal 1:1 threading model. However, I judge that solving this problem in general, in a way that is composable and flexible, is too complex in itself and would add too much work to this thesis. Therefore it is outside the scope of this thesis. -
doc/theses/thierry_delisle_PhD/thesis/thesis.tex
r4b30e8cc rc28ea4e 121 121 % installation instructions there. 122 122 123 \usepackage{csquotes} 124 \usepackage{indentfirst} % as any self-respecting frenchman would 125 123 126 % Setting up the page margins... 124 127 % uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at the … … 218 221 % separate documents, they would each start with the \chapter command, i.e, 219 222 % do not contain \documentclass or \begin{document} and \end{document} commands. 223 \part{Introduction} 220 224 \input{text/intro.tex} 225 \input{text/existing.tex} 221 226 \input{text/runtime.tex} 227 \part{Design} 222 228 \input{text/core.tex} 223 229 \input{text/practice.tex} 224 230 \input{text/io.tex} 231 \part{Evaluation} 232 \chapter{Theoretical and Existance Proofs} 233 \chapter{Micro-Benchmarks} 234 \chapter{Larger-Scale applications} 235 \part{Conclusion \& Annexes} 225 236 226 237 %---------------------------------------------------------------------- … … 245 256 \addcontentsline{toc}{chapter}{\textbf{References}} 246 257 247 \bibliography{ uw-ethesis}258 \bibliography{local} 248 259 % Tip 5: You can create multiple .bib files to organize your references. 249 260 % Just list them all in the \bibliogaphy command, separated by commas (no spaces). 250 261 251 % The following statement causes the specified references to be added to the bibliography% even if they were not252 % cited in the text. The asterisk is a wildcard that causes all entries in the bibliographic database to be included (optional).253 \nocite{*}262 % % The following statement causes the specified references to be added to the bibliography% even if they were not 263 % % cited in the text. The asterisk is a wildcard that causes all entries in the bibliographic database to be included (optional). 264 % \nocite{*} 254 265 255 266 % The \appendix statement indicates the beginning of the appendices. -
libcfa/prelude/builtins.c
r4b30e8cc rc28ea4e 9 9 // Author : Peter A. Buhr 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Oct 9 18:26:19202013 // Update Count : 11 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 14:42:00 2020 13 // Update Count : 111 14 14 // 15 16 #define __cforall_builtins__ 15 17 16 18 // type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions -
libcfa/src/concurrency/clib/cfathread.cfa
r4b30e8cc rc28ea4e 59 59 void cfathread_setproccnt( int ncnt ) { 60 60 assert( ncnt >= 1 ); 61 adelete( proc_cnt, procs);61 adelete( procs ); 62 62 63 63 proc_cnt = ncnt - 1; -
libcfa/src/concurrency/coroutine.cfa
r4b30e8cc rc28ea4e 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue May 26 22:06:09202013 // Update Count : 2 112 // Last Modified On : Fri Oct 23 23:05:24 2020 13 // Update Count : 22 14 14 // 15 15 … … 24 24 #include <unistd.h> 25 25 #include <sys/mman.h> // mprotect 26 extern "C" {27 // use this define to make unwind.h play nice, definitely a hack28 #define HIDE_EXPORTS29 26 #include <unwind.h> 30 #undef HIDE_EXPORTS31 }32 27 33 28 #include "kernel_private.hfa" 29 #include "exception.hfa" 34 30 35 31 #define __CFA_INVOKE_PRIVATE__ … … 49 45 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) 50 46 51 struct __cfaehm_node {52 struct _Unwind_Exception unwind_exception;53 struct __cfaehm_node * next;54 int handler_index;55 };56 57 47 forall(dtype T) 58 48 void mark_exception(CoroutineCancelled(T) *) {} … … 60 50 forall(dtype T) 61 51 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { 52 dst->virtual_table = src->virtual_table; 62 53 dst->the_coroutine = src->the_coroutine; 63 54 dst->the_exception = src->the_exception; … … 74 65 verify( desc->cancellation ); 75 66 desc->state = Cancelled; 76 exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);67 exception_t * except = __cfaehm_cancellation_exception( desc->cancellation ); 77 68 78 69 // TODO: Remove explitate vtable set once trac#186 is fixed. … … 92 83 93 84 // minimum feasible stack size in bytes 94 #define MinStackSize 1000 85 static const size_t MinStackSize = 1000; 95 86 extern size_t __page_size; // architecture pagesize HACK, should go in proper runtime singleton 96 87 … … 217 208 size = libFloor(create_size - stack_data_size - diff, libAlign()); 218 209 } // if 219 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of % d bytes for a stack.", size, MinStackSize );210 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize ); 220 211 221 212 this->storage = (__stack_t *)((intptr_t)storage + size); -
libcfa/src/concurrency/exception.cfa
r4b30e8cc rc28ea4e 10 10 // Created On : Mon Aug 17 10:41:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Aug 25 14:41:00 202013 // Update Count : 012 // Last Modified On : Wed Oct 28 14:34:00 2020 13 // Update Count : 1 14 14 // 15 15 16 extern "C" { 17 // use this define to make unwind.h play nice, definitely a hack 18 #define HIDE_EXPORTS 19 #include <unwind.h> 20 #undef HIDE_EXPORTS 21 } 16 #define __cforall_thread__ 22 17 23 #include "invoke.h"24 18 #include "exception.hfa" 19 25 20 #include "coroutine.hfa" 26 21 27 22 extern struct $thread * mainThread; 23 extern "C" { 24 extern void __cfactx_thrd_leave(); 25 } 28 26 29 27 // Common pattern for all the stop functions, wait until the end then act. … … 52 50 53 51 STOP_AT_END_FUNCTION(thread_cancelstop, 54 // TODO: Instead pass information to the joiner.55 abort();52 __cfactx_thrd_leave(); 53 __cabi_abort( "Resumed cancelled thread" ); 56 54 ) 57 55 … … 85 83 stop_param = (void *)0x22; 86 84 } else { 85 this_thread->self_cor.cancellation = unwind_exception; 86 87 87 stop_func = thread_cancelstop; 88 88 stop_param = this_thread; -
libcfa/src/concurrency/exception.hfa
r4b30e8cc rc28ea4e 16 16 #pragma once 17 17 18 // This is an internal bridge between the two modes and must be C compatable. 19 20 #include <unwind.h> 18 21 #include "bits/defs.hfa" 19 22 #include "invoke.h" 23 #include "exception.h" 20 24 21 25 #ifdef __cforall 22 26 extern "C" { 23 24 #define HIDE_EXPORTS25 27 #endif 26 #include "unwind.h"27 28 28 29 struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD; … … 32 33 33 34 #ifdef __cforall 34 #undef HIDE_EXPORTS35 35 } 36 36 #endif -
libcfa/src/concurrency/invoke.h
r4b30e8cc rc28ea4e 157 157 158 158 // current execution status for coroutine 159 // Possible values are: 160 // - TICKET_BLOCKED (-1) thread is blocked 161 // - TICKET_RUNNING ( 0) thread is running 162 // - TICKET_UNBLOCK ( 1) thread should ignore next block 159 163 volatile int ticket; 160 164 enum __Coroutine_State state:8; -
libcfa/src/concurrency/io/call.cfa.in
r4b30e8cc rc28ea4e 47 47 #include "kernel/fwd.hfa" 48 48 49 #if defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC) 50 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN | IOSQE_ASYNC) 51 #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_ASYNC) 52 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_ASYNC) 53 #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) && defined(CFA_HAVE_IOSQE_IO_DRAIN) 54 #define REGULAR_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_DRAIN) 55 #elif defined(CFA_HAVE_IOSQE_IO_DRAIN) && defined(CFA_HAVE_IOSQE_ASYNC) 56 #define REGULAR_FLAGS (IOSQE_IO_DRAIN | IOSQE_ASYNC) 57 #elif defined(CFA_HAVE_IOSQE_FIXED_FILE) 58 #define REGULAR_FLAGS (IOSQE_FIXED_FILE) 59 #elif defined(CFA_HAVE_IOSQE_IO_DRAIN) 60 #define REGULAR_FLAGS (IOSQE_IO_DRAIN) 61 #elif defined(CFA_HAVE_IOSQE_ASYNC) 62 #define REGULAR_FLAGS (IOSQE_ASYNC) 63 #else 64 #define REGULAR_FLAGS (0) 65 #endif 66 67 #if defined(CFA_HAVE_IOSQE_IO_LINK) && defined(CFA_HAVE_IOSQE_IO_HARDLINK) 68 #define LINK_FLAGS (IOSQE_IO_LINK | IOSQE_IO_HARDLINK) 69 #elif defined(CFA_HAVE_IOSQE_IO_LINK) 70 #define LINK_FLAGS (IOSQE_IO_LINK) 71 #elif defined(CFA_HAVE_IOSQE_IO_HARDLINK) 72 #define LINK_FLAGS (IOSQE_IO_HARDLINK) 73 #else 74 #define LINK_FLAGS (0) 75 #endif 76 77 #if defined(CFA_HAVE_SPLICE_F_FD_IN_FIXED) 78 #define SPLICE_FLAGS (SPLICE_F_FD_IN_FIXED) 79 #else 80 #define SPLICE_FLAGS (0) 81 #endif 49 static const __u8 REGULAR_FLAGS = 0 50 #if defined(CFA_HAVE_IOSQE_FIXED_FILE) 51 | IOSQE_FIXED_FILE 52 #endif 53 #if defined(CFA_HAVE_IOSQE_IO_DRAIN) 54 | IOSQE_IO_DRAIN 55 #endif 56 #if defined(CFA_HAVE_IOSQE_ASYNC) 57 | IOSQE_ASYNC 58 #endif 59 ; 60 61 static const __u32 LINK_FLAGS = 0 62 #if defined(CFA_HAVE_IOSQE_IO_LINK) 63 | IOSQE_IO_LINK 64 #endif 65 #if defined(CFA_HAVE_IOSQE_IO_HARDLINK) 66 | IOSQE_IO_HARDLINK 67 #endif 68 ; 69 70 static const __u32 SPLICE_FLAGS = 0 71 #if defined(CFA_HAVE_SPLICE_F_FD_IN_FIXED) 72 | SPLICE_F_FD_IN_FIXED 73 #endif 74 ; 82 75 83 76 extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ); -
libcfa/src/concurrency/io/setup.cfa
r4b30e8cc rc28ea4e 149 149 id.full_proc = false; 150 150 id.id = doregister(&id); 151 kernelTLS.this_proc_id = &id; 151 152 __cfaabi_dbg_print_safe( "Kernel : IO poller thread starting\n" ); 152 153 … … 180 181 kernelTLS.this_stats = io_ctx->self.curr_cluster->stats; 181 182 #endif 182 __post( io_ctx->sem, &id);183 post( io_ctx->sem ); 183 184 } 184 185 } … … 235 236 if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) { 236 237 237 ready_schedule_lock( (struct __processor_id_t *)active_processor());238 ready_schedule_lock(); 238 239 239 240 // This is the tricky case … … 250 251 // Fixup the thread state 251 252 thrd.state = Blocked; 252 thrd.ticket = 0;253 thrd.ticket = TICKET_BLOCKED; 253 254 thrd.preempted = __NO_PREEMPTION; 254 255 255 ready_schedule_unlock( (struct __processor_id_t *)active_processor());256 ready_schedule_unlock(); 256 257 257 258 // Pretend like the thread was blocked all along … … 275 276 } 276 277 } else { 277 unpark( &thrd);278 post( this.thrd.sem ); 278 279 } 279 280 -
libcfa/src/concurrency/kernel.cfa
r4b30e8cc rc28ea4e 108 108 static $thread * __next_thread_slow(cluster * this); 109 109 static void __run_thread(processor * this, $thread * dst); 110 static void __wake_one( struct __processor_id_t * id,cluster * cltr);110 static void __wake_one(cluster * cltr); 111 111 112 112 static void push (__cluster_idles & idles, processor & proc); … … 252 252 /* paranoid */ verify( kernelTLS.this_thread == thrd_dst ); 253 253 /* paranoid */ verify( thrd_dst->context.SP ); 254 /* paranoid */ verify( thrd_dst->state != Halted ); 254 255 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 255 256 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor … … 281 282 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 282 283 // The thread was preempted, reschedule it and reset the flag 283 __schedule_thread( (__processor_id_t*)this,thrd_dst );284 __schedule_thread( thrd_dst ); 284 285 break RUNNING; 285 286 } … … 287 288 if(unlikely(thrd_dst->state == Halted)) { 288 289 // The thread has halted, it should never be scheduled/run again 289 // We may need to wake someone up here since 290 unpark( this->destroyer ); 291 this->destroyer = 0p; 290 // finish the thread 291 __thread_finish( thrd_dst ); 292 292 break RUNNING; 293 293 } … … 299 299 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST); 300 300 switch(old_ticket) { 301 case 1:301 case TICKET_RUNNING: 302 302 // This is case 1, the regular case, nothing more is needed 303 303 break RUNNING; 304 case 2:304 case TICKET_UNBLOCK: 305 305 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 306 306 // In this case, just run it again. … … 358 358 // Scheduler routines 359 359 // KERNEL ONLY 360 void __schedule_thread( struct __processor_id_t * id,$thread * thrd ) {360 void __schedule_thread( $thread * thrd ) { 361 361 /* paranoid */ verify( thrd ); 362 362 /* paranoid */ verify( thrd->state != Halted ); 363 363 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 364 /* paranoid */ verify( kernelTLS.this_proc_id ); 364 365 /* paranoid */ #if defined( __CFA_WITH_VERIFY__ ) 365 366 /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION, … … 374 375 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 375 376 376 ready_schedule_lock ( id);377 ready_schedule_lock(); 377 378 push( thrd->curr_cluster, thrd ); 378 __wake_one( id,thrd->curr_cluster);379 ready_schedule_unlock( id);379 __wake_one(thrd->curr_cluster); 380 ready_schedule_unlock(); 380 381 381 382 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); … … 384 385 // KERNEL ONLY 385 386 static inline $thread * __next_thread(cluster * this) with( *this ) { 386 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 387 388 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 387 /* paranoid */ verify( kernelTLS.this_proc_id ); 388 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 389 390 ready_schedule_lock(); 389 391 $thread * thrd = pop( this ); 390 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 391 392 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 392 ready_schedule_unlock(); 393 394 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 395 /* paranoid */ verify( kernelTLS.this_proc_id ); 393 396 return thrd; 394 397 } … … 396 399 // KERNEL ONLY 397 400 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 398 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 399 400 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 401 /* paranoid */ verify( kernelTLS.this_proc_id ); 402 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 403 404 ready_schedule_lock(); 401 405 $thread * thrd = pop_slow( this ); 402 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 403 404 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 406 ready_schedule_unlock(); 407 408 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 409 /* paranoid */ verify( kernelTLS.this_proc_id ); 405 410 return thrd; 406 411 } 407 412 408 // KERNEL ONLY unpark with out disabling interrupts 409 void __unpark( struct __processor_id_t * id, $thread * thrd ) { 413 void unpark( $thread * thrd ) { 414 if( !thrd ) return; 415 416 /* paranoid */ verify( kernelTLS.this_proc_id ); 417 bool full = kernelTLS.this_proc_id->full_proc; 418 if(full) disable_interrupts(); 419 420 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 410 421 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 411 422 switch(old_ticket) { 412 case 1:423 case TICKET_RUNNING: 413 424 // Wake won the race, the thread will reschedule/rerun itself 414 425 break; 415 case 0:426 case TICKET_BLOCKED: 416 427 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 417 428 /* paranoid */ verify( thrd->state == Blocked ); 418 429 419 430 // Wake lost the race, 420 __schedule_thread( id,thrd );431 __schedule_thread( thrd ); 421 432 break; 422 433 default: 423 434 // This makes no sense, something is wrong abort 424 abort(); 425 } 426 } 427 428 void unpark( $thread * thrd ) { 429 if( !thrd ) return; 430 431 disable_interrupts(); 432 __unpark( (__processor_id_t*)kernelTLS.this_processor, thrd ); 433 enable_interrupts( __cfaabi_dbg_ctx ); 435 abort("Thread %p (%s) has mismatch park/unpark\n", thrd, thrd->self_cor.name); 436 } 437 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 438 439 if(full) enable_interrupts( __cfaabi_dbg_ctx ); 440 /* paranoid */ verify( kernelTLS.this_proc_id ); 434 441 } 435 442 … … 448 455 } 449 456 450 // KERNEL ONLY 451 void __leave_thread() { 452 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 453 returnToKernel(); 454 abort(); 457 extern "C" { 458 // Leave the thread monitor 459 // last routine called by a thread. 460 // Should never return 461 void __cfactx_thrd_leave() { 462 $thread * thrd = TL_GET( this_thread ); 463 $monitor * this = &thrd->self_mon; 464 465 // Lock the monitor now 466 lock( this->lock __cfaabi_dbg_ctx2 ); 467 468 disable_interrupts(); 469 470 thrd->state = Halted; 471 if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); } 472 if( thrd != this->owner || this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); } 473 474 // Leave the thread 475 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 476 returnToKernel(); 477 abort(); 478 479 // Control flow should never reach here! 480 } 455 481 } 456 482 … … 486 512 //============================================================================================= 487 513 // Wake a thread from the front if there are any 488 static void __wake_one( struct __processor_id_t * id,cluster * this) {489 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 490 /* paranoid */ verify( ready_schedule_islocked( id) );514 static void __wake_one(cluster * this) { 515 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 516 /* paranoid */ verify( ready_schedule_islocked() ); 491 517 492 518 // Check if there is a sleeping processor … … 506 532 #endif 507 533 508 /* paranoid */ verify( ready_schedule_islocked( id) );534 /* paranoid */ verify( ready_schedule_islocked() ); 509 535 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 510 536 … … 709 735 this.print_halts = true; 710 736 } 737 738 void print_stats_now( cluster & this, int flags ) { 739 __print_stats( this.stats, this.print_stats, true, this.name, (void*)&this ); 740 } 711 741 #endif 712 742 // Local Variables: // -
libcfa/src/concurrency/kernel.hfa
r4b30e8cc rc28ea4e 79 79 // Handle to pthreads 80 80 pthread_t kernel_thread; 81 82 // RunThread data83 // Action to do after a thread is ran84 $thread * destroyer;85 81 86 82 // Preemption data -
libcfa/src/concurrency/kernel/fwd.hfa
r4b30e8cc rc28ea4e 35 35 extern "Cforall" { 36 36 extern __attribute__((aligned(128))) thread_local struct KernelThreadData { 37 struct $thread * volatile this_thread; 38 struct processor * volatile this_processor; 39 struct __stats_t * volatile this_stats; 37 struct $thread * volatile this_thread; 38 struct processor * volatile this_processor; 39 struct __processor_id_t * volatile this_proc_id; 40 struct __stats_t * volatile this_stats; 40 41 41 42 struct { -
libcfa/src/concurrency/kernel/startup.cfa
r4b30e8cc rc28ea4e 122 122 NULL, 123 123 NULL, 124 NULL, 124 125 { 1, false, false }, 125 126 }; … … 212 213 //initialize the global state variables 213 214 kernelTLS.this_processor = mainProcessor; 215 kernelTLS.this_proc_id = (__processor_id_t*)mainProcessor; 214 216 kernelTLS.this_thread = mainThread; 215 217 … … 227 229 // Add the main thread to the ready queue 228 230 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 229 __schedule_thread( (__processor_id_t *)mainProcessor,mainThread);231 __schedule_thread(mainThread); 230 232 231 233 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 324 326 processor * proc = (processor *) arg; 325 327 kernelTLS.this_processor = proc; 328 kernelTLS.this_proc_id = (__processor_id_t*)proc; 326 329 kernelTLS.this_thread = 0p; 327 330 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 441 444 442 445 static void ?{}( $thread & this, current_stack_info_t * info) with( this ) { 443 ticket = 1;446 ticket = TICKET_RUNNING; 444 447 state = Start; 445 448 self_cor{ info }; … … 474 477 this.cltr = &_cltr; 475 478 full_proc = true; 476 destroyer = 0p;477 479 do_terminate = false; 478 480 preemption_alarm = 0p; -
libcfa/src/concurrency/kernel_private.hfa
r4b30e8cc rc28ea4e 33 33 } 34 34 35 void __schedule_thread( struct __processor_id_t *,$thread * )35 void __schedule_thread( $thread * ) 36 36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__)) 37 __attribute__((nonnull ( 2)))37 __attribute__((nonnull (1))) 38 38 #endif 39 39 ; 40 40 41 // Block current thread andrelease/wake-up the following resources42 void __ leave_thread() __attribute__((noreturn));41 //release/wake-up the following resources 42 void __thread_finish( $thread * thrd ); 43 43 44 44 //----------------------------------------------------------------------------- … … 63 63 ) 64 64 65 // KERNEL ONLY unpark with out disabling interrupts 66 void __unpark( struct __processor_id_t *, $thread * thrd ); 67 68 static inline bool __post(single_sem & this, struct __processor_id_t * id) { 69 for() { 70 struct $thread * expected = this.ptr; 71 if(expected == 1p) return false; 72 if(expected == 0p) { 73 if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 74 return false; 75 } 76 } 77 else { 78 if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 79 __unpark( id, expected ); 80 return true; 81 } 82 } 83 } 84 } 65 #define TICKET_BLOCKED (-1) // thread is blocked 66 #define TICKET_RUNNING ( 0) // thread is running 67 #define TICKET_UNBLOCK ( 1) // thread should ignore next block 85 68 86 69 //----------------------------------------------------------------------------- … … 197 180 // Reader side : acquire when using the ready queue to schedule but not 198 181 // creating/destroying queues 199 static inline void ready_schedule_lock( struct __processor_id_t * proc) with(*__scheduler_lock) { 200 unsigned iproc = proc->id; 201 /*paranoid*/ verify(data[iproc].handle == proc); 182 static inline void ready_schedule_lock(void) with(*__scheduler_lock) { 183 /*paranoid*/ verify( kernelTLS.this_proc_id ); 184 185 unsigned iproc = kernelTLS.this_proc_id->id; 186 /*paranoid*/ verify(data[iproc].handle == kernelTLS.this_proc_id); 202 187 /*paranoid*/ verify(iproc < ready); 203 188 … … 221 206 } 222 207 223 static inline void ready_schedule_unlock( struct __processor_id_t * proc) with(*__scheduler_lock) { 224 unsigned iproc = proc->id; 225 /*paranoid*/ verify(data[iproc].handle == proc); 208 static inline void ready_schedule_unlock(void) with(*__scheduler_lock) { 209 /*paranoid*/ verify( kernelTLS.this_proc_id ); 210 211 unsigned iproc = kernelTLS.this_proc_id->id; 212 /*paranoid*/ verify(data[iproc].handle == kernelTLS.this_proc_id); 226 213 /*paranoid*/ verify(iproc < ready); 227 214 /*paranoid*/ verify(data[iproc].lock); … … 235 222 236 223 #ifdef __CFA_WITH_VERIFY__ 237 static inline bool ready_schedule_islocked( struct __processor_id_t * proc) { 224 static inline bool ready_schedule_islocked(void) { 225 /*paranoid*/ verify( kernelTLS.this_proc_id ); 226 __processor_id_t * proc = kernelTLS.this_proc_id; 238 227 return __scheduler_lock->data[proc->id].owned; 239 228 } -
libcfa/src/concurrency/monitor.cfa
r4b30e8cc rc28ea4e 281 281 } 282 282 283 extern "C" { 284 // Leave the thread monitor 285 // last routine called by a thread. 286 // Should never return 287 void __cfactx_thrd_leave() { 288 $thread * thrd = TL_GET( this_thread ); 289 $monitor * this = &thrd->self_mon; 290 291 // Lock the monitor now 292 lock( this->lock __cfaabi_dbg_ctx2 ); 293 294 disable_interrupts(); 295 296 thrd->state = Halted; 297 298 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 299 300 // Leaving a recursion level, decrement the counter 301 this->recursion -= 1; 302 303 // If we haven't left the last level of recursion 304 // it must mean there is an error 305 if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); } 306 307 // Fetch the next thread, can be null 308 $thread * new_owner = next_thread( this ); 309 310 // Release the monitor lock 311 unlock( this->lock ); 312 313 // Unpark the next owner if needed 314 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 315 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 316 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer ); 317 /* paranoid */ verify( thrd->state == Halted ); 318 319 kernelTLS.this_processor->destroyer = new_owner; 320 321 // Leave the thread 322 __leave_thread(); 323 324 // Control flow should never reach here! 325 } 326 } 327 328 // Join a thread 329 forall( dtype T | is_thread(T) ) 330 T & join( T & this ) { 331 $monitor * m = get_monitor(this); 332 void (*dtor)(T& mutex this) = ^?{}; 333 monitor_dtor_guard_t __guard = { &m, (fptr_t)dtor, true }; 334 { 335 return this; 336 } 283 void __thread_finish( $thread * thrd ) { 284 $monitor * this = &thrd->self_mon; 285 286 // Lock the monitor now 287 /* paranoid */ verify( this->lock.lock ); 288 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 289 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 290 /* paranoid */ verify( thrd->state == Halted ); 291 /* paranoid */ verify( this->recursion == 1 ); 292 293 // Leaving a recursion level, decrement the counter 294 this->recursion -= 1; 295 this->owner = 0p; 296 297 // Fetch the next thread, can be null 298 $thread * new_owner = next_thread( this ); 299 300 // Release the monitor lock 301 unlock( this->lock ); 302 303 // Unpark the next owner if needed 304 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 305 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 306 /* paranoid */ verify( thrd->state == Halted ); 307 unpark( new_owner ); 337 308 } 338 309 -
libcfa/src/concurrency/preemption.cfa
r4b30e8cc rc28ea4e 38 38 // FwdDeclarations : timeout handlers 39 39 static void preempt( processor * this ); 40 static void timeout( struct __processor_id_t * id,$thread * this );40 static void timeout( $thread * this ); 41 41 42 42 // FwdDeclarations : Signal handlers … … 91 91 92 92 // Tick one frame of the Discrete Event Simulation for alarms 93 static void tick_preemption( struct __processor_id_t * id) {93 static void tick_preemption(void) { 94 94 alarm_node_t * node = 0p; // Used in the while loop but cannot be declared in the while condition 95 95 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 109 109 } 110 110 else if( node->type == User ) { 111 timeout( id,node->thrd );111 timeout( node->thrd ); 112 112 } 113 113 else { 114 114 bool unpark_thd = node->callback(*node); 115 if (unpark_thd) timeout( id,node->thrd );115 if (unpark_thd) timeout( node->thrd ); 116 116 } 117 117 … … 274 274 275 275 // reserved for future use 276 static void timeout( struct __processor_id_t * id,$thread * this ) {276 static void timeout( $thread * this ) { 277 277 #if !defined( __CFA_NO_STATISTICS__ ) 278 278 kernelTLS.this_stats = this->curr_cluster->stats; 279 279 #endif 280 __unpark( id,this );280 unpark( this ); 281 281 } 282 282 … … 417 417 id.full_proc = false; 418 418 id.id = doregister(&id); 419 kernelTLS.this_proc_id = &id; 419 420 420 421 // Block sigalrms to control when they arrive … … 462 463 // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" ); 463 464 lock( event_kernel->lock __cfaabi_dbg_ctx2 ); 464 tick_preemption( &id);465 tick_preemption(); 465 466 unlock( event_kernel->lock ); 466 467 break; -
libcfa/src/concurrency/snzi.hfa
r4b30e8cc rc28ea4e 36 36 static inline void depart( __snzi_node_t & ); 37 37 38 #define __snzi_half -1 38 static const int __snzi_half = -1; 39 39 40 40 //-------------------------------------------------- -
libcfa/src/concurrency/thread.cfa
r4b30e8cc rc28ea4e 19 19 20 20 #include "kernel_private.hfa" 21 #include "exception.hfa" 21 22 22 23 #define __CFA_INVOKE_PRIVATE__ … … 28 29 context{ 0p, 0p }; 29 30 self_cor{ name, storage, storageSize }; 30 ticket = 1;31 ticket = TICKET_RUNNING; 31 32 state = Start; 32 33 preempted = __NO_PREEMPTION; … … 58 59 } 59 60 61 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t)) 62 63 forall(dtype T) 64 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) { 65 dst->virtual_table = src->virtual_table; 66 dst->the_thread = src->the_thread; 67 dst->the_exception = src->the_exception; 68 } 69 70 forall(dtype T) 71 const char * msg(ThreadCancelled(T) *) { 72 return "ThreadCancelled"; 73 } 74 75 forall(dtype T) 76 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 77 abort( "Unhandled thread cancellation.\n" ); 78 } 79 80 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 81 void ?{}( thread_dtor_guard_t & this, 82 T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) { 83 $monitor * m = get_monitor(thrd); 84 void (*dtor)(T& mutex this) = ^?{}; 85 bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0; 86 (this.mg){&m, (void(*)())dtor, join}; 87 88 // After the guard set-up and any wait, check for cancellation. 89 $thread * desc = get_thread(thrd); 90 struct _Unwind_Exception * cancellation = desc->self_cor.cancellation; 91 if ( likely( 0p == cancellation ) ) { 92 return; 93 } else if ( Cancelled == desc->state ) { 94 return; 95 } 96 desc->state = Cancelled; 97 if (!join) { 98 defaultResumptionHandler = default_thread_cancel_handler; 99 } 100 101 ThreadCancelled(T) except; 102 // TODO: Remove explitate vtable set once trac#186 is fixed. 103 except.virtual_table = &get_exception_vtable(&except); 104 except.the_thread = &thrd; 105 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 106 throwResume except; 107 108 except.the_exception->virtual_table->free( except.the_exception ); 109 free( cancellation ); 110 desc->self_cor.cancellation = 0p; 111 } 112 113 void ^?{}( thread_dtor_guard_t & this ) { 114 ^(this.mg){}; 115 } 116 60 117 //----------------------------------------------------------------------------- 61 118 // Starting and stopping threads … … 70 127 verify( this_thrd->context.SP ); 71 128 72 __schedule_thread( (__processor_id_t *)kernelTLS.this_processor, this_thrd);129 __schedule_thread( this_thrd ); 73 130 enable_interrupts( __cfaabi_dbg_ctx ); 74 131 } … … 93 150 } 94 151 152 //----------------------------------------------------------------------------- 153 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))) 154 T & join( T & this ) { 155 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; 156 return this; 157 } 158 95 159 // Local Variables: // 96 160 // mode: c // -
libcfa/src/concurrency/thread.hfa
r4b30e8cc rc28ea4e 22 22 #include "kernel.hfa" 23 23 #include "monitor.hfa" 24 #include "exception.hfa" 24 25 25 26 //----------------------------------------------------------------------------- 26 27 // thread trait 27 28 trait is_thread(dtype T) { 28 29 30 29 void ^?{}(T& mutex this); 30 void main(T& this); 31 $thread* get_thread(T& this); 31 32 }; 33 34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) ( 35 thread_t * the_thread; 36 exception_t * the_exception; 37 ); 38 39 forall(dtype T) 40 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src); 41 42 forall(dtype T) 43 const char * msg(ThreadCancelled(T) *); 32 44 33 45 // define that satisfies the trait without using the thread keyword … … 65 77 static inline void ?{}($thread & this, const char * const name, struct cluster & cl ) { this{ name, cl, 0p, 65000 }; } 66 78 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; } 79 80 struct thread_dtor_guard_t { 81 monitor_dtor_guard_t mg; 82 }; 83 84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) ) 85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) ); 86 void ^?{}( thread_dtor_guard_t & this ); 67 87 68 88 //----------------------------------------------------------------------------- … … 108 128 //---------- 109 129 // join 110 forall( dtype T | is_thread(T) )130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) ) 111 131 T & join( T & this ); 112 132 -
libcfa/src/exception.c
r4b30e8cc rc28ea4e 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Aug 29 15:52:22202013 // Update Count : 3 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 16:27:00 2020 13 // Update Count : 35 14 14 // 15 15 … … 17 17 #include <stddef.h> // for size_t 18 18 19 #include <unwind.h> // for struct _Unwind_Exception {...}; 20 19 21 #include "exception.h" 20 22 21 23 #include <stdlib.h> 22 24 #include <stdio.h> 23 #include <unwind.h>24 25 #include <bits/debug.hfa> 25 26 #include "concurrency/invoke.h" … … 113 114 114 115 // MEMORY MANAGEMENT ========================================================= 115 116 struct __cfaehm_node {117 struct _Unwind_Exception unwind_exception;118 struct __cfaehm_node * next;119 int handler_index;120 };121 116 122 117 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node))) -
libcfa/src/exception.h
r4b30e8cc rc28ea4e 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // exception.h -- Builtins for exception handling.7 // exception.h -- Internal exception handling definitions. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 19 14:17:00 202013 // Update Count : 1 012 // Last Modified On : Tue Oct 27 14:45:00 2020 13 // Update Count : 11 14 14 // 15 15 16 16 #pragma once 17 17 18 // This could be considered several headers. All are internal to the exception 19 // system but needed to depending on whether they are C/Cforall code and 20 // whether or not they are part of the builtins. 18 21 19 22 #ifdef __cforall 20 23 extern "C" { 21 24 #endif 25 26 // Included in C code or the built-ins. 27 #if !defined(__cforall) || defined(__cforall_builtins__) 22 28 23 29 struct __cfaehm_base_exception_t; … … 47 53 // Function catches termination exceptions. 48 54 void __cfaehm_try_terminate( 49 50 51 55 void (*try_block)(), 56 void (*catch_block)(int index, exception_t * except), 57 int (*match_block)(exception_t * except)); 52 58 53 59 // Clean-up the exception in catch blocks. … … 56 62 // Data structure creates a list of resume handlers. 57 63 struct __cfaehm_try_resume_node { 58 59 64 struct __cfaehm_try_resume_node * next; 65 _Bool (*handler)(exception_t * except); 60 66 }; 61 67 62 68 // These act as constructor and destructor for the resume node. 63 69 void __cfaehm_try_resume_setup( 64 65 70 struct __cfaehm_try_resume_node * node, 71 _Bool (*handler)(exception_t * except)); 66 72 void __cfaehm_try_resume_cleanup( 67 73 struct __cfaehm_try_resume_node * node); 68 74 69 75 // Check for a standard way to call fake deconstructors. 70 76 struct __cfaehm_cleanup_hook {}; 71 77 78 #endif 79 80 // Included in C code and the library. 81 #if !defined(__cforall) || !defined(__cforall_builtins__) 82 struct __cfaehm_node { 83 struct _Unwind_Exception unwind_exception; 84 struct __cfaehm_node * next; 85 int handler_index; 86 }; 87 88 static inline exception_t * __cfaehm_cancellation_exception( 89 struct _Unwind_Exception * unwind_exception ) { 90 return (exception_t *)(1 + (struct __cfaehm_node *)unwind_exception); 91 } 92 #endif 93 72 94 #ifdef __cforall 73 95 } 96 97 // Built-ins not visible in C. 98 #if defined(__cforall_builtins__) 74 99 75 100 // Not all the built-ins can be expressed in C. These can't be … … 124 149 125 150 #endif 151 152 #endif -
libcfa/src/stdlib.cfa
r4b30e8cc rc28ea4e 58 58 59 59 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) 60 void adelete( size_t dim,T arr[] ) {60 void adelete( T arr[] ) { 61 61 if ( arr ) { // ignore null 62 size_t dim = malloc_size( arr ) / sizeof( T ); 62 63 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 63 64 ^(arr[i]){}; // run destructor … … 68 69 69 70 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) 70 void adelete( size_t dim,T arr[], Params rest ) {71 void adelete( T arr[], Params rest ) { 71 72 if ( arr ) { // ignore null 73 size_t dim = malloc_size( arr ) / sizeof( T ); 72 74 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 73 75 ^(arr[i]){}; // run destructor -
libcfa/src/stdlib.hfa
r4b30e8cc rc28ea4e 263 263 // Cforall allocation/deallocation and constructor/destructor, array types 264 264 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p ); 265 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim,T arr[] );266 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim,T arr[], Params rest );265 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] ); 266 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( T arr[], Params rest ); 267 267 268 268 //--------------------------------------- -
src/AST/Convert.cpp
r4b30e8cc rc28ea4e 25 25 #include "AST/Init.hpp" 26 26 #include "AST/Stmt.hpp" 27 #include "AST/TranslationUnit.hpp" 27 28 #include "AST/TypeSubstitution.hpp" 28 29 … … 47 48 48 49 //================================================================================================ 49 namespace {50 namespace ast { 50 51 51 52 // This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not) 52 53 // allow us to use the same stratagy in the new ast. 54 // xxx - since convert back pass works, this concern seems to be unnecessary. 55 56 // these need to be accessed in new FixInit now 53 57 ast::Type * sizeType = nullptr; 54 58 ast::FunctionDecl * dereferenceOperator = nullptr; … … 63 67 using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >; 64 68 Cache cache; 69 70 // Statements can no longer be shared. 71 // however, since StmtExprResult is now implemented, need to still maintain 72 // readonly references. 73 Cache readonlyCache; 65 74 66 75 template<typename T> … … 154 163 } 155 164 156 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 157 auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth ); 158 auto&& type = get<Type>().accept1( node->type ); 159 auto&& init = get<Initializer>().accept1( node->init ); 160 auto&& attr = get<Attribute>().acceptL( node->attributes ); 165 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 161 166 if ( inCache( node ) ) { 162 167 return nullptr; 163 168 } 169 auto bfwd = get<Expression>().accept1( node->bitfieldWidth ); 170 auto type = get<Type>().accept1( node->type ); 171 auto attr = get<Attribute>().acceptL( node->attributes ); 172 164 173 auto decl = new ObjectDecl( 165 174 node->name, … … 168 177 bfwd, 169 178 type->clone(), 170 init,179 nullptr, // prevent infinite loop 171 180 attr, 172 181 Type::FuncSpecifiers( node->funcSpec.val ) 173 182 ); 174 return declWithTypePostamble( decl, node ); 183 184 // handles the case where node->init references itself 185 // xxx - does it really happen? 186 declWithTypePostamble(decl, node); 187 auto init = get<Initializer>().accept1( node->init ); 188 decl->init = init; 189 190 this->node = decl; 191 return nullptr; 175 192 } 176 193 … … 205 222 decl->statements = get<CompoundStmt>().accept1( node->stmts ); 206 223 decl->withExprs = get<Expression>().acceptL( node->withExprs ); 207 if ( dereferenceOperator == node ) {224 if ( ast::dereferenceOperator == node ) { 208 225 Validate::dereferenceOperator = decl; 209 226 } 210 if ( dtorStructDestroy == node ) {227 if ( ast::dtorStructDestroy == node ) { 211 228 Validate::dtorStructDestroy = decl; 212 229 } … … 267 284 ); 268 285 269 if ( dtorStruct == node ) {286 if ( ast::dtorStruct == node ) { 270 287 Validate::dtorStruct = decl; 271 288 } … … 320 337 321 338 const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) { 322 cache.emplace( node, stmt ); 339 // force statements in old tree to be unique. 340 // cache.emplace( node, stmt ); 341 readonlyCache.emplace( node, stmt ); 323 342 stmt->location = node->location; 324 343 stmt->labels = makeLabelL( stmt, node->labels ); … … 337 356 if ( inCache( node ) ) return nullptr; 338 357 auto stmt = new ExprStmt( nullptr ); 339 cache.emplace( node, stmt );340 358 stmt->expr = get<Expression>().accept1( node->expr ); 341 359 return stmtPostamble( stmt, node ); … … 1011 1029 auto stmts = node->stmts; 1012 1030 // disable sharing between multiple StmtExprs explicitly. 1013 if (inCache(stmts)) { 1014 stmts = ast::deepCopy(stmts.get()); 1015 } 1031 // this should no longer be true. 1032 1016 1033 auto rslt = new StmtExpr( 1017 1034 get<CompoundStmt>().accept1(stmts) … … 1020 1037 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls); 1021 1038 rslt->dtors = get<Expression>().acceptL(node->dtors); 1039 if (node->resultExpr) { 1040 // this MUST be found by children visit 1041 rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr)); 1042 } 1022 1043 1023 1044 auto expr = visitBaseExpr( node, rslt ); … … 1036 1057 1037 1058 auto expr = visitBaseExpr( node, rslt ); 1038 this->node = expr ;1059 this->node = expr->clone(); 1039 1060 return nullptr; 1040 1061 } … … 1126 1147 auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind }; 1127 1148 // I believe this should always be a BasicType. 1128 if ( sizeType == node ) {1149 if ( ast::sizeType == node ) { 1129 1150 Validate::SizeType = type; 1130 1151 } … … 1384 1405 }; 1385 1406 1386 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > >&& translationUnit ) {1407 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) { 1387 1408 ConverterNewToOld c; 1388 1409 std::list< Declaration * > decls; 1389 for(auto d : translationUnit ) {1410 for(auto d : translationUnit.decls) { 1390 1411 decls.emplace_back( c.decl( d ) ); 1391 1412 } … … 1529 1550 1530 1551 // function type is now derived from parameter decls instead of storing them 1552 1553 /* 1531 1554 auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type)); 1532 1555 ftype->params.reserve(paramVars.size()); … … 1540 1563 } 1541 1564 ftype->forall = std::move(forall); 1542 visitType(old->type, ftype); 1565 */ 1566 1567 // can function type have attributes? seems not to be the case. 1568 // visitType(old->type, ftype); 1543 1569 1544 1570 auto decl = new ast::FunctionDecl{ … … 1546 1572 old->name, 1547 1573 // GET_ACCEPT_1(type, FunctionType), 1574 std::move(forall), 1548 1575 std::move(paramVars), 1549 1576 std::move(returnVars), … … 1552 1579 { old->linkage.val }, 1553 1580 GET_ACCEPT_V(attributes, Attribute), 1554 { old->get_funcSpec().val } 1581 { old->get_funcSpec().val }, 1582 old->type->isVarArgs 1555 1583 }; 1556 1584 1557 decl->type = ftype;1585 // decl->type = ftype; 1558 1586 cache.emplace( old, decl ); 1559 1587 … … 1570 1598 1571 1599 if ( Validate::dereferenceOperator == old ) { 1572 dereferenceOperator = decl;1600 ast::dereferenceOperator = decl; 1573 1601 } 1574 1602 1575 1603 if ( Validate::dtorStructDestroy == old ) { 1576 dtorStructDestroy = decl;1604 ast::dtorStructDestroy = decl; 1577 1605 } 1578 1606 } … … 1599 1627 1600 1628 if ( Validate::dtorStruct == old ) { 1601 dtorStruct = decl;1629 ast::dtorStruct = decl; 1602 1630 } 1603 1631 } … … 2531 2559 // I believe this should always be a BasicType. 2532 2560 if ( Validate::SizeType == old ) { 2533 sizeType = type;2561 ast::sizeType = type; 2534 2562 } 2535 2563 visitType( old, type ); … … 2776 2804 #undef GET_ACCEPT_1 2777 2805 2778 std::list< ast::ptr< ast::Decl > >convert( const std::list< Declaration * > && translationUnit ) {2806 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) { 2779 2807 ConverterOldToNew c; 2780 std::list< ast::ptr< ast::Decl > > decls;2808 ast::TranslationUnit unit; 2781 2809 for(auto d : translationUnit) { 2782 2810 d->accept( c ); 2783 decls.emplace_back( c.decl() );2811 unit.decls.emplace_back( c.decl() ); 2784 2812 } 2785 2813 deleteAll(translationUnit); 2786 return decls;2814 return unit; 2787 2815 } -
src/AST/Convert.hpp
r4b30e8cc rc28ea4e 18 18 #include <list> 19 19 20 #include "AST/Node.hpp"21 22 20 class Declaration; 23 21 namespace ast { 24 class Decl;22 class TranslationUnit; 25 23 }; 26 24 27 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > >&& translationUnit );28 std::list< ast::ptr< ast::Decl > >convert( const std::list< Declaration * > && translationUnit );25 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ); 26 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ); -
src/AST/Decl.cpp
r4b30e8cc rc28ea4e 48 48 49 49 // --- FunctionDecl 50 51 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 52 std::vector<ptr<TypeDecl>>&& forall, 53 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 54 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 55 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs) 56 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 57 stmts( stmts ) { 58 FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs)); 59 for (auto & param : this->params) { 60 ftype->params.emplace_back(param->get_type()); 61 } 62 for (auto & ret : this->returns) { 63 ftype->returns.emplace_back(ret->get_type()); 64 } 65 ftype->forall = std::move(forall); 66 this->type = ftype; 67 } 68 50 69 51 70 const Type * FunctionDecl::get_type() const { return type.get(); } -
src/AST/Decl.hpp
r4b30e8cc rc28ea4e 131 131 std::vector< ptr<Expr> > withExprs; 132 132 133 FunctionDecl( const CodeLocation & loc, const std::string & name, 133 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall, 134 134 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 135 135 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 136 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {} )137 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),138 stmts( stmts ) {}136 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false); 137 // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 138 // stmts( stmts ) {} 139 139 140 140 const Type * get_type() const override; -
src/AST/DeclReplacer.cpp
r4b30e8cc rc28ea4e 38 38 const ast::TypeInstType * previsit( const ast::TypeInstType * ); 39 39 }; 40 41 struct VarExprReplacer { 42 private: 43 const ExprMap & exprMap; 44 45 public: 46 VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {} 47 48 const Expr * postvisit (const VariableExpr *); 49 }; 40 50 } 41 51 … … 54 64 DeclMap declMap; 55 65 return replace( node, declMap, typeMap, debug ); 66 } 67 68 const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) { 69 Pass<VarExprReplacer> replacer = {exprMap}; 70 return node->accept( replacer ); 56 71 } 57 72 … … 88 103 return ninst; 89 104 } 105 106 const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) { 107 if (!exprMap.count(expr->var)) return expr; 108 109 return exprMap.at(expr->var); 110 } 111 90 112 } 91 113 } -
src/AST/DeclReplacer.hpp
r4b30e8cc rc28ea4e 23 23 class DeclWithType; 24 24 class TypeDecl; 25 class Expr; 25 26 26 27 namespace DeclReplacer { 27 28 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 28 29 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 29 31 30 32 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 31 33 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 32 34 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 35 const Node * replace( const Node * node, const ExprMap & exprMap); 33 36 } 34 37 } -
src/AST/Expr.cpp
r4b30e8cc rc28ea4e 67 67 // --- UntypedExpr 68 68 69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) { 70 70 assert( arg ); 71 71 … … 92 92 } 93 93 94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs,Expr * rhs ) {94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) { 95 95 assert( lhs && rhs ); 96 96 … … 102 102 } 103 103 return ret; 104 } 105 106 // --- VariableExpr 107 108 VariableExpr::VariableExpr( const CodeLocation & loc ) 109 : Expr( loc ), var( nullptr ) {} 110 111 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v ) 112 : Expr( loc ), var( v ) { 113 assert( var ); 114 assert( var->get_type() ); 115 result = shallowCopy( var->get_type() ); 116 } 117 118 bool VariableExpr::get_lvalue() const { 119 // It isn't always an lvalue, but it is never an rvalue. 120 return true; 121 } 122 123 VariableExpr * VariableExpr::functionPointer( 124 const CodeLocation & loc, const FunctionDecl * decl ) { 125 // wrap usually-determined result type in a pointer 126 VariableExpr * funcExpr = new VariableExpr{ loc, decl }; 127 funcExpr->result = new PointerType{ funcExpr->result }; 128 return funcExpr; 104 129 } 105 130 … … 238 263 } 239 264 240 // --- VariableExpr241 242 VariableExpr::VariableExpr( const CodeLocation & loc )243 : Expr( loc ), var( nullptr ) {}244 245 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )246 : Expr( loc ), var( v ) {247 assert( var );248 assert( var->get_type() );249 result = shallowCopy( var->get_type() );250 }251 252 bool VariableExpr::get_lvalue() const {253 // It isn't always an lvalue, but it is never an rvalue.254 return true;255 }256 257 VariableExpr * VariableExpr::functionPointer(258 const CodeLocation & loc, const FunctionDecl * decl ) {259 // wrap usually-determined result type in a pointer260 VariableExpr * funcExpr = new VariableExpr{ loc, decl };261 funcExpr->result = new PointerType{ funcExpr->result };262 return funcExpr;263 }264 265 265 // --- ConstantExpr 266 266 -
src/AST/Expr.hpp
r4b30e8cc rc28ea4e 226 226 227 227 /// Creates a new dereference expression 228 static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );228 static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg ); 229 229 /// Creates a new assignment expression 230 static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs,Expr * rhs );230 static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ); 231 231 232 232 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 247 247 private: 248 248 NameExpr * clone() const override { return new NameExpr{ *this }; } 249 MUTATE_FRIEND 250 }; 251 252 /// A reference to a named variable. 253 class VariableExpr final : public Expr { 254 public: 255 readonly<DeclWithType> var; 256 257 VariableExpr( const CodeLocation & loc ); 258 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 259 260 bool get_lvalue() const final; 261 262 /// generates a function pointer for a given function 263 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 264 265 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 266 private: 267 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 249 268 MUTATE_FRIEND 250 269 }; … … 392 411 }; 393 412 394 /// A reference to a named variable.395 class VariableExpr final : public Expr {396 public:397 readonly<DeclWithType> var;398 399 VariableExpr( const CodeLocation & loc );400 VariableExpr( const CodeLocation & loc, const DeclWithType * v );401 402 bool get_lvalue() const final;403 404 /// generates a function pointer for a given function405 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );406 407 const Expr * accept( Visitor & v ) const override { return v.visit( this ); }408 private:409 VariableExpr * clone() const override { return new VariableExpr{ *this }; }410 MUTATE_FRIEND411 };412 413 413 /// A compile-time constant. 414 414 /// Mostly carries C-source text from parse to code-gen, without interpretation. E.g. strings keep their outer quotes and never have backslashes interpreted. … … 422 422 const CodeLocation & loc, const Type * ty, const std::string & r, 423 423 std::optional<unsigned long long> i ) 424 : Expr( loc, ty ), rep( r ), ival( i ) {}424 : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {} 425 425 426 426 /// Gets the integer value of this constant, if one is appropriate to its type. … … 617 617 618 618 ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call ) 619 : Expr( loc, call->result ) { assert( call); }619 : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); } 620 620 621 621 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 742 742 std::vector<ptr<Expr>> dtors; ///< destructor(s) for return variable(s) 743 743 744 readonly<ExprStmt> resultExpr; 745 744 746 StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ); 745 747 -
src/AST/Fwd.hpp
r4b30e8cc rc28ea4e 137 137 typedef unsigned int UniqueId; 138 138 139 class TranslationUnit; 140 // TODO: Get from the TranslationUnit: 141 extern Type * sizeType; 142 extern FunctionDecl * dereferenceOperator; 143 extern StructDecl * dtorStruct; 144 extern FunctionDecl * dtorStructDestroy; 145 139 146 } -
src/AST/Node.hpp
r4b30e8cc rc28ea4e 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const {return strong_count > 0; } 51 52 52 53 private: -
src/AST/Pass.hpp
r4b30e8cc rc28ea4e 103 103 /// Construct and run a pass on a translation unit. 104 104 template< typename... Args > 105 static void run( std::list< ptr<Decl> >& decls, Args &&... args ) {105 static void run( TranslationUnit & decls, Args &&... args ) { 106 106 Pass<core_t> visitor( std::forward<Args>( args )... ); 107 107 accept_all( decls, visitor ); … … 119 119 // Versions of the above for older compilers. 120 120 template< typename... Args > 121 static void run( std::list< ptr<Decl> >& decls ) {121 static void run( TranslationUnit & decls ) { 122 122 Pass<core_t> visitor; 123 123 accept_all( decls, visitor ); … … 228 228 template<typename core_type> 229 229 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor ); 230 231 bool isInFunction() const { 232 return inFunction; 233 } 234 230 235 private: 231 236 … … 235 240 const ast::Stmt * call_accept( const ast::Stmt * ); 236 241 const ast::Expr * call_accept( const ast::Expr * ); 242 243 // requests WithStmtsToAdd directly add to this statement, as if it is a compound. 244 245 const ast::Stmt * call_accept_as_compound(const ast::Stmt *); 237 246 238 247 template< typename node_t > … … 257 266 template<typename node_t, typename parent_t, typename child_t> 258 267 void maybe_accept(const node_t * &, child_t parent_t::* child); 268 269 template<typename node_t, typename parent_t, typename child_t> 270 void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child); 259 271 260 272 private: … … 284 296 private: 285 297 bool inFunction = false; 298 bool atFunctionTop = false; 286 299 }; 287 300 … … 289 302 template<typename core_t> 290 303 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor ); 304 305 template<typename core_t> 306 void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor ); 291 307 292 308 //------------------------------------------------------------------------------------------------- … … 371 387 struct WithVisitorRef { 372 388 Pass<core_t> * const visitor = nullptr; 389 390 bool isInFunction() const { 391 return visitor->isInFunction(); 392 } 373 393 }; 374 394 -
src/AST/Pass.impl.hpp
r4b30e8cc rc28ea4e 20 20 #include <unordered_map> 21 21 22 #include "AST/TranslationUnit.hpp" 22 23 #include "AST/TypeSubstitution.hpp" 23 24 … … 167 168 __pedantic_pass_assert( stmt ); 168 169 170 return stmt->accept( *this ); 171 } 172 173 template< typename core_t > 174 const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 175 __pedantic_pass_assert( __visit_children() ); 176 __pedantic_pass_assert( stmt ); 177 169 178 // add a few useful symbols to the scope 170 179 using __pass::empty; … … 334 343 } 335 344 345 template< typename core_t > 346 template<typename node_t, typename parent_t, typename child_t> 347 void ast::Pass< core_t >::maybe_accept_as_compound( 348 const node_t * & parent, 349 child_t parent_t::*child 350 ) { 351 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" ); 352 353 if(__pass::skip(parent->*child)) return; 354 const auto & old_val = __pass::get(parent->*child, 0); 355 356 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 357 358 auto new_val = call_accept_as_compound( old_val ); 359 360 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); 361 362 if( __pass::differs(old_val, new_val) ) { 363 auto new_parent = __pass::mutate<core_t>(parent); 364 new_parent->*child = new_val; 365 parent = new_parent; 366 } 367 } 368 336 369 337 370 template< typename core_t > … … 398 431 pass_visitor_stats.depth--; 399 432 if ( !errors.isEmpty() ) { throw errors; } 433 } 434 435 template< typename core_t > 436 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 437 return ast::accept_all( unit.decls, visitor ); 400 438 } 401 439 … … 470 508 // foralls are still in function type 471 509 maybe_accept( node, &FunctionDecl::type ); 472 // function body needs to have the same scope as parameters - CompoundStmt will not enter 473 // a new scope if inFunction is true 510 // First remember that we are now within a function. 474 511 ValueGuard< bool > oldInFunction( inFunction ); 475 512 inFunction = true; 513 // The function body needs to have the same scope as parameters. 514 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 515 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 516 atFunctionTop = true; 476 517 maybe_accept( node, &FunctionDecl::stmts ); 477 518 maybe_accept( node, &FunctionDecl::attributes ); … … 639 680 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) { 640 681 VISIT_START( node ); 641 VISIT( {642 // do not enter a new scope if inFunction is true - needs to check old state before the assignment643 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {644 if ( ! inFunctionCpy) __pass::symtab::enter(core, 0);645 }, [this, inFunctionCpy = this->inFunction]() {646 if ( ! inFunctionCpy) __pass::symtab::leave(core, 0);682 VISIT( 683 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result. 684 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() { 685 if ( enterScope ) __pass::symtab::enter(core, 0); 686 }, [this, leaveScope = !this->atFunctionTop]() { 687 if ( leaveScope ) __pass::symtab::leave(core, 0); 647 688 }); 648 ValueGuard< bool > guard2( inFunction ); 689 ValueGuard< bool > guard2( atFunctionTop ); 690 atFunctionTop = false; 649 691 guard_scope guard3 { *this }; 650 inFunction = false;651 692 maybe_accept( node, &CompoundStmt::kids ); 652 })693 ) 653 694 VISIT_END( CompoundStmt, node ); 654 695 } … … 703 744 maybe_accept( node, &IfStmt::inits ); 704 745 maybe_accept( node, &IfStmt::cond ); 705 maybe_accept ( node, &IfStmt::thenPart );706 maybe_accept ( node, &IfStmt::elsePart );746 maybe_accept_as_compound( node, &IfStmt::thenPart ); 747 maybe_accept_as_compound( node, &IfStmt::elsePart ); 707 748 }) 708 749 … … 721 762 maybe_accept( node, &WhileStmt::inits ); 722 763 maybe_accept( node, &WhileStmt::cond ); 723 maybe_accept ( node, &WhileStmt::body );764 maybe_accept_as_compound( node, &WhileStmt::body ); 724 765 }) 725 766 … … 736 777 // for statements introduce a level of scope (for the initialization) 737 778 guard_symtab guard { *this }; 779 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later. 738 780 maybe_accept( node, &ForStmt::inits ); 739 781 maybe_accept( node, &ForStmt::cond ); 740 782 maybe_accept( node, &ForStmt::inc ); 741 maybe_accept ( node, &ForStmt::body );783 maybe_accept_as_compound( node, &ForStmt::body ); 742 784 }) 743 785 … … 834 876 maybe_accept( node, &CatchStmt::decl ); 835 877 maybe_accept( node, &CatchStmt::cond ); 836 maybe_accept ( node, &CatchStmt::body );878 maybe_accept_as_compound( node, &CatchStmt::body ); 837 879 }) 838 880 -
src/AST/Pass.proto.hpp
r4b30e8cc rc28ea4e 22 22 template<typename core_t> 23 23 class Pass; 24 25 class TranslationUnit; 24 26 25 27 struct PureVisitor; -
src/AST/SymbolTable.cpp
r4b30e8cc rc28ea4e 335 335 } 336 336 337 /* 338 void SymbolTable::addFunction Type( const FunctionType * ftype) {339 addTypes( f type->forall );340 addIds( f type->returns );341 addIds( f type->params );342 } 343 */ 337 338 void SymbolTable::addFunction( const FunctionDecl * func ) { 339 addTypes( func->type->forall ); 340 addIds( func->returns ); 341 addIds( func->params ); 342 } 343 344 344 345 345 void SymbolTable::lazyInitScope() { -
src/AST/SymbolTable.hpp
r4b30e8cc rc28ea4e 145 145 146 146 /// convenience function for adding all of the declarations in a function type to the indexer 147 // void addFunctionType( const FunctionType * ftype);147 void addFunction( const FunctionDecl * ); 148 148 149 149 private: -
src/AST/Type.cpp
r4b30e8cc rc28ea4e 157 157 158 158 template<typename decl_t> 159 SueInstType<decl_t>::SueInstType( 160 const base_type * b, std::vector<ptr<Expr>> && params, 161 CV::Qualifiers q, std::vector<ptr<Attribute>> && as ) 162 : BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {} 163 164 template<typename decl_t> 159 165 bool SueInstType<decl_t>::isComplete() const { 160 166 return base ? base->body : false; -
src/AST/Type.hpp
r4b30e8cc rc28ea4e 302 302 class FunctionType final : public ParameterizedType { 303 303 public: 304 // std::vector<ptr<DeclWithType>> returns;305 // std::vector<ptr<DeclWithType>> params;306 307 304 std::vector<ptr<Type>> returns; 308 305 std::vector<ptr<Type>> params; … … 345 342 : ParameterizedType(q, std::move(as)), params(), name(n) {} 346 343 344 BaseInstType( 345 const std::string& n, std::vector<ptr<Expr>> && params, 346 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 347 : ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {} 348 347 349 BaseInstType( const BaseInstType & o ); 348 350 … … 369 371 370 372 SueInstType( 371 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 373 const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 374 375 SueInstType( 376 const base_type * b, std::vector<ptr<Expr>> && params, 377 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 372 378 373 379 bool isComplete() const override; -
src/AST/porting.md
r4b30e8cc rc28ea4e 30 30 * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0` 31 31 * `PassVisitor` is replaced with `ast::Pass` 32 * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`. 33 34 `WithConstTypeSubstitution` 35 * `env` => `typeSubs` 32 36 33 37 ## Structural Changes ## … … 146 150 * allows `newObject` as just default settings 147 151 152 `FunctionDecl` 153 * `params` and `returns` added. 154 * Contain the declarations of the parameters and return variables. 155 * Types should match (even be shared with) the fields of `type`. 156 148 157 `NamedTypeDecl` 149 158 * `parameters` => `params` … … 154 163 `AggregateDecl` 155 164 * `parameters` => `params` 165 166 `StructDecl` 167 * `makeInst` replaced by better constructor on `StructInstType`. 156 168 157 169 `Expr` … … 245 257 * **TODO** move `kind`, `typeNames` into code generator 246 258 247 `ReferenceToType` 259 `ReferenceToType` => `BaseInstType` 248 260 * deleted `get_baseParameters()` from children 249 261 * replace with `aggr() ? aggr()->params : nullptr` … … 261 273 * `returnVals` => `returns` 262 274 * `parameters` => `params` 275 * Both now just point at types. 263 276 * `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;` 277 278 `SueInstType` 279 * Template class, with specializations and using to implement some other types: 280 * `StructInstType`, `UnionInstType` & `EnumInstType` 264 281 265 282 `TypeInstType` -
src/Common/PassVisitor.h
r4b30e8cc rc28ea4e 354 354 virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final; 355 355 356 bool isInFunction() const { 357 return inFunction; 358 } 359 356 360 private: 357 361 bool inFunction = false; 362 bool atFunctionTop = false; 358 363 359 364 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 526 531 public: 527 532 PassVisitor<pass_type> * const visitor = nullptr; 533 534 bool isInFunction() const { 535 return visitor->isInFunction(); 536 } 528 537 }; 529 538 -
src/Common/PassVisitor.impl.h
r4b30e8cc rc28ea4e 532 532 indexerAddId( &func ); 533 533 maybeAccept_impl( node->type, *this ); 534 // function body needs to have the same scope as parameters - CompoundStmt will not enter 535 // a new scope if inFunction is true 534 // First remember that we are now within a function. 536 535 ValueGuard< bool > oldInFunction( inFunction ); 537 536 inFunction = true; 537 // The function body needs to have the same scope as parameters. 538 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 539 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 540 atFunctionTop = true; 538 541 maybeAccept_impl( node->statements, *this ); 539 542 maybeAccept_impl( node->attributes, *this ); … … 567 570 indexerAddId( &func ); 568 571 maybeAccept_impl( node->type, *this ); 569 // function body needs to have the same scope as parameters - CompoundStmt will not enter 570 // a new scope if inFunction is true 572 // First remember that we are now within a function. 571 573 ValueGuard< bool > oldInFunction( inFunction ); 572 574 inFunction = true; 575 // The function body needs to have the same scope as parameters. 576 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 577 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 578 atFunctionTop = true; 573 579 maybeAccept_impl( node->statements, *this ); 574 580 maybeAccept_impl( node->attributes, *this ); … … 601 607 indexerAddId( &func ); 602 608 maybeMutate_impl( node->type, *this ); 603 // function body needs to have the same scope as parameters - CompoundStmt will not enter 604 // a new scope if inFunction is true 609 // First remember that we are now within a function. 605 610 ValueGuard< bool > oldInFunction( inFunction ); 606 611 inFunction = true; 612 // The function body needs to have the same scope as parameters. 613 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 614 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 615 atFunctionTop = true; 607 616 maybeMutate_impl( node->statements, *this ); 608 617 maybeMutate_impl( node->attributes, *this ); … … 1007 1016 VISIT_START( node ); 1008 1017 { 1009 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1010 ValueGuard< bool > old InFunction( inFunction);1011 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1018 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1019 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1020 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1012 1021 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1013 inFunction= false;1022 atFunctionTop = false; 1014 1023 visitStatementList( node->kids ); 1015 1024 } … … 1021 1030 VISIT_START( node ); 1022 1031 { 1023 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1024 ValueGuard< bool > old InFunction( inFunction);1025 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1032 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1033 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1034 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1026 1035 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1027 inFunction= false;1036 atFunctionTop = false; 1028 1037 visitStatementList( node->kids ); 1029 1038 } … … 1035 1044 MUTATE_START( node ); 1036 1045 { 1037 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1038 ValueGuard< bool > old InFunction( inFunction);1039 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1046 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1047 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1048 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1040 1049 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1041 inFunction= false;1050 atFunctionTop = false; 1042 1051 mutateStatementList( node->kids ); 1043 1052 } -
src/Common/utility.h
r4b30e8cc rc28ea4e 360 360 reverse_iterate_t( T & ref ) : ref(ref) {} 361 361 362 typedef typename T::reverse_iterator iterator; 363 iterator begin() { return ref.rbegin(); } 364 iterator end() { return ref.rend(); } 362 // this does NOT work on const T!!! 363 // typedef typename T::reverse_iterator iterator; 364 auto begin() { return ref.rbegin(); } 365 auto end() { return ref.rend(); } 365 366 }; 366 367 -
src/Concurrency/Keywords.cc
r4b30e8cc rc28ea4e 46 46 } 47 47 48 // Only detects threads constructed with the keyword thread. 49 inline static bool isThread( DeclarationWithType * decl ) { 50 Type * baseType = decl->get_type()->stripDeclarator(); 51 StructInstType * instType = dynamic_cast<StructInstType *>( baseType ); 52 if ( nullptr == instType ) { return false; } 53 return instType->baseStruct->is_thread(); 54 } 55 48 56 //============================================================================================= 49 57 // Pass declarations … … 119 127 "get_thread", 120 128 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 121 " ",129 "ThreadCancelled", 122 130 true, 123 131 AggregateDecl::Thread … … 290 298 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first ); 291 299 void validate( DeclarationWithType * ); 292 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 293 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 300 void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 301 void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 302 void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ); 294 303 295 304 static void implement( std::list< Declaration * > & translationUnit ) { … … 302 311 StructDecl* guard_decl = nullptr; 303 312 StructDecl* dtor_guard_decl = nullptr; 313 StructDecl* thread_guard_decl = nullptr; 304 314 305 315 static std::unique_ptr< Type > generic_func; … … 801 811 bool first = false; 802 812 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 803 bool isDtor = CodeGen::isDestructor( decl->name );813 bool const isDtor = CodeGen::isDestructor( decl->name ); 804 814 805 815 // Is this function relevant to monitors … … 849 859 850 860 // Instrument the body 851 if( isDtor ) { 852 addDtorStatments( decl, body, mutexArgs ); 861 if ( isDtor && isThread( mutexArgs.front() ) ) { 862 if( !thread_guard_decl ) { 863 SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" ); 864 } 865 addThreadDtorStatements( decl, body, mutexArgs ); 866 } 867 else if ( isDtor ) { 868 addDtorStatements( decl, body, mutexArgs ); 853 869 } 854 870 else { 855 addStat ments( decl, body, mutexArgs );871 addStatements( decl, body, mutexArgs ); 856 872 } 857 873 } … … 870 886 assert( !dtor_guard_decl ); 871 887 dtor_guard_decl = decl; 888 } 889 else if( decl->name == "thread_dtor_guard_t" && decl->body ) { 890 assert( !thread_guard_decl ); 891 thread_guard_decl = decl; 872 892 } 873 893 } … … 908 928 } 909 929 910 void MutexKeyword::addDtorStat ments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {930 void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 911 931 Type * arg_type = args.front()->get_type()->clone(); 912 932 arg_type->set_mutex( false ); … … 957 977 958 978 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 959 body->push_front( new DeclStmt( monitors) ); 960 } 961 962 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 979 body->push_front( new DeclStmt( monitors ) ); 980 } 981 982 void MutexKeyword::addThreadDtorStatements( 983 FunctionDecl*, CompoundStmt * body, 984 const std::list<DeclarationWithType * > & args ) { 985 assert( args.size() == 1 ); 986 DeclarationWithType * arg = args.front(); 987 Type * arg_type = arg->get_type()->clone(); 988 assert( arg_type->get_mutex() ); 989 arg_type->set_mutex( false ); 990 991 // thread_dtor_guard_t __guard = { this, intptr( 0 ) }; 992 body->push_front( 993 new DeclStmt( new ObjectDecl( 994 "__guard", 995 noStorageClasses, 996 LinkageSpec::Cforall, 997 nullptr, 998 new StructInstType( 999 noQualifiers, 1000 thread_guard_decl 1001 ), 1002 new ListInit( 1003 { 1004 new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ), 1005 new SingleInit( new UntypedExpr( 1006 new NameExpr( "intptr" ), { 1007 new ConstantExpr( Constant::from_int( 0 ) ), 1008 } 1009 ) ), 1010 }, 1011 noDesignators, 1012 true 1013 ) 1014 )) 1015 ); 1016 } 1017 1018 void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 963 1019 ObjectDecl * monitors = new ObjectDecl( 964 1020 "__monitors", -
src/GenPoly/GenPoly.cc
r4b30e8cc rc28ea4e 46 46 } 47 47 48 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) { 49 for (auto ¶m : params) { 50 auto paramType = param.strict_as<ast::TypeExpr>(); 51 if (isPolyType(paramType->type, env)) return true; 52 } 53 return false; 54 } 55 48 56 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 49 57 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 56 64 } 57 65 66 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 67 for (auto ¶m : params) { 68 auto paramType = param.strict_as<ast::TypeExpr>(); 69 if (isPolyType(paramType->type, tyVars, env)) return true; 70 } 71 return false; 72 } 73 58 74 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 59 75 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 92 108 Type *newType = env->lookup( typeInst->get_name() ); 93 109 if ( newType ) return newType; 110 } 111 return type; 112 } 113 114 const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { 115 if (!env) return type; 116 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) { 117 auto newType = env->lookup(typeInst->name); 118 if (newType) return newType; 94 119 } 95 120 return type; … … 111 136 } 112 137 138 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) { 139 type = replaceTypeInst( type, env ); 140 141 if ( dynamic_cast< const ast::TypeInstType * >( type ) ) { 142 return type; 143 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 144 return isPolyType( arrayType->base, env ); 145 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 146 if ( hasPolyParams( structType->params, env ) ) return type; 147 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 148 if ( hasPolyParams( unionType->params, env ) ) return type; 149 } 150 return 0; 151 } 152 113 153 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 114 154 type = replaceTypeInst( type, env ); … … 126 166 } 127 167 return 0; 168 } 169 170 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 171 type = replaceTypeInst( type, env ); 172 173 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) { 174 return tyVars.find(typeInst->name) != tyVars.end() ? type : nullptr; 175 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 176 return isPolyType( arrayType->base, env ); 177 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 178 if ( hasPolyParams( structType->params, env ) ) return type; 179 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 180 if ( hasPolyParams( unionType->params, env ) ) return type; 181 } 182 return nullptr; 128 183 } 129 184 … … 449 504 } 450 505 506 namespace { 507 // temporary hack to avoid re-implementing anything related to TyVarMap 508 // does this work? these two structs have identical definitions. 509 inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) { 510 return *reinterpret_cast<const TypeDecl::Data *>(&data); 511 } 512 } 513 451 514 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 452 515 // is parameter is not polymorphic, don't need to box … … 459 522 } 460 523 524 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) { 525 // is parameter is not polymorphic, don't need to box 526 if ( ! isPolyType( param, exprTyVars ) ) return false; 527 ast::ptr<ast::Type> newType = arg; 528 if ( env ) env->apply( newType ); 529 // if the argument's type is polymorphic, we don't need to box again! 530 return ! isPolyType( newType ); 531 } 532 461 533 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 462 534 FunctionType * function = getFunctionType( appExpr->function->result ); … … 467 539 } 468 540 541 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) { 542 const ast::FunctionType * function = getFunctionType(appExpr->func->result); 543 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() ); 544 TyVarMap exprTyVars(TypeDecl::Data{}); 545 makeTyVarMap(function, exprTyVars); 546 return needsBoxing(param, arg, exprTyVars, env); 547 548 } 549 469 550 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { 470 551 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } ); 552 } 553 554 void addToTyVarMap( const ast::TypeDecl * tyVar, TyVarMap & tyVarMap) { 555 tyVarMap.insert(tyVar->name, convData(ast::TypeDecl::Data{tyVar})); 471 556 } 472 557 … … 478 563 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { 479 564 makeTyVarMap( pointer->get_base(), tyVarMap ); 565 } 566 } 567 568 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) { 569 if (auto ptype = dynamic_cast<const ast::ParameterizedType *>(type)) { 570 for (auto & tyVar : ptype->forall) { 571 assert (tyVar); 572 addToTyVarMap(tyVar, tyVarMap); 573 } 574 } 575 if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) { 576 makeTyVarMap(pointer->base, tyVarMap); 480 577 } 481 578 } -
src/GenPoly/GenPoly.h
r4b30e8cc rc28ea4e 26 26 27 27 namespace GenPoly { 28 28 29 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 29 30 30 /// Replaces a TypeInstType by its referrent in the environment, if applicable 31 31 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); … … 33 33 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 34 34 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 ); 35 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 35 36 36 37 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 37 38 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 39 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr); 38 40 39 41 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided … … 84 86 /// true if arg requires boxing given exprTyVars 85 87 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ); 88 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env); 86 89 87 90 /// true if arg requires boxing in the call to appExpr 88 91 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ); 92 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env); 89 93 90 94 /// Adds the type variable `tyVar` to `tyVarMap` … … 93 97 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 94 98 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 99 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap); 95 100 96 101 /// Prints type variable map -
src/GenPoly/Specialize.cc
r4b30e8cc rc28ea4e 218 218 thunkFunc->get_attributes().push_back( new Attribute( "unused" ) ); 219 219 220 // Thunks at the global level must be static to avoid collisions between files. 221 // (Conversly thunks inside a function must be unique and not static.) 222 thunkFunc->storageClasses.is_static = !isInFunction(); 223 220 224 // thread thunk parameters into call to actual function, naming thunk parameters as we go 221 225 UniqueName paramNamer( paramPrefix ); -
src/InitTweak/FixGlobalInit.cc
r4b30e8cc rc28ea4e 34 34 #include "SynTree/Visitor.h" // for acceptAll, Visitor 35 35 36 #include "AST/Expr.hpp" 37 #include "AST/Node.hpp" 38 #include "AST/Pass.hpp" 39 36 40 namespace InitTweak { 37 41 class GlobalFixer : public WithShortCircuiting { … … 50 54 FunctionDecl * initFunction; 51 55 FunctionDecl * destroyFunction; 56 }; 57 58 class GlobalFixer_new : public ast::WithShortCircuiting { 59 public: 60 void previsit (const ast::ObjectDecl *); 61 void previsit (const ast::FunctionDecl *) { visit_children = false; } 62 void previsit (const ast::StructDecl *) { visit_children = false; } 63 void previsit (const ast::UnionDecl *) { visit_children = false; } 64 void previsit (const ast::EnumDecl *) { visit_children = false; } 65 void previsit (const ast::TraitDecl *) { visit_children = false; } 66 void previsit (const ast::TypeDecl *) { visit_children = false; } 67 68 std::list< ast::ptr<ast::Stmt> > initStmts; 69 std::list< ast::ptr<ast::Stmt> > destroyStmts; 52 70 }; 53 71 … … 91 109 } 92 110 111 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 112 ast::Pass<GlobalFixer_new> fixer; 113 accept_all(translationUnit, fixer); 114 115 if ( !fixer.core.initStmts.empty() ) { 116 std::vector<ast::ptr<ast::Expr>> ctorParams; 117 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 118 auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)), 119 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))}); 120 121 translationUnit.decls.emplace_back( initFunction ); 122 } // if 123 124 if ( !fixer.core.destroyStmts.empty() ) { 125 std::vector<ast::ptr<ast::Expr>> dtorParams; 126 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 127 auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)), 128 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))}); 129 130 translationUnit.decls.emplace_back(destroyFunction); 131 } // if 132 } 133 93 134 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 94 135 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); … … 112 153 } // if 113 154 if ( Statement * ctor = ctorInit->ctor ) { 114 // Translation 1: Add this attribute on the global declaration: 115 // __attribute__((section (".data#"))) 116 // which makes gcc put the global in the data section, 117 // so that the global is writeable (via a const cast) in the init function. 118 // The trailing # is an injected assembly comment, to suppress the "a" in 119 // .section .data,"a" 120 // .section .data#,"a" 121 // to avoid assembler warning "ignoring changed section attributes for .data" 122 Type *strLitT = new PointerType( Type::Qualifiers( ), 123 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 124 std::list< Expression * > attr_params; 125 attr_params.push_back( 126 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 127 objDecl->attributes.push_back(new Attribute("section", attr_params)); 128 // Translation 2: Move the initizliation off the global declaration, 129 // into the startup function. 155 addDataSectonAttribute( objDecl ); 130 156 initStatements.push_back( ctor ); 131 157 objDecl->init = nullptr; … … 142 168 } 143 169 170 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 171 auto mutDecl = mutate(objDecl); 172 assertf(mutDecl == objDecl, "Global object decl must be unique"); 173 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) { 174 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 175 assert( ! ctorInit->ctor || ! ctorInit->init ); 176 177 const ast::Stmt * dtor = ctorInit->dtor; 178 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 179 // don't need to call intrinsic dtor, because it does nothing, but 180 // non-intrinsic dtors must be called 181 destroyStmts.push_front( dtor ); 182 // ctorInit->dtor = nullptr; 183 } // if 184 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 185 initStmts.push_back( ctor ); 186 mutDecl->init = nullptr; 187 // ctorInit->ctor = nullptr; 188 } else if ( const ast::Init * init = ctorInit->init ) { 189 mutDecl->init = init; 190 // ctorInit->init = nullptr; 191 } else { 192 // no constructor and no initializer, which is okay 193 mutDecl->init = nullptr; 194 } // if 195 // delete ctorInit; 196 } // if 197 } 198 144 199 // only modify global variables 145 200 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; } -
src/InitTweak/FixGlobalInit.h
r4b30e8cc rc28ea4e 19 19 #include <string> // for string 20 20 21 #include <AST/Fwd.hpp> 22 23 21 24 class Declaration; 22 25 … … 26 29 /// function is for library code. 27 30 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 28 32 } // namespace 29 33 -
src/InitTweak/FixInit.cc
r4b30e8cc rc28ea4e 219 219 }; 220 220 221 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution,public WithStmtsToAdd {221 struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd { 222 222 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 223 223 static void split( std::list< Declaration * > &translationUnit ); … … 802 802 if ( Statement * ctor = ctorInit->get_ctor() ) { 803 803 if ( objDecl->get_storageClasses().is_static ) { 804 805 // The ojbect needs to go in the data section, regardless of dtor complexity below. 806 // The attribute works, and is meant to apply, both for leaving the static local alone, 807 // and for hoisting it out as a static global. 808 addDataSectonAttribute( objDecl ); 809 804 810 // originally wanted to take advantage of gcc nested functions, but 805 811 // we get memory errors with this approach. To remedy this, the static -
src/InitTweak/FixInit.h
r4b30e8cc rc28ea4e 20 20 21 21 class Declaration; 22 namespace ast { 23 class TranslationUnit; 24 } 22 25 23 26 namespace InitTweak { 24 27 /// replace constructor initializers with expression statements and unwrap basic C-style initializers 25 28 void fix( std::list< Declaration * > & translationUnit, bool inLibrary ); 29 30 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 26 31 } // namespace 27 32 -
src/InitTweak/GenInit.cc
r4b30e8cc rc28ea4e 283 283 assert( stmts.size() <= 1 ); 284 284 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr; 285 286 } 287 288 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 289 assertf(objDecl, "genCtorDtor passed null objDecl"); 290 InitExpander_new srcParam(arg); 291 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 285 292 } 286 293 -
src/InitTweak/GenInit.h
r4b30e8cc rc28ea4e 33 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 34 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr ); 35 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 35 36 36 37 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer -
src/InitTweak/InitTweak.cc
r4b30e8cc rc28ea4e 498 498 } 499 499 500 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 501 assertf( func, "getParamThis: nullptr ftype" ); 502 auto & params = func->params; 503 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 504 return params.front().strict_as<ast::ObjectDecl>(); 505 } 506 500 507 bool tryConstruct( DeclarationWithType * dwt ) { 501 508 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt ); … … 511 518 } 512 519 520 bool tryConstruct( const ast::DeclWithType * dwt ) { 521 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt ); 522 if ( ! objDecl ) return false; 523 return (objDecl->init == nullptr || 524 ( objDecl->init != nullptr && objDecl->init->maybeConstructed )) 525 && ! objDecl->storage.is_extern 526 && isConstructable( objDecl->type ); 527 } 528 529 bool isConstructable( const ast::Type * type ) { 530 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type ) 531 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type ); 532 } 533 513 534 struct CallFinder_old { 514 535 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} … … 536 557 537 558 struct CallFinder_new final { 538 std::vector< ast::ptr< ast::Expr >> matches;559 std::vector< const ast::Expr * > matches; 539 560 const std::vector< std::string > names; 540 561 … … 558 579 } 559 580 560 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt ) {581 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 561 582 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 562 583 maybe_accept( stmt, finder ); … … 696 717 template <typename Predicate> 697 718 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 698 std::vector< ast::ptr< ast::Expr >> callExprs = collectCtorDtorCalls( stmt );719 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 699 720 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 700 721 } … … 939 960 } 940 961 962 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 963 // following passes may accidentally resolve this expression if returned as untyped... 964 ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) { 965 static ast::ptr<ast::FunctionDecl> assign = nullptr; 966 if (!assign) { 967 auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true); 968 assign = new ast::FunctionDecl({}, "?=?", {}, 969 { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 970 new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))}, 971 { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 972 } 973 if (dst->result.as<ast::ReferenceType>()) { 974 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 975 dst = new ast::AddressExpr(dst); 976 } 977 } 978 else { 979 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 980 } 981 if (src->result.as<ast::ReferenceType>()) { 982 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 983 src = new ast::AddressExpr(src); 984 } 985 } 986 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src}); 987 } 988 941 989 struct ConstExprChecker : public WithShortCircuiting { 942 990 // most expressions are not const expr … … 1055 1103 return isCopyFunction( decl, "?{}" ); 1056 1104 } 1105 1106 void addDataSectonAttribute( ObjectDecl * objDecl ) { 1107 Type *strLitT = new PointerType( Type::Qualifiers( ), 1108 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 1109 std::list< Expression * > attr_params; 1110 attr_params.push_back( 1111 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 1112 objDecl->attributes.push_back(new Attribute("section", attr_params)); 1113 } 1114 1057 1115 } -
src/InitTweak/InitTweak.h
r4b30e8cc rc28ea4e 38 38 /// returns the first parameter of a constructor/destructor/assignment function 39 39 ObjectDecl * getParamThis( FunctionType * ftype ); 40 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 40 41 41 42 /// generate a bitwise assignment operation. 42 43 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ); 44 45 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 43 46 44 47 /// transform Initializer into an argument list that can be passed to a call expression … … 48 51 /// True if the resolver should try to construct dwt 49 52 bool tryConstruct( DeclarationWithType * dwt ); 53 bool tryConstruct( const ast::DeclWithType * dwt ); 50 54 51 55 /// True if the type can have a user-defined constructor 52 56 bool isConstructable( Type * t ); 57 bool isConstructable( const ast::Type * t ); 53 58 54 59 /// True if the Initializer contains designations … … 79 84 /// get all Ctor/Dtor call expressions from a Statement 80 85 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ); 81 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt );86 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 82 87 83 88 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call … … 102 107 bool isConstExpr( Expression * expr ); 103 108 bool isConstExpr( Initializer * init ); 109 110 /// Modifies objDecl to have: 111 /// __attribute__((section (".data#"))) 112 /// which makes gcc put the declared variable in the data section, 113 /// which is helpful for global constants on newer gcc versions, 114 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 115 /// The trailing # is an injected assembly comment, to suppress the "a" in 116 /// .section .data,"a" 117 /// .section .data#,"a" 118 /// to avoid assembler warning "ignoring changed section attributes for .data" 119 void addDataSectonAttribute( ObjectDecl * objDecl ); 104 120 105 121 class InitExpander_old { -
src/InitTweak/module.mk
r4b30e8cc rc28ea4e 23 23 InitTweak/GenInit.h \ 24 24 InitTweak/InitTweak.cc \ 25 InitTweak/InitTweak.h 25 InitTweak/InitTweak.h \ 26 InitTweak/FixInitNew.cpp 26 27 27 28 SRCDEMANGLE += \ -
src/Parser/ParseNode.h
r4b30e8cc rc28ea4e 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jul 6 09:33:32202013 // Update Count : 89 212 // Last Modified On : Sat Oct 24 03:53:54 2020 13 // Update Count : 895 14 14 // 15 15 … … 205 205 struct TypeData; 206 206 207 class DeclarationNode : public ParseNode { 208 public: 207 struct DeclarationNode : public ParseNode { 209 208 // These enumerations must harmonize with their names in DeclarationNode.cc. 210 209 enum BasicType { Void, Bool, Char, Int, Int128, … … 304 303 bool get_inLine() const { return inLine; } 305 304 DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; } 306 public: 305 307 306 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); } 308 307 … … 360 359 //############################################################################## 361 360 362 class StatementNode final : public ParseNode { 363 public: 361 struct StatementNode final : public ParseNode { 364 362 StatementNode() { stmt = nullptr; } 365 363 StatementNode( Statement * stmt ) : stmt( stmt ) {} … … 382 380 os << stmt.get() << std::endl; 383 381 } 384 private: 382 385 383 std::unique_ptr<Statement> stmt; 386 384 }; // StatementNode … … 426 424 Statement * build_finally( StatementNode * stmt ); 427 425 Statement * build_compound( StatementNode * first ); 426 StatementNode * maybe_build_compound( StatementNode * first ); 428 427 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr ); 429 428 Statement * build_directive( std::string * directive ); -
src/Parser/StatementNode.cc
r4b30e8cc rc28ea4e 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 4 09:39:25 201813 // Update Count : 3 6312 // Last Modified On : Sat Oct 24 04:20:55 2020 13 // Update Count : 383 14 14 // 15 15 … … 345 345 } // build_compound 346 346 347 // A single statement in a control structure is always converted to a compound statement so subsequent generated code 348 // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single 349 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a 350 // conical form for code generation. 351 StatementNode * maybe_build_compound( StatementNode * first ) { 352 // Optimization: if the control-structure statement is a compound statement, do not wrap it. 353 // e.g., if (...) {...} do not wrap the existing compound statement. 354 if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr 355 CompoundStmt * cs = new CompoundStmt(); 356 buildMoveList( first, cs->get_kids() ); 357 return new StatementNode( cs ); 358 } // if 359 return first; 360 } // maybe_build_compound 361 347 362 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 348 363 std::list< Expression * > out, in; -
src/Parser/parser.yy
r4b30e8cc rc28ea4e 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 9 18:09:09202013 // Update Count : 46 1412 // Last Modified On : Sat Oct 24 08:21:14 2020 13 // Update Count : 4624 14 14 // 15 15 … … 1080 1080 IF '(' if_control_expression ')' statement %prec THEN 1081 1081 // explicitly deal with the shift/reduce conflict on if/else 1082 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }1082 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); } 1083 1083 | IF '(' if_control_expression ')' statement ELSE statement 1084 { $$ = new StatementNode( build_if( $3, $5, $7) ); }1084 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); } 1085 1085 ; 1086 1086 … … 1130 1130 1131 1131 case_clause: // CFA 1132 case_label_list statement { $$ = $1->append_last_case( new StatementNode( build_compound( $2 )) ); }1132 case_label_list statement { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); } 1133 1133 ; 1134 1134 … … 1148 1148 iteration_statement: 1149 1149 WHILE '(' push if_control_expression ')' statement pop 1150 { $$ = new StatementNode( build_while( $4, $6) ); }1150 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); } 1151 1151 | WHILE '(' ')' statement // CFA => while ( 1 ) 1152 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4) ); }1152 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1153 1153 | DO statement WHILE '(' comma_expression ')' ';' 1154 { $$ = new StatementNode( build_do_while( $5, $2) ); }1154 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1155 1155 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1156 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2) ); }1156 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1157 1157 | FOR '(' push for_control_expression_list ')' statement pop 1158 { $$ = new StatementNode( build_for( $4, $6) ); }1158 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); } 1159 1159 | FOR '(' ')' statement // CFA => for ( ;; ) 1160 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4) ); }1160 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1161 1161 ; 1162 1162 … … 1341 1341 waitfor_clause: 1342 1342 when_clause_opt waitfor statement %prec THEN 1343 { $$ = build_waitfor( $2, $3, $1 ); }1343 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); } 1344 1344 | when_clause_opt waitfor statement WOR waitfor_clause 1345 { $$ = build_waitfor( $2, $3, $1, $5 ); }1345 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); } 1346 1346 | when_clause_opt timeout statement %prec THEN 1347 { $$ = build_waitfor_timeout( $2, $3, $1 ); }1347 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); } 1348 1348 | when_clause_opt ELSE statement 1349 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }1349 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); } 1350 1350 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1351 1351 | when_clause_opt timeout statement WOR ELSE statement 1352 1352 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1353 1353 | when_clause_opt timeout statement WOR when_clause ELSE statement 1354 { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }1354 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); } 1355 1355 ; 1356 1356 -
src/ResolvExpr/Resolver.cc
r4b30e8cc rc28ea4e 1105 1105 } 1106 1106 1107 /// Establish post-resolver invariants for expressions 1107 1108 } // anonymous namespace 1109 /// Establish post-resolver invariants for expressions 1108 1110 void finishExpr( 1109 1111 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, … … 1118 1120 StripCasts_new::strip( expr ); 1119 1121 } 1120 } // anonymous namespace1121 1122 1122 1123 1123 ast::ptr< ast::Expr > resolveInVoidContext( … … 1139 1139 } 1140 1140 1141 namespace { 1142 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1141 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1143 1142 /// context. 1144 1143 ast::ptr< ast::Expr > findVoidExpression( … … 1151 1150 return newExpr; 1152 1151 } 1152 1153 namespace { 1154 1153 1155 1154 1156 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the … … 1162 1164 CandidateRef choice = 1163 1165 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1164 finishExpr( choice->expr, choice->env, untyped->env );1166 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env ); 1165 1167 return std::move( choice->expr ); 1166 1168 } … … 1272 1274 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 1273 1275 1274 void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {1276 void resolve( ast::TranslationUnit& translationUnit ) { 1275 1277 ast::Pass< Resolver_new >::run( translationUnit ); 1276 1278 } -
src/ResolvExpr/Resolver.h
r4b30e8cc rc28ea4e 35 35 class StmtExpr; 36 36 class SymbolTable; 37 class TranslationUnit; 37 38 class Type; 38 39 class TypeEnvironment; … … 55 56 56 57 /// Checks types and binds syntactic constructs to typed representations 57 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );58 void resolve( ast::TranslationUnit& translationUnit ); 58 59 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 59 60 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); … … 66 67 ast::ptr< ast::Expr > findSingleExpression( 67 68 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab ); 69 ast::ptr< ast::Expr > findVoidExpression( 70 const ast::Expr * untyped, const ast::SymbolTable & symtab); 68 71 /// Resolves a constructor init expression 69 ast::ptr< ast::Init > resolveCtorInit( 72 ast::ptr< ast::Init > resolveCtorInit( 70 73 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab ); 71 74 /// Resolves a statement expression 72 ast::ptr< ast::Expr > resolveStmtExpr( 75 ast::ptr< ast::Expr > resolveStmtExpr( 73 76 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab ); 74 77 } // namespace ResolvExpr -
src/SymTab/Autogen.cc
r4b30e8cc rc28ea4e 233 233 } 234 234 235 // shallow copy the pointer list for return 236 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) { 237 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) { 238 return structInst->base->params; 239 } 240 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) { 241 return unionInst->base->params; 242 } 243 return {}; 244 } 245 235 246 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 236 247 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 244 255 ftype->parameters.push_back( dstParam ); 245 256 return ftype; 257 } 258 259 /// 260 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) { 261 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 262 if (maybePolymorphic) typeParams = getGenericParams(paramType); 263 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall); 264 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc)); 246 265 } 247 266 -
src/SymTab/Autogen.h
r4b30e8cc rc28ea4e 55 55 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic 56 56 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true ); 57 58 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true); 57 59 58 60 /// generate the type of a copy constructor for paramType. -
src/SynTree/Expression.h
r4b30e8cc rc28ea4e 163 163 }; 164 164 165 /// VariableExpr represents an expression that simply refers to the value of a named variable. 166 /// Does not take ownership of var. 167 class VariableExpr : public Expression { 168 public: 169 DeclarationWithType * var; 170 171 VariableExpr(); 172 VariableExpr( DeclarationWithType * var ); 173 VariableExpr( const VariableExpr & other ); 174 virtual ~VariableExpr(); 175 176 bool get_lvalue() const final; 177 178 DeclarationWithType * get_var() const { return var; } 179 void set_var( DeclarationWithType * newValue ) { var = newValue; } 180 181 static VariableExpr * functionPointer( FunctionDecl * decl ); 182 183 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); } 184 virtual void accept( Visitor & v ) override { v.visit( this ); } 185 virtual void accept( Visitor & v ) const override { v.visit( this ); } 186 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 187 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 188 }; 189 165 190 // The following classes are used to represent expression types that cannot be converted into 166 191 // function-call format. … … 329 354 }; 330 355 331 /// VariableExpr represents an expression that simply refers to the value of a named variable.332 /// Does not take ownership of var.333 class VariableExpr : public Expression {334 public:335 DeclarationWithType * var;336 337 VariableExpr();338 VariableExpr( DeclarationWithType * var );339 VariableExpr( const VariableExpr & other );340 virtual ~VariableExpr();341 342 bool get_lvalue() const final;343 344 DeclarationWithType * get_var() const { return var; }345 void set_var( DeclarationWithType * newValue ) { var = newValue; }346 347 static VariableExpr * functionPointer( FunctionDecl * decl );348 349 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }350 virtual void accept( Visitor & v ) override { v.visit( this ); }351 virtual void accept( Visitor & v ) const override { v.visit( this ); }352 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }353 virtual void print( std::ostream & os, Indenter indent = {} ) const override;354 };355 356 356 /// ConstantExpr represents an expression that simply refers to the value of a constant 357 357 class ConstantExpr : public Expression { -
src/main.cc
r4b30e8cc rc28ea4e 343 343 auto transUnit = convert( move( translationUnit ) ); 344 344 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 345 if ( exprp ) { 346 translationUnit = convert( move( transUnit ) ); 347 dump( translationUnit ); 348 return EXIT_SUCCESS; 349 } // if 350 351 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 345 352 translationUnit = convert( move( transUnit ) ); 346 353 } else { 347 354 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 355 if ( exprp ) { 356 dump( translationUnit ); 357 return EXIT_SUCCESS; 358 } 359 360 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 348 361 } 349 362 350 if ( exprp ) {351 dump( translationUnit );352 return EXIT_SUCCESS;353 } // if354 355 363 // fix ObjectDecl - replaces ConstructorInit nodes 356 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );357 364 if ( ctorinitp ) { 358 365 dump ( translationUnit ); -
tests/.expect/const-init.txt
r4b30e8cc rc28ea4e 1 done 1 almost done 2 dtor -
tests/Makefile.am
r4b30e8cc rc28ea4e 53 53 54 54 # adjust CC to current flags 55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ,$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})55 CC = LC_ALL=C $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS}) 56 56 CFACC = $(CC) 57 57 … … 60 60 61 61 # adjusted CC but without the actual distcc call 62 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS} ,$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})62 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS} ${AST_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS} ${AST_FLAGS}) 63 63 CFACCLINK = $(CFACCLOCAL) -quiet $(if $(test), 2> $(test), ) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) 64 64 -
tests/alloc.cfa
r4b30e8cc rc28ea4e 342 342 for ( i; dim ) { printf( "%d %g, ", stp1[i].x, stp1[i].y ); } 343 343 printf( "\n" ); 344 adelete( dim, stp, dim, stp1 );344 adelete( stp, stp1 ); 345 345 346 346 // extras -
tests/complex.cfa
r4b30e8cc rc28ea4e 14 14 // 15 15 16 #include <stdio.h>17 16 #include <complex.h> 18 17 #ifdef __CFA__ -
tests/config.py.in
r4b30e8cc rc28ea4e 9 9 HOSTARCH = "@host_cpu@" 10 10 DISTRIBUTE = @HAS_DISTCC@ 11 NEWAST = @DEFAULT_NEW_AST@ -
tests/const-init.cfa
r4b30e8cc rc28ea4e 16 16 /* 17 17 18 Th is test shows non-crashing of generated code for constants with interesting initizers.18 These tests show non-crashing of generated code for constants with interesting initializers. 19 19 The potential for these to crash is compiler dependent. 20 20 21 21 There are two cases: 22 1. static constants in one compilation unit (tested here )22 1. static constants in one compilation unit (tested here, in a few sub-cases) 23 23 2. extern constants across compilation units (tested by libcfa being loadable, specifically 24 the constant de clarations in libcfa/src/limits.cfa, which almost every test exercises,24 the constant definitions in libcfa/src/limits.cfa, which almost every test exercises, 25 25 including "hello;" but notably, the "limits" test does not exercise it because that test 26 26 is compile-only) … … 37 37 GCC-10 on Ubuntu 20.04 Has crashed Has crashed 38 38 39 For this test caseto fail, with most other tests passing, would be a situation only ever39 For this test to fail, with most other tests passing, would be a situation only ever 40 40 observed with GCC-8. 41 41 42 42 */ 43 43 44 // initailized by generated function, called before main 44 45 static const char foo = -1; 45 46 47 struct thing{}; 48 void ^?{}( thing & ) { printf("dtor\n"); } 49 46 50 int main() { 47 printf("done\n"); 51 // foo is already initialized 52 53 // no dtor => stays a (static) local, initialized here 54 static const char bar = -1; 55 56 // has dtor => becomes a global, ctor called here, dtor called at exit 57 static const thing it; 58 59 printf("almost done\n"); 48 60 } -
tests/exceptions/cancel/coroutine.cfa
r4b30e8cc rc28ea4e 1 1 // Try cancelling a coroutine. 2 2 3 #include <stdio.h>4 3 #include <coroutine.hfa> 5 4 #include <exception.hfa> -
tests/exceptions/conditional.cfa
r4b30e8cc rc28ea4e 5 5 6 6 #include <exception.hfa> 7 #include <stdio.h>8 7 9 8 VTABLE_DECLARATION(num_error)( -
tests/exceptions/except-io.hfa
r4b30e8cc rc28ea4e 1 1 // Common tools for the exception tests. 2 3 #include <stdio.h>4 2 5 3 // Echo when a destructor is run and an area/block is left. -
tests/exceptions/trash.cfa
r4b30e8cc rc28ea4e 2 2 3 3 #include <exception.hfa> 4 #include <stdio.h>5 4 6 5 TRIVIAL_EXCEPTION(yin); -
tests/global-monomorph.cfa
r4b30e8cc rc28ea4e 1 // Crea 2 3 #include <stdlib.hfa> 4 #include <stdio.h> 1 // Create monomorphic instances of polymorphic types at global scope. 5 2 6 3 forall(dtype T) -
tests/poly-d-cycle.cfa
r4b30e8cc rc28ea4e 1 1 // Check that a cycle of polymorphic dtype structures can be instancated. 2 3 #include <stdio.h>4 2 5 3 forall(dtype T) -
tests/poly-o-cycle.cfa
r4b30e8cc rc28ea4e 1 1 // Check that a cycle of polymorphic otype structures can be instancated. 2 3 #include <stdio.h>4 2 5 3 forall(otype T) -
tests/pybin/settings.py
r4b30e8cc rc28ea4e 85 85 def filter(self, tests): 86 86 return [test for test in tests if not test.arch or self.target == test.arch] 87 return True if not arch else self.target == arch88 87 89 88 @staticmethod … … 98 97 self.path = "debug" if value else "nodebug" 99 98 99 class AST: 100 def __init__(self, ast): 101 if ast == "new": 102 self.target = ast 103 self.string = "New AST" 104 self.flags = """AST_FLAGS=-XCFA,--new-ast""" 105 elif ast == "old": 106 self.target = ast 107 self.string = "Old AST" 108 self.flags = """AST_FLAGS=-XCFA,--old-ast""" 109 elif ast == None: 110 self.target = "new" if config.NEWAST else "old" 111 self.string = "Default AST (%s)" % self.target 112 self.flags = """AST_FLAGS=""" 113 else: 114 print("""ERROR: Invalid ast configuration, must be "old", "new" or left unspecified, was %s""" % (value), file=sys.stderr) 115 sys.exit(1) 116 117 def filter(self, tests): 118 119 return [test for test in tests if not test.astv or self.target == test.astv] 120 100 121 class Install: 101 122 def __init__(self, value): … … 120 141 121 142 def init( options ): 143 global all_ast 122 144 global all_arch 123 145 global all_debug 124 146 global all_install 147 global ast 125 148 global arch 149 global debug 126 150 global archive 151 global install 152 127 153 global continue_ 128 global debug129 154 global dry_run 130 155 global generating 131 global install132 156 global make 133 157 global output_width … … 135 159 global timeout2gdb 136 160 161 all_ast = [AST(o) for o in list(dict.fromkeys(options.ast ))] if options.ast else [AST(None)] 137 162 all_arch = [Architecture(o) for o in list(dict.fromkeys(options.arch ))] if options.arch else [Architecture(None)] 138 163 all_debug = [Debug(o) for o in list(dict.fromkeys(options.debug ))] -
tests/pybin/test_run.py
r4b30e8cc rc28ea4e 11 11 self.path = '' 12 12 self.arch = '' 13 self.astv = '' 13 14 14 15 def toString(self): 15 return "{:25s} ({:5s} {:s})".format( self.name, self.arch if self.archelse "Any", self.target() )16 return "{:25s} ({:5s} arch, {:s} ast: {:s})".format( self.name, self.arch if self.arch else "Any", self.astv if self.astv else "Any", self.target() ) 16 17 17 18 def prepare(self): … … 20 21 21 22 def expect(self): 22 return os.path.normpath( os.path.join(settings.SRCDIR , self.path, ".expect", "%s%s.txt" % (self.name,'' if not self.arch else ".%s" % self.arch)) ) 23 arch = '' if not self.arch else ".%s" % self.arch 24 astv = '' if not self.astv else ".nast" if self.astv == "new" else ".oast" 25 return os.path.normpath( os.path.join(settings.SRCDIR , self.path, ".expect", "%s%s%s.txt" % (self.name,astv,arch)) ) 23 26 24 27 def error_log(self): … … 45 48 46 49 @staticmethod 47 def new_target(target, arch ):50 def new_target(target, arch, astv): 48 51 test = Test() 49 52 test.name = os.path.basename(target) 50 53 test.path = os.path.relpath (os.path.dirname(target), settings.SRCDIR) 51 54 test.arch = arch.target if arch else '' 55 test.astv = astv.target if astv else '' 52 56 return test 53 57 -
tests/pybin/tools.py
r4b30e8cc rc28ea4e 181 181 '-s' if silent else None, 182 182 test_param, 183 settings.ast.flags, 183 184 settings.arch.flags, 184 185 settings.debug.flags, -
tests/test.py
r4b30e8cc rc28ea4e 24 24 25 25 def match_test(path): 26 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\. [\w\-_]+)?\.txt$" % settings.SRCDIR, path)26 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.nast|\.oast)?(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path) 27 27 if match : 28 28 test = Test() 29 29 test.name = match.group(2) 30 30 test.path = match.group(1) 31 test.arch = match.group(3)[1:] if match.group(3) else None 31 test.arch = match.group(4)[1:] if match.group(4) else None 32 33 astv = match.group(3)[1:] if match.group(3) else None 34 if astv == 'oast': 35 test.astv = 'old' 36 elif astv == 'nast': 37 test.astv = 'new' 38 elif astv: 39 print('ERROR: "%s", expect file has astv but it is not "nast" or "oast"' % testname, file=sys.stderr) 40 sys.exit(1) 41 32 42 expected.append(test) 33 43 … … 66 76 if options.regenerate_expected : 67 77 for testname in options.tests : 68 testname = canonical_path( testname ) 78 testname = os.path.normpath( os.path.join(settings.SRCDIR, testname) ) 79 69 80 # first check if this is a valid name to regenerate 70 81 if Test.valid_name(testname): 71 82 # this is a valid name, let's check if it already exists 72 83 found = [test for test in all_tests if canonical_path( test.target() ) == testname] 84 setup = itertools.product(settings.all_arch if options.arch else [None], settings.all_ast if options.ast else [None]) 73 85 if not found: 74 # it's a new name, create it according to the name and specified architecture 75 if options.arch: 76 # user specified one or multiple architectures, assume the tests will have architecture specific results 77 tests.extend( [Test.new_target(testname, arch) for arch in settings.all_arch] ) 78 else: 79 # user didn't specify an architecture, just create a cross platform test 80 tests.append( Test.new_target( testname, None ) ) 86 # it's a new name, create it according to the name and specified architecture/ast version 87 tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] ) 81 88 elif len(found) == 1 and not found[0].arch: 82 89 # we found a single test, the user better be wanting to create a cross platform test 83 90 if options.arch: 84 91 print('ERROR: "%s", test has no specified architecture but --arch was specified, ignoring it' % testname, file=sys.stderr) 92 elif options.ast: 93 print('ERROR: "%s", test has no specified ast version but --ast was specified, ignoring it' % testname, file=sys.stderr) 85 94 else: 86 95 tests.append( found[0] ) 87 96 else: 88 97 # this test is already cross platform, just add a test for each platform the user asked 89 tests.extend( [Test.new_target(testname, arch ) for arch in settings.all_arch] )98 tests.extend( [Test.new_target(testname, arch, ast) for arch, ast in setup] ) 90 99 91 100 # print a warning if it users didn't ask for a specific architecture 92 101 if not options.arch: 93 102 print('WARNING: "%s", test has architecture specific expected files but --arch was not specified, regenerating only for current host' % testname, file=sys.stderr) 103 104 105 # print a warning if it users didn't ask for a specific ast version 106 if not options.ast: 107 print('WARNING: "%s", test has ast version specific expected files but --ast was not specified, regenerating only for current ast' % testname, file=sys.stderr) 94 108 95 109 else : … … 112 126 # create a parser with the arguments for the tests script 113 127 parser = argparse.ArgumentParser(description='Script which runs cforall tests') 128 parser.add_argument('--ast', help='Test for specific ast', type=comma_separated(str), default=None) 129 parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None) 114 130 parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes') 115 131 parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no') 116 parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default=None)117 132 parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_') 118 133 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120) … … 251 266 except KeyboardInterrupt: 252 267 return False, "" 253 except Exception as ex:254 print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)255 sys.stderr.flush()256 return False, ""268 # except Exception as ex: 269 # print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr) 270 # sys.stderr.flush() 271 # return False, "" 257 272 258 273 … … 362 377 # for each build configurations, run the test 363 378 with Timed() as total_dur: 364 for arch, debug, install in itertools.product(settings.all_arch, settings.all_debug, settings.all_install): 379 for ast, arch, debug, install in itertools.product(settings.all_ast, settings.all_arch, settings.all_debug, settings.all_install): 380 settings.ast = ast 365 381 settings.arch = arch 366 382 settings.debug = debug … … 369 385 # filter out the tests for a different architecture 370 386 # tests are the same across debug/install 371 local_tests = settings.arch.filter( tests ) 387 local_tests = settings.ast.filter( tests ) 388 local_tests = settings.arch.filter( local_tests ) 372 389 options.jobs, forceJobs = job_count( options, local_tests ) 373 390 settings.update_make_cmd(forceJobs, options.jobs) … … 377 394 378 395 # print configuration 379 print('%s %i tests on %i cores (%s:%s )' % (396 print('%s %i tests on %i cores (%s:%s - %s)' % ( 380 397 'Regenerating' if settings.generating else 'Running', 381 398 len(local_tests), 382 399 options.jobs, 400 settings.ast.string, 383 401 settings.arch.string, 384 402 settings.debug.string 385 403 )) 404 if not local_tests : 405 print('WARNING: No tests for this configuration') 406 continue 386 407 387 408 # otherwise run all tests and make sure to return the correct error code
Note:
See TracChangeset
for help on using the changeset viewer.