Compare commits
278
Commits
release_70
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56d941a8ce | ||
|
|
cb6f3c46a8 | ||
|
|
ace8505db1 | ||
|
|
9dfddd6912 | ||
|
|
731769fe89 | ||
|
|
3bdcaec89a | ||
|
|
85e24591e4 | ||
|
|
dbb024cf94 | ||
|
|
2cb5d49f71 | ||
|
|
66ddc2110a | ||
|
|
2b135c5afc | ||
|
|
b93e8ad893 | ||
|
|
537de38cfe | ||
|
|
1fe4d6217e | ||
|
|
ee03160612 | ||
|
|
7ed5372fe0 | ||
|
|
bae5e5989e | ||
|
|
77d31c11e8 | ||
|
|
bfca7f70c5 | ||
|
|
ad72f5e57b | ||
|
|
cd9405f3b9 | ||
|
|
3f4c51a258 | ||
|
|
3eae253b1a | ||
|
|
7875131e8d | ||
|
|
b0cb65c508 | ||
|
|
04b98c1875 | ||
|
|
923dcc5544 | ||
|
|
ee9c0c5007 | ||
|
|
dabebaf3ab | ||
|
|
9ea8071852 | ||
|
|
3654abe1c4 | ||
|
|
2535f2b254 | ||
|
|
c8294f02f9 | ||
|
|
3c7e9228ca | ||
|
|
6a2cf6907c | ||
|
|
64bfa8497f | ||
|
|
e8bd614a37 | ||
|
|
716f6ba727 | ||
|
|
6cbafacdcf | ||
|
|
34b2830c83 | ||
|
|
ca7d371ddf | ||
|
|
b9b98019a0 | ||
|
|
57b2fafae6 | ||
|
|
b840a856c2 | ||
|
|
9ad60c0ccd | ||
|
|
8dabfbaf51 | ||
|
|
b0376454fa | ||
|
|
c1b1ef1c00 | ||
|
|
07f4283e71 | ||
|
|
cff3557e55 | ||
|
|
0519a2c6b2 | ||
|
|
946967528b | ||
|
|
d4b114904a | ||
|
|
bb2634a97e | ||
|
|
8e626ba79d | ||
|
|
201ba9ed4c | ||
|
|
3a22f66a9b | ||
|
|
0b1328156a | ||
|
|
bbbee1dd60 | ||
|
|
f9ad1a04db | ||
|
|
a31ae2e44a | ||
|
|
0afc673b17 | ||
|
|
4df92eda05 | ||
|
|
79d5d6d37a | ||
|
|
3f381f546e | ||
|
|
e9791d7f37 | ||
|
|
402c7439d7 | ||
|
|
dba741d61d | ||
|
|
6973da5c32 | ||
|
|
74db2a4213 | ||
|
|
48eeef98d8 | ||
|
|
93fe5cefbd | ||
|
|
34def82866 | ||
|
|
926938a039 | ||
|
|
f8e8d598bf | ||
|
|
7481323078 | ||
|
|
9994ae3c1c | ||
|
|
665d5c5112 | ||
|
|
dac3432cdb | ||
|
|
ba56714719 | ||
|
|
9a0d0f00e9 | ||
|
|
a86b5e4738 | ||
|
|
0a3b7b60f6 | ||
|
|
c1985baed2 | ||
|
|
8db7163070 | ||
|
|
fe501ad8d1 | ||
|
|
d5bb0a8d36 | ||
|
|
d140b83ae9 | ||
|
|
e55ab99292 | ||
|
|
aebe831622 | ||
|
|
ae9830cdb8 | ||
|
|
49325fc6ab | ||
|
|
2d4c5f915a | ||
|
|
db75b85d57 | ||
|
|
573fae7275 | ||
|
|
ca840d66bb | ||
|
|
9377fa9653 | ||
|
|
67ef47a8a1 | ||
|
|
03f8ac57f0 | ||
|
|
867a57389a | ||
|
|
777f60f39b | ||
|
|
a76db752a7 | ||
|
|
31b09e96f2 | ||
|
|
6c198765a0 | ||
|
|
c1629ee231 | ||
|
|
cc33e97870 | ||
|
|
e45eef02bb | ||
|
|
258655da08 | ||
|
|
4403c91b6b | ||
|
|
c8db463d1f | ||
|
|
3d280aa419 | ||
|
|
cf0276b9ab | ||
|
|
3e3199a800 | ||
|
|
fe2a27367a | ||
|
|
e6bc0b3edb | ||
|
|
28e31a2d58 | ||
|
|
13cfd61cf5 | ||
|
|
5696c2b695 | ||
|
|
59e2a5754d | ||
|
|
9b5ef0220a | ||
|
|
e7e8b2803e | ||
|
|
922ed1345c | ||
|
|
e0a1fba241 | ||
|
|
6b80cedde4 | ||
|
|
9aa5fc8a74 | ||
|
|
2e429f17a6 | ||
|
|
8453ca8594 | ||
|
|
bbb6f01707 | ||
|
|
acb2548dde | ||
|
|
698a904a22 | ||
|
|
eaaceb40bb | ||
|
|
ebd6a4561f | ||
|
|
85df023bba | ||
|
|
553654650e | ||
|
|
e518cdac15 | ||
|
|
bde568706e | ||
|
|
e85e92b0ff | ||
|
|
41cad1362d | ||
|
|
87a0e3609f | ||
|
|
9d191f041c | ||
|
|
71c5f3cb2f | ||
|
|
2853609484 | ||
|
|
95c11ec5a9 | ||
|
|
c1fe93aaa4 | ||
|
|
f30a96a18f | ||
|
|
4b75f4e92a | ||
|
|
7e084d9fdf | ||
|
|
42bf584150 | ||
|
|
e223da31a4 | ||
|
|
4338c2574e | ||
|
|
da71b1ee45 | ||
|
|
9c08284967 | ||
|
|
c7550f83fb | ||
|
|
16228bba2f | ||
|
|
c43ee4db7e | ||
|
|
9a1cb103a1 | ||
|
|
4cb0b6cbbc | ||
|
|
eb95f61acb | ||
|
|
f52d8ccc95 | ||
|
|
58ea7bd7b9 | ||
|
|
2355503bd2 | ||
|
|
abb31f1d1f | ||
|
|
766c19dcb0 | ||
|
|
12eef27677 | ||
|
|
38895e681e | ||
|
|
900210a375 | ||
|
|
58df0162f1 | ||
|
|
a999c520ac | ||
|
|
c0c737ac56 | ||
|
|
270adfa61a | ||
|
|
a04cc5ff8b | ||
|
|
6f4c90a4f5 | ||
|
|
b4efbcf3fe | ||
|
|
1f1c3ec263 | ||
|
|
7a5b7589b9 | ||
|
|
4918c86552 | ||
|
|
880387ae38 | ||
|
|
daa386bb15 | ||
|
|
c89e1255ba | ||
|
|
f9fd93f0a3 | ||
|
|
91e1c35cfa | ||
|
|
600918d9e3 | ||
|
|
7635714732 | ||
|
|
0918584865 | ||
|
|
12258aa8d9 | ||
|
|
3a4f262765 | ||
|
|
ee8460486f | ||
|
|
67d037d373 | ||
|
|
97619771cf | ||
|
|
741abf8b86 | ||
|
|
84d57ed8c5 | ||
|
|
4bccfc4806 | ||
|
|
3ccd20f0f6 | ||
|
|
92f5818ca0 | ||
|
|
e90d5a5074 | ||
|
|
a23f780b1a | ||
|
|
d0892198a1 | ||
|
|
a72c79b3a9 | ||
|
|
b3d05abc41 | ||
|
|
ad8fb24595 | ||
|
|
5a8f745ca5 | ||
|
|
28c12c9c14 | ||
|
|
71a315102d | ||
|
|
b0a4d9c9aa | ||
|
|
591fa693cc | ||
|
|
4bf5fcd9d1 | ||
|
|
9982959fbe | ||
|
|
f421676039 | ||
|
|
e80a48c537 | ||
|
|
03e17c4ce6 | ||
|
|
2b5d51056d | ||
|
|
d3bcab99b9 | ||
|
|
1c39e0dcf6 | ||
|
|
3de4398f5b | ||
|
|
69e4da403e | ||
|
|
f5927ac8eb | ||
|
|
72eb02b9d3 | ||
|
|
4a7ed293d5 | ||
|
|
cbf35099d6 | ||
|
|
f3f860a2d6 | ||
|
|
35f8cbccc5 | ||
|
|
78cad4d168 | ||
|
|
4925467fdb | ||
|
|
d81b10f441 | ||
|
|
8e7e0d6ec7 | ||
|
|
e9c3056dbd | ||
|
|
c39393741e | ||
|
|
be73d23db2 | ||
|
|
789cb443e4 | ||
|
|
81ef7a1088 | ||
|
|
e5c7a85edb | ||
|
|
624d29080c | ||
|
|
0a0af171d2 | ||
|
|
5741b91970 | ||
|
|
e85324c770 | ||
|
|
119df3803b | ||
|
|
08bc82d162 | ||
|
|
7371e54788 | ||
|
|
71f9b0e1ed | ||
|
|
56b88ef572 | ||
|
|
5ada8050d9 | ||
|
|
37230a1faa | ||
|
|
83a13b92aa | ||
|
|
e1688b470b | ||
|
|
e5a629ee54 | ||
|
|
5cab53912c | ||
|
|
059ad35b23 | ||
|
|
170abc518b | ||
|
|
aebd27b4dc | ||
|
|
afaf9baa48 | ||
|
|
7eaaab9be9 | ||
|
|
d590b1f16e | ||
|
|
0913dc2564 | ||
|
|
bf407340fb | ||
|
|
ada5cfff6b | ||
|
|
56b2913b62 | ||
|
|
88f5f2f15c | ||
|
|
148228909a | ||
|
|
44cbbcf605 | ||
|
|
f45f0fd74f | ||
|
|
7512891e63 | ||
|
|
4ae92ac4ef | ||
|
|
3e1e7c423b | ||
|
|
ba9bfa0f98 | ||
|
|
e1ad05c6ba | ||
|
|
9035de6e1c | ||
|
|
743b502b93 | ||
|
|
984dfdcac7 | ||
|
|
420cbcd0c4 | ||
|
|
d9dca06e83 | ||
|
|
95171846cd | ||
|
|
10c8501bb8 | ||
|
|
967f3abd77 | ||
|
|
2b9968a2f9 | ||
|
|
d97a5dfc16 | ||
|
|
f9ac8870bd | ||
|
|
9d379ca627 | ||
|
|
c6a4932afe |
+239
-52
@@ -1,4 +1,241 @@
|
||||
==============================================================================
|
||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||
==============================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
==============================================================================
|
||||
Software from third parties included in the LLVM Project:
|
||||
==============================================================================
|
||||
The LLVM Project contains third party software which is under different license
|
||||
terms. All such code will be identified clearly using at least one of two
|
||||
mechanisms:
|
||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||
`LICENSE` file at the top containing the specific license and restrictions
|
||||
which apply to that software, or
|
||||
2) It will contain specific license and restriction terms at the top of every
|
||||
file.
|
||||
|
||||
==============================================================================
|
||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||
==============================================================================
|
||||
|
||||
The software contained in this directory tree is dual licensed under both the
|
||||
University of Illinois "BSD-Like" license and the MIT license. As a user of
|
||||
@@ -14,7 +251,7 @@ software contained in this directory tree is included below.
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 1997-2016 Intel Corporation
|
||||
Copyright (c) 1997-2019 Intel Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
@@ -51,7 +288,7 @@ SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 1997-2016 Intel Corporation
|
||||
Copyright (c) 1997-2019 Intel Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -122,53 +359,3 @@ conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
ARM Limited
|
||||
|
||||
Software Grant License Agreement ("Agreement")
|
||||
|
||||
Except for the license granted herein to you, ARM Limited ("ARM") reserves all
|
||||
right, title, and interest in and to the Software (defined below).
|
||||
|
||||
Definition
|
||||
|
||||
"Software" means the code and documentation as well as any original work of
|
||||
authorship, including any modifications or additions to an existing work, that
|
||||
is intentionally submitted by ARM to llvm.org (http://llvm.org) ("LLVM") for
|
||||
inclusion in, or documentation of, any of the products owned or managed by LLVM
|
||||
(the "Work"). For the purposes of this definition, "submitted" means any form of
|
||||
electronic, verbal, or written communication sent to LLVM or its
|
||||
representatives, including but not limited to communication on electronic
|
||||
mailing lists, source code control systems, and issue tracking systems that are
|
||||
managed by, or on behalf of, LLVM for the purpose of discussing and improving
|
||||
the Work, but excluding communication that is conspicuously marked otherwise.
|
||||
|
||||
1. Grant of Copyright License. Subject to the terms and conditions of this
|
||||
Agreement, ARM hereby grants to you and to recipients of the Software
|
||||
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable copyright license to reproduce, prepare derivative
|
||||
works of, publicly display, publicly perform, sublicense, and distribute the
|
||||
Software and such derivative works.
|
||||
|
||||
2. Grant of Patent License. Subject to the terms and conditions of this
|
||||
Agreement, ARM hereby grants you and to recipients of the Software
|
||||
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable (except as stated in this section) patent license
|
||||
to make, have made, use, offer to sell, sell, import, and otherwise transfer
|
||||
the Work, where such license applies only to those patent claims licensable
|
||||
by ARM that are necessarily infringed by ARM's Software alone or by
|
||||
combination of the Software with the Work to which such Software was
|
||||
submitted. If any entity institutes patent litigation against ARM or any
|
||||
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that ARM's Software, or the Work to which ARM has contributed constitutes
|
||||
direct or contributory patent infringement, then any patent licenses granted
|
||||
to that entity under this Agreement for the Software or Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the software is
|
||||
provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
either express or implied, including, without limitation, any warranties or
|
||||
conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
+7
-14
@@ -133,7 +133,7 @@ Options for all Libraries
|
||||
Options for ``libomp``
|
||||
----------------------
|
||||
|
||||
**LIBOMP_ARCH** = ``aarch64|arm|i386|mic|mips|mips64|ppc64|ppc64le|x86_64``
|
||||
**LIBOMP_ARCH** = ``aarch64|arm|i386|mic|mips|mips64|ppc64|ppc64le|x86_64|riscv64``
|
||||
The default value for this option is chosen based on probing the compiler for
|
||||
architecture macros (e.g., is ``__x86_64__`` predefined by compiler?).
|
||||
|
||||
@@ -141,10 +141,6 @@ Options for ``libomp``
|
||||
Intel(R) Many Integrated Core Architecture (Intel(R) MIC Architecture) to
|
||||
build for. This value is ignored if **LIBOMP_ARCH** does not equal ``mic``.
|
||||
|
||||
**LIBOMP_OMP_VERSION** = ``50|45|40|30``
|
||||
OpenMP version to build for. Older versions will disable certain
|
||||
functionality and entry points.
|
||||
|
||||
**LIBOMP_LIB_TYPE** = ``normal|profile|stubs``
|
||||
Library type can be ``normal``, ``profile``, or ``stubs``.
|
||||
|
||||
@@ -192,9 +188,9 @@ Optional Features
|
||||
multi-node systems where a small ``CACHE_LINE`` setting leads to false sharing.
|
||||
|
||||
**LIBOMP_OMPT_SUPPORT** = ``ON|OFF``
|
||||
Include support for the OpenMP Tools Interface (OMPT).
|
||||
This option is supported and ``ON`` by default for x86, x86_64, AArch64, and
|
||||
PPC64 on Linux* and macOS*.
|
||||
Include support for the OpenMP Tools Interface (OMPT).
|
||||
This option is supported and ``ON`` by default for x86, x86_64, AArch64,
|
||||
PPC64 and RISCV64 on Linux* and macOS*.
|
||||
This option is ``OFF`` if this feature is not supported for the platform.
|
||||
|
||||
**LIBOMP_OMPT_OPTIONAL** = ``ON|OFF``
|
||||
@@ -225,9 +221,6 @@ These flags are **appended**, they do not overwrite any of the preset flags.
|
||||
**LIBOMP_CPPFLAGS** = <space-separated flags>
|
||||
Additional C preprocessor flags.
|
||||
|
||||
**LIBOMP_CFLAGS** = <space-separated flags>
|
||||
Additional C compiler flags.
|
||||
|
||||
**LIBOMP_CXXFLAGS** = <space-separated flags>
|
||||
Additional C++ compiler flags.
|
||||
|
||||
@@ -325,12 +318,12 @@ Advanced Builds with Various Options
|
||||
|
||||
$ cmake -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc -DCMAKE_Fortran_COMPILER=ifort -DLIBOMP_FORTRAN_MODULES=on ..
|
||||
|
||||
- Have CMake find the C/C++ compiler and specify additional flags for the C
|
||||
compiler, preprocessor, and C++ compiler.
|
||||
- Have CMake find the C/C++ compiler and specify additional flags for the
|
||||
preprocessor and C++ compiler.
|
||||
|
||||
.. code-blocks:: console
|
||||
|
||||
$ cmake -DLIBOMP_CFLAGS='-specific-flag' -DLIBOMP_CPPFLAGS='-DNEW_FEATURE=1 -DOLD_FEATURE=0' -DLIBOMP_CXXFLAGS='--one-specific-flag --two-specific-flag' ..
|
||||
$ cmake -DLIBOMP_CPPFLAGS='-DNEW_FEATURE=1 -DOLD_FEATURE=0' -DLIBOMP_CXXFLAGS='--one-specific-flag --two-specific-flag' ..
|
||||
|
||||
- Build the stubs library
|
||||
|
||||
|
||||
@@ -18,8 +18,12 @@ if (NOT OpenMP_Found)
|
||||
set(OpenMP_CXX_FLAGS "-fopenmp")
|
||||
endif()
|
||||
|
||||
set(C_FLAGS ${flags} ${OpenMP_C_FLAGS})
|
||||
set(CXX_FLAGS ${flags} ${OpenMP_CXX_FLAGS})
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
set(C_FLAGS "${OpenMP_C_FLAGS} ${CMAKE_THREAD_LIBS_INIT}")
|
||||
set(CXX_FLAGS "${OpenMP_CXX_FLAGS} ${CMAKE_THREAD_LIBS_INIT}")
|
||||
|
||||
# TODO: Implement blockaddress in GlobalISel and remove this flag!
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if (${OPENMP_STANDALONE_BUILD})
|
||||
if (OPENMP_STANDALONE_BUILD)
|
||||
# From HandleLLVMOptions.cmake
|
||||
function(append_if condition value)
|
||||
if (${condition})
|
||||
@@ -9,8 +9,27 @@ if (${OPENMP_STANDALONE_BUILD})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
if (${OPENMP_ENABLE_WERROR})
|
||||
# MSVC and clang-cl in compatibility mode map -Wall to -Weverything.
|
||||
# TODO: LLVM adds /W4 instead, check if that works for the OpenMP runtimes.
|
||||
if (NOT MSVC)
|
||||
append_if(OPENMP_HAVE_WALL_FLAG "-Wall" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
if (OPENMP_ENABLE_WERROR)
|
||||
append_if(OPENMP_HAVE_WERROR_FLAG "-Werror" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
|
||||
append_if(OPENMP_HAVE_STD_CPP11_FLAG "-std=c++11" CMAKE_CXX_FLAGS)
|
||||
# Additional warnings that are not enabled by -Wall.
|
||||
append_if(OPENMP_HAVE_WCAST_QUAL_FLAG "-Wcast-qual" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_if(OPENMP_HAVE_WFORMAT_PEDANTIC_FLAG "-Wformat-pedantic" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_if(OPENMP_HAVE_WIMPLICIT_FALLTHROUGH_FLAG "-Wimplicit-fallthrough" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_if(OPENMP_HAVE_WSIGN_COMPARE_FLAG "-Wsign-compare" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
|
||||
# Warnings that we want to disable because they are too verbose or fragile.
|
||||
append_if(OPENMP_HAVE_WNO_EXTRA_FLAG "-Wno-extra" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_if(OPENMP_HAVE_WNO_PEDANTIC_FLAG "-Wno-pedantic" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_if(OPENMP_HAVE_WNO_MAYBE_UNINITIALIZED_FLAG "-Wno-maybe-uninitialized" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
|
||||
append_if(OPENMP_HAVE_STD_GNUPP11_FLAG "-std=gnu++11" CMAKE_CXX_FLAGS)
|
||||
if (NOT OPENMP_HAVE_STD_GNUPP11_FLAG)
|
||||
append_if(OPENMP_HAVE_STD_CPP11_FLAG "-std=c++11" CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
|
||||
@@ -99,7 +99,7 @@ if (${OPENMP_STANDALONE_BUILD})
|
||||
# project is built which is too late for detecting the compiler...
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/DetectTestCompiler)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} ${CMAKE_CURRENT_LIST_DIR}/DetectTestCompiler
|
||||
COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/DetectTestCompiler
|
||||
-DCMAKE_C_COMPILER=${OPENMP_TEST_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${OPENMP_TEST_CXX_COMPILER}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/DetectTestCompiler
|
||||
@@ -120,8 +120,16 @@ else()
|
||||
set(OPENMP_TEST_COMPILER_VERSION "${LLVM_VERSION}")
|
||||
set(OPENMP_TEST_COMPILER_VERSION_MAJOR "${LLVM_MAJOR_VERSION}")
|
||||
set(OPENMP_TEST_COMPILER_VERSION_MAJOR_MINOR "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}")
|
||||
# Unfortunately the top-level cmake/config-ix.cmake file mangles CMake's
|
||||
# CMAKE_THREAD_LIBS_INIT variable from the FindThreads package, so work
|
||||
# around that, until it is fixed there.
|
||||
if("${CMAKE_THREAD_LIBS_INIT}" STREQUAL "-lpthread")
|
||||
set(OPENMP_TEST_COMPILER_THREAD_FLAGS "-pthread")
|
||||
else()
|
||||
set(OPENMP_TEST_COMPILER_THREAD_FLAGS "${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
# TODO: Implement blockaddress in GlobalISel and remove this flag!
|
||||
set(OPENMP_TEST_COMPILER_OPENMP_FLAGS "-fopenmp -fno-experimental-isel")
|
||||
set(OPENMP_TEST_COMPILER_OPENMP_FLAGS "-fopenmp ${OPENMP_TEST_COMPILER_THREAD_FLAGS} -fno-experimental-isel")
|
||||
endif()
|
||||
|
||||
# Function to set compiler features for use in lit.
|
||||
@@ -147,7 +155,7 @@ function(add_openmp_testsuite target comment)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_parse_arguments(ARG "" "" "DEPENDS" ${ARGN})
|
||||
cmake_parse_arguments(ARG "" "" "DEPENDS;ARGS" ${ARGN})
|
||||
# EXCLUDE_FROM_ALL excludes the test ${target} out of check-openmp.
|
||||
if (NOT EXCLUDE_FROM_ALL)
|
||||
# Register the testsuites and depends for the check-openmp rule.
|
||||
@@ -156,8 +164,9 @@ function(add_openmp_testsuite target comment)
|
||||
endif()
|
||||
|
||||
if (${OPENMP_STANDALONE_BUILD})
|
||||
set(LIT_ARGS ${OPENMP_LIT_ARGS} ${ARG_ARGS})
|
||||
add_custom_target(${target}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${OPENMP_LLVM_LIT_EXECUTABLE} ${OPENMP_LIT_ARGS} ${ARG_UNPARSED_ARGUMENTS}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${OPENMP_LLVM_LIT_EXECUTABLE} ${LIT_ARGS} ${ARG_UNPARSED_ARGUMENTS}
|
||||
COMMENT ${comment}
|
||||
DEPENDS ${ARG_DEPENDS}
|
||||
${cmake_3_2_USES_TERMINAL}
|
||||
@@ -166,7 +175,8 @@ function(add_openmp_testsuite target comment)
|
||||
add_lit_testsuite(${target}
|
||||
${comment}
|
||||
${ARG_UNPARSED_ARGUMENTS}
|
||||
DEPENDS clang clang-headers FileCheck ${ARG_DEPENDS}
|
||||
DEPENDS clang clang-resource-headers FileCheck ${ARG_DEPENDS}
|
||||
ARGS ${ARG_ARGS}
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
+15
-3
@@ -1,6 +1,18 @@
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
check_c_compiler_flag(-Werror OPENMP_HAVE_WERROR_FLAG)
|
||||
check_cxx_compiler_flag(-Wall OPENMP_HAVE_WALL_FLAG)
|
||||
check_cxx_compiler_flag(-Werror OPENMP_HAVE_WERROR_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(-std=c++11 OPENMP_HAVE_STD_CPP11_FLAG)
|
||||
# Additional warnings that are not enabled by -Wall.
|
||||
check_cxx_compiler_flag(-Wcast-qual OPENMP_HAVE_WCAST_QUAL_FLAG)
|
||||
check_cxx_compiler_flag(-Wformat-pedantic OPENMP_HAVE_WFORMAT_PEDANTIC_FLAG)
|
||||
check_cxx_compiler_flag(-Wimplicit-fallthrough OPENMP_HAVE_WIMPLICIT_FALLTHROUGH_FLAG)
|
||||
check_cxx_compiler_flag(-Wsign-compare OPENMP_HAVE_WSIGN_COMPARE_FLAG)
|
||||
|
||||
# Warnings that we want to disable because they are too verbose or fragile.
|
||||
check_cxx_compiler_flag(-Wno-extra OPENMP_HAVE_WNO_EXTRA_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-pedantic OPENMP_HAVE_WNO_PEDANTIC_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-maybe-uninitialized OPENMP_HAVE_WNO_MAYBE_UNINITIALIZED_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(-std=gnu++11 OPENMP_HAVE_STD_GNUPP11_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++11 OPENMP_HAVE_STD_CPP11_FLAG)
|
||||
|
||||
+23
-12
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
@@ -20,6 +19,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules ${CMAKE_MODULE_P
|
||||
|
||||
if(OPENMP_STANDALONE_BUILD)
|
||||
# Build all libraries into a common place so that tests can find them.
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
@@ -40,17 +40,17 @@ set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} nvptx64-nvidia-cuda")
|
||||
# the list of supported targets in the current system.
|
||||
set (LIBOMPTARGET_SYSTEM_TARGETS "")
|
||||
|
||||
# Set base directories - required for lit to locate the tests.
|
||||
set(LIBOMPTARGET_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LIBOMPTARGET_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# If building this library in debug mode, we define a macro to enable
|
||||
# dumping progress messages at runtime.
|
||||
# Check whether using debug mode. In debug mode, allow dumping progress
|
||||
# messages at runtime by default. Otherwise, it can be enabled
|
||||
# independently using the LIBOMPTARGET_ENABLE_DEBUG option.
|
||||
string( TOLOWER "${CMAKE_BUILD_TYPE}" LIBOMPTARGET_CMAKE_BUILD_TYPE)
|
||||
if(LIBOMPTARGET_CMAKE_BUILD_TYPE MATCHES debug)
|
||||
option(LIBOMPTARGET_ENABLE_DEBUG "Allow debug output with the environment variable LIBOMPTARGET_DEBUG=1" ON)
|
||||
else()
|
||||
option(LIBOMPTARGET_ENABLE_DEBUG "Allow debug output with the environment variable LIBOMPTARGET_DEBUG=1" OFF)
|
||||
endif()
|
||||
if(LIBOMPTARGET_ENABLE_DEBUG)
|
||||
add_definitions(-DOMPTARGET_DEBUG)
|
||||
add_definitions(-g)
|
||||
add_definitions(-O0)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
@@ -65,6 +65,17 @@ if(NOT LIBOMPTARGET_LIBRARY_DIR)
|
||||
set(LIBOMPTARGET_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
# Definitions for testing, for reuse when testing libomptarget-nvptx.
|
||||
if(OPENMP_STANDALONE_BUILD)
|
||||
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src" CACHE STRING
|
||||
"Path to folder containing omp.h")
|
||||
set(LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src" CACHE STRING
|
||||
"Path to folder containing libomp.so")
|
||||
else()
|
||||
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src")
|
||||
endif()
|
||||
|
||||
|
||||
# Build offloading plugins and device RTLs if they are available.
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(deviceRTLs)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -112,6 +111,9 @@ mark_as_advanced(
|
||||
################################################################################
|
||||
# Looking for CUDA...
|
||||
################################################################################
|
||||
if (CUDA_TOOLKIT_ROOT_DIR)
|
||||
set(LIBOMPTARGET_CUDA_TOOLKIT_ROOT_DIR_PRESET TRUE)
|
||||
endif()
|
||||
find_package(CUDA QUIET)
|
||||
|
||||
set(LIBOMPTARGET_DEP_CUDA_FOUND ${CUDA_FOUND})
|
||||
@@ -158,3 +160,33 @@ find_package_handle_standard_args(
|
||||
LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBOMPTARGET_DEP_CUDA_DRIVER_LIBRARIES)
|
||||
|
||||
################################################################################
|
||||
# Looking for CUDA libdevice subdirectory
|
||||
#
|
||||
# Special case for Debian/Ubuntu to have nvidia-cuda-toolkit work
|
||||
# out of the box. More info on http://bugs.debian.org/882505
|
||||
################################################################################
|
||||
|
||||
set(LIBOMPTARGET_CUDA_LIBDEVICE_SUBDIR nvvm/libdevice)
|
||||
|
||||
# Don't alter CUDA_TOOLKIT_ROOT_DIR if the user specified it, if a value was
|
||||
# already cached for it, or if it already has libdevice. Otherwise, on
|
||||
# Debian/Ubuntu, look where the nvidia-cuda-toolkit package normally installs
|
||||
# libdevice.
|
||||
if (NOT LIBOMPTARGET_CUDA_TOOLKIT_ROOT_DIR_PRESET AND
|
||||
NOT EXISTS
|
||||
"${CUDA_TOOLKIT_ROOT_DIR}/${LIBOMPTARGET_CUDA_LIBDEVICE_SUBDIR}")
|
||||
find_program(LSB_RELEASE lsb_release)
|
||||
if (LSB_RELEASE)
|
||||
execute_process(COMMAND ${LSB_RELEASE} -is
|
||||
OUTPUT_VARIABLE LSB_RELEASE_ID
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(candidate_dir /usr/lib/cuda)
|
||||
if ((LSB_RELEASE_ID STREQUAL "Debian" OR LSB_RELEASE_ID STREQUAL "Ubuntu")
|
||||
AND EXISTS "${candidate_dir}/${LIBOMPTARGET_CUDA_LIBDEVICE_SUBDIR}")
|
||||
set(CUDA_TOOLKIT_ROOT_DIR "${candidate_dir}" CACHE PATH
|
||||
"Toolkit location." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -79,7 +78,7 @@ endfunction()
|
||||
|
||||
# These flags are required to emit LLVM Bitcode. We check them together because
|
||||
# if any of them are not supported, there is no point in finding out which are.
|
||||
set(compiler_flags_required -emit-llvm -O1 --cuda-device-only --cuda-path=${CUDA_TOOLKIT_ROOT_DIR})
|
||||
set(compiler_flags_required -emit-llvm -O1 --cuda-device-only -std=c++11 --cuda-path=${CUDA_TOOLKIT_ROOT_DIR})
|
||||
set(compiler_flags_required_src "extern \"C\" __device__ int thread() { return threadIdx.x; }")
|
||||
check_bitcode_compilation(LIBOMPTARGET_NVPTX_CUDA_COMPILER_SUPPORTS_FLAGS_REQUIRED "${compiler_flags_required_src}" ${compiler_flags_required})
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
+142
-126
@@ -1,18 +1,14 @@
|
||||
//===------- interface.h - NVPTX OpenMP interface definitions ---- CUDA -*-===//
|
||||
//===------- interface.h - OpenMP interface definitions ---------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains debug macros to be used in the application.
|
||||
//
|
||||
// This file contains all the definitions that are relevant to
|
||||
// the interface. The first section contains the interface as
|
||||
// declared by OpenMP. A second section includes library private calls
|
||||
// (mostly debug, temporary?) The third section includes the compiler
|
||||
// declared by OpenMP. The second section includes the compiler
|
||||
// specific interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -20,6 +16,12 @@
|
||||
#ifndef _INTERFACES_H_
|
||||
#define _INTERFACES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#include "nvptx/src/nvptx_interface.h"
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OpenMP interface
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -88,18 +90,6 @@ EXTERN int omp_is_initial_device(void);
|
||||
EXTERN int omp_get_initial_device(void);
|
||||
EXTERN int omp_get_max_task_priority(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OMPTARGET_NVPTX private (debug / temportary?) interface
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// for debug
|
||||
EXTERN void __kmpc_print_str(char *title);
|
||||
EXTERN void __kmpc_print_title_int(char *title, int data);
|
||||
EXTERN void __kmpc_print_index(char *title, int i);
|
||||
EXTERN void __kmpc_print_int(int data);
|
||||
EXTERN void __kmpc_print_double(double data);
|
||||
EXTERN void __kmpc_print_address_int64(int64_t data);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// file below is swiped from kmpc host interface
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -116,6 +106,8 @@ typedef enum kmp_sched_t {
|
||||
kmp_sched_runtime = 37,
|
||||
kmp_sched_auto = 38,
|
||||
|
||||
kmp_sched_static_balanced_chunk = 45,
|
||||
|
||||
kmp_sched_static_ordered = 65,
|
||||
kmp_sched_static_nochunk_ordered = 66,
|
||||
kmp_sched_dynamic_ordered = 67,
|
||||
@@ -168,8 +160,36 @@ typedef enum kmp_sched_t {
|
||||
|
||||
} kmp_sched_t;
|
||||
|
||||
/*!
|
||||
* Enum for accesseing the reserved_2 field of the ident_t struct below.
|
||||
*/
|
||||
enum {
|
||||
/*! Bit set to 1 when in SPMD mode. */
|
||||
KMP_IDENT_SPMD_MODE = 0x01,
|
||||
/*! Bit set to 1 when a simplified runtime is used. */
|
||||
KMP_IDENT_SIMPLE_RT_MODE = 0x02,
|
||||
};
|
||||
|
||||
/*!
|
||||
* The ident structure that describes a source location.
|
||||
* The struct is identical to the one in the kmp.h file.
|
||||
* We maintain the same data structure for compatibility.
|
||||
*/
|
||||
typedef int kmp_int32;
|
||||
typedef struct ident {
|
||||
kmp_int32 reserved_1; /**< might be used in Fortran; see above */
|
||||
kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags; KMP_IDENT_KMPC
|
||||
identifies this union member */
|
||||
kmp_int32 reserved_2; /**< not really used in Fortran any more; see above */
|
||||
kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for C++ */
|
||||
char const *psource; /**< String describing the source location.
|
||||
The string is composed of semi-colon separated fields
|
||||
which describe the source file, the function and a pair
|
||||
of line numbers that delimit the construct. */
|
||||
} ident_t;
|
||||
|
||||
// parallel defs
|
||||
typedef void kmp_Indent;
|
||||
typedef ident_t kmp_Ident;
|
||||
typedef void (*kmp_ParFctPtr)(int32_t *global_tid, int32_t *bound_tid, ...);
|
||||
typedef void (*kmp_ReductFctPtr)(void *lhsData, void *rhsData);
|
||||
typedef void (*kmp_InterWarpCopyFctPtr)(void *src, int32_t warp_num);
|
||||
@@ -181,6 +201,7 @@ typedef void (*kmp_CopyToScratchpadFctPtr)(void *reduceData, void *scratchpad,
|
||||
typedef void (*kmp_LoadReduceFctPtr)(void *reduceData, void *scratchpad,
|
||||
int32_t index, int32_t width,
|
||||
int32_t reduce);
|
||||
typedef void (*kmp_ListGlobalFctPtr)(void *buffer, int idx, void *reduce_data);
|
||||
|
||||
// task defs
|
||||
typedef struct kmp_TaskDescr kmp_TaskDescr;
|
||||
@@ -191,68 +212,31 @@ typedef struct kmp_TaskDescr {
|
||||
int32_t partId; // unused
|
||||
kmp_TaskFctPtr destructors; // destructor of c++ first private
|
||||
} kmp_TaskDescr;
|
||||
// task dep defs
|
||||
#define KMP_TASKDEP_IN 0x1u
|
||||
#define KMP_TASKDEP_OUT 0x2u
|
||||
typedef struct kmp_TaskDep_Public {
|
||||
void *addr;
|
||||
size_t len;
|
||||
uint8_t flags; // bit 0: in, bit 1: out
|
||||
} kmp_TaskDep_Public;
|
||||
|
||||
// flags that interpret the interface part of tasking flags
|
||||
#define KMP_TASK_IS_TIED 0x1
|
||||
#define KMP_TASK_FINAL 0x2
|
||||
#define KMP_TASK_MERGED_IF0 0x4 /* unused */
|
||||
#define KMP_TASK_DESTRUCTOR_THUNK 0x8
|
||||
|
||||
// flags for task setup return
|
||||
#define KMP_CURRENT_TASK_NOT_SUSPENDED 0
|
||||
#define KMP_CURRENT_TASK_SUSPENDED 1
|
||||
|
||||
// sync defs
|
||||
typedef int32_t kmp_CriticalName[8];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// flags for kstate (all bits initially off)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// first 2 bits used by kmp_Reduction (defined in kmp_reduction.cpp)
|
||||
#define KMP_REDUCTION_MASK 0x3
|
||||
#define KMP_SKIP_NEXT_CALL 0x4
|
||||
#define KMP_SKIP_NEXT_CANCEL_BARRIER 0x8
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// external interface
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// query
|
||||
EXTERN int32_t __kmpc_global_num_threads(kmp_Indent *loc); // missing
|
||||
EXTERN int32_t __kmpc_bound_thread_num(kmp_Indent *loc); // missing
|
||||
EXTERN int32_t __kmpc_bound_num_threads(kmp_Indent *loc); // missing
|
||||
EXTERN int32_t __kmpc_in_parallel(kmp_Indent *loc); // missing
|
||||
|
||||
// parallel
|
||||
EXTERN int32_t __kmpc_global_thread_num(kmp_Indent *loc);
|
||||
EXTERN void __kmpc_push_num_threads(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_global_thread_num(kmp_Ident *loc);
|
||||
EXTERN void __kmpc_push_num_threads(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t num_threads);
|
||||
// simd
|
||||
EXTERN void __kmpc_push_simd_limit(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_push_simd_limit(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t simd_limit);
|
||||
// aee ... not supported
|
||||
// EXTERN void __kmpc_fork_call(kmp_Indent *loc, int32_t argc, kmp_ParFctPtr
|
||||
// EXTERN void __kmpc_fork_call(kmp_Ident *loc, int32_t argc, kmp_ParFctPtr
|
||||
// microtask, ...);
|
||||
EXTERN void __kmpc_serialized_parallel(kmp_Indent *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_end_serialized_parallel(kmp_Indent *loc,
|
||||
EXTERN void __kmpc_serialized_parallel(kmp_Ident *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_end_serialized_parallel(kmp_Ident *loc,
|
||||
uint32_t global_tid);
|
||||
EXTERN uint16_t __kmpc_parallel_level(kmp_Indent *loc, uint32_t global_tid);
|
||||
EXTERN uint16_t __kmpc_parallel_level(kmp_Ident *loc, uint32_t global_tid);
|
||||
|
||||
// proc bind
|
||||
EXTERN void __kmpc_push_proc_bind(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_push_proc_bind(kmp_Ident *loc, uint32_t global_tid,
|
||||
int proc_bind);
|
||||
EXTERN int omp_get_num_places(void);
|
||||
EXTERN int omp_get_place_num_procs(int place_num);
|
||||
@@ -262,52 +246,52 @@ EXTERN int omp_get_partition_num_places(void);
|
||||
EXTERN void omp_get_partition_place_nums(int *place_nums);
|
||||
|
||||
// for static (no chunk or chunk)
|
||||
EXTERN void __kmpc_for_static_init_4(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_4(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN void __kmpc_for_static_init_4u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_4u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
uint32_t *plower, uint32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN void __kmpc_for_static_init_8(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_8(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk);
|
||||
EXTERN void __kmpc_for_static_init_8u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_8u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter1,
|
||||
uint64_t *plower, uint64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_4_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4u_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_4u_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
uint32_t *plower, uint32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_8_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8u_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_8u_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t *plastiter1,
|
||||
uint64_t *plower, uint64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4_simple_generic(kmp_Indent *loc,
|
||||
void __kmpc_for_static_init_4_simple_generic(kmp_Ident *loc,
|
||||
int32_t global_tid, int32_t sched,
|
||||
int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper,
|
||||
@@ -315,11 +299,11 @@ void __kmpc_for_static_init_4_simple_generic(kmp_Indent *loc,
|
||||
int32_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4u_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t sched, int32_t *plastiter,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t sched, int32_t *plastiter,
|
||||
uint32_t *plower, uint32_t *pupper, int32_t *pstride, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8_simple_generic(kmp_Indent *loc,
|
||||
void __kmpc_for_static_init_8_simple_generic(kmp_Ident *loc,
|
||||
int32_t global_tid, int32_t sched,
|
||||
int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper,
|
||||
@@ -327,57 +311,61 @@ void __kmpc_for_static_init_8_simple_generic(kmp_Indent *loc,
|
||||
int64_t chunk);
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8u_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t sched, int32_t *plastiter1,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t sched, int32_t *plastiter1,
|
||||
uint64_t *plower, uint64_t *pupper, int64_t *pstride, int64_t incr,
|
||||
int64_t chunk);
|
||||
|
||||
EXTERN void __kmpc_for_static_fini(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_for_static_fini(kmp_Ident *loc, int32_t global_tid);
|
||||
|
||||
// for dynamic
|
||||
EXTERN void __kmpc_dispatch_init_4(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_dispatch_init_4(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int32_t lower, int32_t upper,
|
||||
int32_t incr, int32_t chunk);
|
||||
EXTERN void __kmpc_dispatch_init_4u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_dispatch_init_4u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, uint32_t lower,
|
||||
uint32_t upper, int32_t incr,
|
||||
int32_t chunk);
|
||||
EXTERN void __kmpc_dispatch_init_8(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_dispatch_init_8(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, int64_t lower, int64_t upper,
|
||||
int64_t incr, int64_t chunk);
|
||||
EXTERN void __kmpc_dispatch_init_8u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_dispatch_init_8u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t sched, uint64_t lower,
|
||||
uint64_t upper, int64_t incr,
|
||||
int64_t chunk);
|
||||
|
||||
EXTERN int __kmpc_dispatch_next_4(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int __kmpc_dispatch_next_4(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t *plastiter, int32_t *plower,
|
||||
int32_t *pupper, int32_t *pstride);
|
||||
EXTERN int __kmpc_dispatch_next_4u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int __kmpc_dispatch_next_4u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t *plastiter, uint32_t *plower,
|
||||
uint32_t *pupper, int32_t *pstride);
|
||||
EXTERN int __kmpc_dispatch_next_8(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int __kmpc_dispatch_next_8(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t *plastiter, int64_t *plower,
|
||||
int64_t *pupper, int64_t *pstride);
|
||||
EXTERN int __kmpc_dispatch_next_8u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int __kmpc_dispatch_next_8u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t *plastiter, uint64_t *plower,
|
||||
uint64_t *pupper, int64_t *pstride);
|
||||
|
||||
EXTERN void __kmpc_dispatch_fini_4(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_4u(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_8(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_8u(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_4(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_4u(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_8(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_dispatch_fini_8u(kmp_Ident *loc, int32_t global_tid);
|
||||
|
||||
// Support for reducing conditional lastprivate variables
|
||||
EXTERN void __kmpc_reduce_conditional_lastprivate(kmp_Indent *loc,
|
||||
EXTERN void __kmpc_reduce_conditional_lastprivate(kmp_Ident *loc,
|
||||
int32_t global_tid,
|
||||
int32_t varNum, void *array);
|
||||
|
||||
// reduction
|
||||
EXTERN void __kmpc_nvptx_end_reduce(int32_t global_tid);
|
||||
EXTERN void __kmpc_nvptx_end_reduce_nowait(int32_t global_tid);
|
||||
EXTERN int32_t __kmpc_nvptx_parallel_reduce_nowait(
|
||||
EXTERN __attribute__((deprecated)) int32_t __kmpc_nvptx_parallel_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct);
|
||||
EXTERN int32_t __kmpc_nvptx_parallel_reduce_nowait_v2(
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t num_vars, size_t reduce_size,
|
||||
void *reduce_data, kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct);
|
||||
EXTERN int32_t __kmpc_nvptx_parallel_reduce_nowait_simple_spmd(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct);
|
||||
@@ -387,6 +375,12 @@ EXTERN int32_t __kmpc_nvptx_parallel_reduce_nowait_simple_generic(
|
||||
EXTERN int32_t __kmpc_nvptx_simd_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct);
|
||||
EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait_v2(
|
||||
kmp_Ident *loc, int32_t global_tid, void *global_buffer,
|
||||
int32_t num_of_records, void *reduce_data, kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct, kmp_ListGlobalFctPtr lgcpyFct,
|
||||
kmp_ListGlobalFctPtr lgredFct, kmp_ListGlobalFctPtr glcpyFct,
|
||||
kmp_ListGlobalFctPtr glredFct);
|
||||
EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct,
|
||||
@@ -399,67 +393,75 @@ EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait_simple_generic(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct,
|
||||
kmp_CopyToScratchpadFctPtr sratchFct, kmp_LoadReduceFctPtr ldFct);
|
||||
EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait_simple(kmp_Ident *loc,
|
||||
int32_t global_tid,
|
||||
kmp_CriticalName *crit);
|
||||
EXTERN void __kmpc_nvptx_teams_end_reduce_nowait_simple(kmp_Ident *loc,
|
||||
int32_t global_tid,
|
||||
kmp_CriticalName *crit);
|
||||
EXTERN int32_t __kmpc_shuffle_int32(int32_t val, int16_t delta, int16_t size);
|
||||
EXTERN int64_t __kmpc_shuffle_int64(int64_t val, int16_t delta, int16_t size);
|
||||
|
||||
// sync barrier
|
||||
EXTERN void __kmpc_barrier(kmp_Indent *loc_ref, int32_t tid);
|
||||
EXTERN void __kmpc_barrier_simple_spmd(kmp_Indent *loc_ref, int32_t tid);
|
||||
EXTERN void __kmpc_barrier_simple_generic(kmp_Indent *loc_ref, int32_t tid);
|
||||
EXTERN int32_t __kmpc_cancel_barrier(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_barrier(kmp_Ident *loc_ref, int32_t tid);
|
||||
EXTERN void __kmpc_barrier_simple_spmd(kmp_Ident *loc_ref, int32_t tid);
|
||||
EXTERN void __kmpc_barrier_simple_generic(kmp_Ident *loc_ref, int32_t tid);
|
||||
EXTERN int32_t __kmpc_cancel_barrier(kmp_Ident *loc, int32_t global_tid);
|
||||
|
||||
// single
|
||||
EXTERN int32_t __kmpc_single(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_single(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN int32_t __kmpc_single(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_single(kmp_Ident *loc, int32_t global_tid);
|
||||
|
||||
// sync
|
||||
EXTERN int32_t __kmpc_master(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_master(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_ordered(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_ordered(kmp_Indent *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_critical(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_master(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_master(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_ordered(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_end_ordered(kmp_Ident *loc, int32_t global_tid);
|
||||
EXTERN void __kmpc_critical(kmp_Ident *loc, int32_t global_tid,
|
||||
kmp_CriticalName *crit);
|
||||
EXTERN void __kmpc_end_critical(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_end_critical(kmp_Ident *loc, int32_t global_tid,
|
||||
kmp_CriticalName *crit);
|
||||
EXTERN void __kmpc_flush(kmp_Indent *loc);
|
||||
EXTERN void __kmpc_flush(kmp_Ident *loc);
|
||||
|
||||
// vote
|
||||
EXTERN int32_t __kmpc_warp_active_thread_mask();
|
||||
EXTERN __kmpc_impl_lanemask_t __kmpc_warp_active_thread_mask();
|
||||
// syncwarp
|
||||
EXTERN void __kmpc_syncwarp(__kmpc_impl_lanemask_t);
|
||||
|
||||
// tasks
|
||||
EXTERN kmp_TaskDescr *__kmpc_omp_task_alloc(kmp_Indent *loc,
|
||||
EXTERN kmp_TaskDescr *__kmpc_omp_task_alloc(kmp_Ident *loc,
|
||||
uint32_t global_tid, int32_t flag,
|
||||
size_t sizeOfTaskInclPrivate,
|
||||
size_t sizeOfSharedTable,
|
||||
kmp_TaskFctPtr sub);
|
||||
EXTERN int32_t __kmpc_omp_task(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_task(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newLegacyTaskDescr);
|
||||
EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newLegacyTaskDescr,
|
||||
int32_t depNum, void *depList,
|
||||
int32_t noAliasDepNum,
|
||||
void *noAliasDepList);
|
||||
EXTERN void __kmpc_omp_task_begin_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_task_begin_if0(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newLegacyTaskDescr);
|
||||
EXTERN void __kmpc_omp_task_complete_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_task_complete_if0(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newLegacyTaskDescr);
|
||||
EXTERN void __kmpc_omp_wait_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_wait_deps(kmp_Ident *loc, uint32_t global_tid,
|
||||
int32_t depNum, void *depList,
|
||||
int32_t noAliasDepNum, void *noAliasDepList);
|
||||
EXTERN void __kmpc_taskgroup(kmp_Indent *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_end_taskgroup(kmp_Indent *loc, uint32_t global_tid);
|
||||
EXTERN int32_t __kmpc_omp_taskyield(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_taskgroup(kmp_Ident *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_end_taskgroup(kmp_Ident *loc, uint32_t global_tid);
|
||||
EXTERN int32_t __kmpc_omp_taskyield(kmp_Ident *loc, uint32_t global_tid,
|
||||
int end_part);
|
||||
EXTERN int32_t __kmpc_omp_taskwait(kmp_Indent *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_taskloop(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_taskwait(kmp_Ident *loc, uint32_t global_tid);
|
||||
EXTERN void __kmpc_taskloop(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr, int if_val,
|
||||
uint64_t *lb, uint64_t *ub, int64_t st, int nogroup,
|
||||
int32_t sched, uint64_t grainsize, void *task_dup);
|
||||
|
||||
// cancel
|
||||
EXTERN int32_t __kmpc_cancellationpoint(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_cancellationpoint(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t cancelVal);
|
||||
EXTERN int32_t __kmpc_cancel(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_cancel(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t cancelVal);
|
||||
|
||||
// non standard
|
||||
@@ -468,17 +470,20 @@ EXTERN void __kmpc_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime);
|
||||
EXTERN void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized);
|
||||
EXTERN void __kmpc_spmd_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime,
|
||||
int16_t RequiresDataSharing);
|
||||
EXTERN void __kmpc_spmd_kernel_deinit();
|
||||
EXTERN __attribute__((deprecated)) void __kmpc_spmd_kernel_deinit();
|
||||
EXTERN void __kmpc_spmd_kernel_deinit_v2(int16_t RequiresOMPRuntime);
|
||||
EXTERN void __kmpc_kernel_prepare_parallel(void *WorkFn,
|
||||
int16_t IsOMPRuntimeInitialized);
|
||||
EXTERN bool __kmpc_kernel_parallel(void **WorkFn,
|
||||
int16_t IsOMPRuntimeInitialized);
|
||||
EXTERN void __kmpc_kernel_end_parallel();
|
||||
EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer, uint32_t Mask,
|
||||
EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer,
|
||||
__kmpc_impl_lanemask_t Mask,
|
||||
bool *IsFinal,
|
||||
int32_t *LaneSource);
|
||||
EXTERN void __kmpc_kernel_end_convergent_parallel(void *buffer);
|
||||
EXTERN bool __kmpc_kernel_convergent_simd(void *buffer, uint32_t Mask,
|
||||
EXTERN bool __kmpc_kernel_convergent_simd(void *buffer,
|
||||
__kmpc_impl_lanemask_t Mask,
|
||||
bool *IsFinal, int32_t *LaneSource,
|
||||
int32_t *LaneId, int32_t *NumLanes);
|
||||
EXTERN void __kmpc_kernel_end_convergent_simd(void *buffer);
|
||||
@@ -486,6 +491,8 @@ EXTERN void __kmpc_kernel_end_convergent_simd(void *buffer);
|
||||
|
||||
EXTERN void __kmpc_data_sharing_init_stack();
|
||||
EXTERN void __kmpc_data_sharing_init_stack_spmd();
|
||||
EXTERN void *__kmpc_data_sharing_coalesced_push_stack(size_t size,
|
||||
int16_t UseSharedMemory);
|
||||
EXTERN void *__kmpc_data_sharing_push_stack(size_t size, int16_t UseSharedMemory);
|
||||
EXTERN void __kmpc_data_sharing_pop_stack(void *a);
|
||||
EXTERN void __kmpc_begin_sharing_variables(void ***GlobalArgs, size_t nArgs);
|
||||
@@ -507,12 +514,13 @@ __kmpc_initialize_data_sharing_environment(__kmpc_data_sharing_slot *RootS,
|
||||
size_t InitialDataSize);
|
||||
EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
__kmpc_data_sharing_slot **SavedSharedSlot, void **SavedSharedStack,
|
||||
void **SavedSharedFrame, int32_t *SavedActiveThreads,
|
||||
void **SavedSharedFrame, __kmpc_impl_lanemask_t *SavedActiveThreads,
|
||||
size_t SharingDataSize, size_t SharingDefaultDataSize,
|
||||
int16_t IsOMPRuntimeInitialized);
|
||||
EXTERN void __kmpc_data_sharing_environment_end(
|
||||
__kmpc_data_sharing_slot **SavedSharedSlot, void **SavedSharedStack,
|
||||
void **SavedSharedFrame, int32_t *SavedActiveThreads, int32_t IsEntryPoint);
|
||||
void **SavedSharedFrame, __kmpc_impl_lanemask_t *SavedActiveThreads,
|
||||
int32_t IsEntryPoint);
|
||||
|
||||
EXTERN void *
|
||||
__kmpc_get_data_sharing_environment_frame(int32_t SourceThreadID,
|
||||
@@ -520,4 +528,12 @@ __kmpc_get_data_sharing_environment_frame(int32_t SourceThreadID,
|
||||
|
||||
// SPMD execution mode interrogation function.
|
||||
EXTERN int8_t __kmpc_is_spmd_exec_mode();
|
||||
|
||||
EXTERN void __kmpc_get_team_static_memory(int16_t isSPMDExecutionMode,
|
||||
const void *buf, size_t size,
|
||||
int16_t is_shared, const void **res);
|
||||
|
||||
EXTERN void __kmpc_restore_team_static_memory(int16_t isSPMDExecutionMode,
|
||||
int16_t is_shared);
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
@@ -36,6 +35,10 @@ if(CUDA_HOST_COMPILER MATCHES clang)
|
||||
set(CUDA_HOST_COMPILER "${LIBOMPTARGET_NVPTX_ALTERNATE_GCC_HOST_COMPILER}" CACHE FILEPATH "" FORCE)
|
||||
endif()
|
||||
|
||||
get_filename_component(devicertl_base_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DIRECTORY)
|
||||
|
||||
if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
libomptarget_say("Building CUDA offloading device RTL.")
|
||||
|
||||
@@ -84,7 +87,7 @@ if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
# yet supported by the CUDA toolchain on the device.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
list(APPEND CUDA_NVCC_FLAGS -I${devicertl_base_directory})
|
||||
cuda_add_library(omptarget-nvptx STATIC ${cuda_src_files} ${omp_data_objects}
|
||||
OPTIONS ${CUDA_ARCH} ${CUDA_DEBUG})
|
||||
|
||||
@@ -118,7 +121,8 @@ if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
libomptarget_say("Building CUDA LLVM bitcode offloading device RTL.")
|
||||
|
||||
# Set flags for LLVM Bitcode compilation.
|
||||
set(bc_flags ${LIBOMPTARGET_NVPTX_SELECTED_CUDA_COMPILER_FLAGS} -DOMPTARGET_NVPTX_TEST=0)
|
||||
set(bc_flags ${LIBOMPTARGET_NVPTX_SELECTED_CUDA_COMPILER_FLAGS}
|
||||
-I${devicertl_base_directory})
|
||||
if(${LIBOMPTARGET_NVPTX_DEBUG})
|
||||
set(bc_flags ${bc_flags} -DOMPTARGET_NVPTX_DEBUG=-1)
|
||||
else()
|
||||
@@ -132,6 +136,9 @@ if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
set(bc_flags ${bc_flags} -Dnv_weak=weak)
|
||||
endif()
|
||||
|
||||
# Create target to build all Bitcode libraries.
|
||||
add_custom_target(omptarget-nvptx-bc)
|
||||
|
||||
# Generate a Bitcode library for all the compute capabilities the user requested.
|
||||
foreach(sm ${nvptx_sm_list})
|
||||
set(cuda_arch --cuda-gpu-arch=sm_${sm})
|
||||
@@ -165,6 +172,7 @@ if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES libomptarget-nvptx-sm_${sm}.bc)
|
||||
|
||||
add_custom_target(omptarget-nvptx-${sm}-bc ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/libomptarget-nvptx-sm_${sm}.bc)
|
||||
add_dependencies(omptarget-nvptx-bc omptarget-nvptx-${sm}-bc)
|
||||
|
||||
# Copy library to destination.
|
||||
add_custom_command(TARGET omptarget-nvptx-${sm}-bc POST_BUILD
|
||||
@@ -176,6 +184,7 @@ if(LIBOMPTARGET_DEP_CUDA_FOUND)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_subdirectory(test)
|
||||
else()
|
||||
libomptarget_say("Not building CUDA offloading device RTL: CUDA tools not found in the system.")
|
||||
endif()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------ cancel.cu - NVPTX OpenMP cancel interface ------------ CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -13,16 +12,16 @@
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
|
||||
EXTERN int32_t __kmpc_cancellationpoint(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_cancellationpoint(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t cancelVal) {
|
||||
PRINT(LD_IO, "call kmpc_cancellationpoint(cancel val %d)\n", cancelVal);
|
||||
PRINT(LD_IO, "call kmpc_cancellationpoint(cancel val %d)\n", (int)cancelVal);
|
||||
// disabled
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_cancel(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN int32_t __kmpc_cancel(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t cancelVal) {
|
||||
PRINT(LD_IO, "call kmpc_cancel(cancel val %d)\n", cancelVal);
|
||||
PRINT(LD_IO, "call kmpc_cancel(cancel val %d)\n", (int)cancelVal);
|
||||
// disabled
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
//===------ counter_group.h - NVPTX OpenMP loop scheduling ------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Interface to implement OpenMP loop scheduling
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _OMPTARGET_NVPTX_COUNTER_GROUP_H_
|
||||
#define _OMPTARGET_NVPTX_COUNTER_GROUP_H_
|
||||
|
||||
#include "option.h"
|
||||
|
||||
// counter group type for synchronizations
|
||||
class omptarget_nvptx_CounterGroup {
|
||||
public:
|
||||
// getters and setters
|
||||
INLINE Counter &Event() { return v_event; }
|
||||
INLINE volatile Counter &Start() { return v_start; }
|
||||
INLINE Counter &Init() { return v_init; }
|
||||
|
||||
// Synchronization Interface
|
||||
|
||||
INLINE void Clear(); // first time start=event
|
||||
INLINE void Reset(); // init = first
|
||||
INLINE void Init(Counter &priv); // priv = init
|
||||
INLINE Counter Next(); // just counts number of events
|
||||
|
||||
// set priv to n, to be used in later waitOrRelease
|
||||
INLINE void Complete(Counter &priv, Counter n);
|
||||
|
||||
// check priv and decide if we have to wait or can free the other warps
|
||||
INLINE void Release(Counter priv, Counter current_event_value);
|
||||
INLINE void WaitOrRelease(Counter priv, Counter current_event_value);
|
||||
|
||||
private:
|
||||
Counter v_event; // counter of events (atomic)
|
||||
|
||||
// volatile is needed to force loads to read from global
|
||||
// memory or L2 cache and see the write by the last master
|
||||
volatile Counter v_start; // signal when events registered are finished
|
||||
|
||||
Counter v_init; // used to initialize local thread variables
|
||||
};
|
||||
|
||||
#endif /* SRC_COUNTER_GROUP_H_ */
|
||||
@@ -1,82 +0,0 @@
|
||||
//===----- counter_groupi.h - NVPTX OpenMP loop scheduling ------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Interface implementation for OpenMP loop scheduling
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "option.h"
|
||||
|
||||
INLINE void omptarget_nvptx_CounterGroup::Clear() {
|
||||
PRINT0(LD_SYNCD, "clear counters\n")
|
||||
v_event = 0;
|
||||
v_start = 0;
|
||||
// v_init does not need to be reset (its value is dead)
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_CounterGroup::Reset() {
|
||||
// done by master before entering parallel
|
||||
ASSERT(LT_FUSSY, v_event == v_start,
|
||||
"error, entry %lld !=start %lld at reset\n", P64(v_event),
|
||||
P64(v_start));
|
||||
v_init = v_start;
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_CounterGroup::Init(Counter &priv) {
|
||||
PRINT(LD_SYNCD, "init priv counter 0x%llx with val %lld\n", P64(&priv),
|
||||
P64(v_start));
|
||||
priv = v_start;
|
||||
}
|
||||
|
||||
// just counts number of events
|
||||
INLINE Counter omptarget_nvptx_CounterGroup::Next() {
|
||||
Counter oldVal = atomicAdd(&v_event, (Counter)1);
|
||||
PRINT(LD_SYNCD, "next event counter 0x%llx with val %lld->%lld\n",
|
||||
P64(&v_event), P64(oldVal), P64(oldVal + 1));
|
||||
|
||||
return oldVal;
|
||||
}
|
||||
|
||||
// set priv to n, to be used in later waitOrRelease
|
||||
INLINE void omptarget_nvptx_CounterGroup::Complete(Counter &priv, Counter n) {
|
||||
PRINT(LD_SYNCD, "complete priv counter 0x%llx with val %llu->%llu (+%llu)\n",
|
||||
P64(&priv), P64(priv), P64(priv + n), n);
|
||||
priv += n;
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_CounterGroup::Release(Counter priv,
|
||||
Counter current_event_value) {
|
||||
if (priv - 1 == current_event_value) {
|
||||
PRINT(LD_SYNCD, "Release start counter 0x%llx with val %lld->%lld\n",
|
||||
P64(&v_start), P64(v_start), P64(priv));
|
||||
v_start = priv;
|
||||
}
|
||||
}
|
||||
|
||||
// check priv and decide if we have to wait or can free the other warps
|
||||
INLINE void
|
||||
omptarget_nvptx_CounterGroup::WaitOrRelease(Counter priv,
|
||||
Counter current_event_value) {
|
||||
if (priv - 1 == current_event_value) {
|
||||
PRINT(LD_SYNCD, "Release start counter 0x%llx with val %lld->%lld\n",
|
||||
P64(&v_start), P64(v_start), P64(priv));
|
||||
v_start = priv;
|
||||
} else {
|
||||
PRINT(LD_SYNCD,
|
||||
"Start waiting while start counter 0x%llx with val %lld < %lld\n",
|
||||
P64(&v_start), P64(v_start), P64(priv));
|
||||
while (priv > v_start) {
|
||||
// IDLE LOOP
|
||||
// start is volatile: it will be re-loaded at each while loop
|
||||
}
|
||||
PRINT(LD_SYNCD,
|
||||
"Done waiting as start counter 0x%llx with val %lld >= %lld\n",
|
||||
P64(&v_start), P64(v_start), P64(priv));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------ critical.cu - NVPTX OpenMP critical ------------------ CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -16,17 +15,15 @@
|
||||
#include "omptarget-nvptx.h"
|
||||
|
||||
EXTERN
|
||||
void __kmpc_critical(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_critical(kmp_Ident *loc, int32_t global_tid,
|
||||
kmp_CriticalName *lck) {
|
||||
PRINT0(LD_IO, "call to kmpc_critical()\n");
|
||||
omptarget_nvptx_TeamDescr &teamDescr = getMyTeamDescriptor();
|
||||
omp_set_lock(teamDescr.CriticalLock());
|
||||
omp_set_lock((omp_lock_t *)lck);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_end_critical(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_end_critical(kmp_Ident *loc, int32_t global_tid,
|
||||
kmp_CriticalName *lck) {
|
||||
PRINT0(LD_IO, "call to kmpc_end_critical()\n");
|
||||
omptarget_nvptx_TeamDescr &teamDescr = getMyTeamDescriptor();
|
||||
omp_unset_lock(teamDescr.CriticalLock());
|
||||
omp_unset_lock((omp_lock_t *)lck);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===----- data_sharing.cu - NVPTX OpenMP debug utilities -------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -11,44 +10,29 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "omptarget-nvptx.h"
|
||||
#include "target_impl.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// Number of threads in the CUDA block.
|
||||
__device__ static unsigned getNumThreads() { return blockDim.x; }
|
||||
// Thread ID in the CUDA block
|
||||
__device__ static unsigned getThreadId() { return threadIdx.x; }
|
||||
// Warp ID in the CUDA block
|
||||
__device__ static unsigned getWarpId() { return threadIdx.x / WARPSIZE; }
|
||||
INLINE static unsigned getWarpId() { return threadIdx.x / WARPSIZE; }
|
||||
// Lane ID in the CUDA warp.
|
||||
__device__ static unsigned getLaneId() { return threadIdx.x % WARPSIZE; }
|
||||
|
||||
// The CUDA thread ID of the master thread.
|
||||
__device__ static unsigned getMasterThreadId() {
|
||||
unsigned Mask = WARPSIZE - 1;
|
||||
return (getNumThreads() - 1) & (~Mask);
|
||||
}
|
||||
|
||||
// Find the active threads in the warp - return a mask whose n-th bit is set if
|
||||
// the n-th thread in the warp is active.
|
||||
__device__ static unsigned getActiveThreadsMask() {
|
||||
return __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
}
|
||||
INLINE static unsigned getLaneId() { return threadIdx.x % WARPSIZE; }
|
||||
|
||||
// Return true if this is the first active thread in the warp.
|
||||
__device__ static bool IsWarpMasterActiveThread() {
|
||||
unsigned long long Mask = getActiveThreadsMask();
|
||||
unsigned long long ShNum = WARPSIZE - (getThreadId() % WARPSIZE);
|
||||
INLINE static bool IsWarpMasterActiveThread() {
|
||||
unsigned long long Mask = __kmpc_impl_activemask();
|
||||
unsigned long long ShNum = WARPSIZE - (GetThreadIdInBlock() % WARPSIZE);
|
||||
unsigned long long Sh = Mask << ShNum;
|
||||
// Truncate Sh to the 32 lower bits
|
||||
return (unsigned)Sh == 0;
|
||||
}
|
||||
// Return true if this is the master thread.
|
||||
__device__ static bool IsMasterThread() {
|
||||
return !isSPMDMode() && getMasterThreadId() == getThreadId();
|
||||
INLINE static bool IsMasterThread(bool isSPMDExecutionMode) {
|
||||
return !isSPMDExecutionMode && GetMasterThreadID() == GetThreadIdInBlock();
|
||||
}
|
||||
|
||||
/// Return the provided size aligned to the size of a pointer.
|
||||
__device__ static size_t AlignVal(size_t Val) {
|
||||
INLINE static size_t AlignVal(size_t Val) {
|
||||
const size_t Align = (size_t)sizeof(void *);
|
||||
if (Val & (Align - 1)) {
|
||||
Val += Align;
|
||||
@@ -79,38 +63,40 @@ __device__ static size_t AlignVal(size_t Val) {
|
||||
EXTERN void
|
||||
__kmpc_initialize_data_sharing_environment(__kmpc_data_sharing_slot *rootS,
|
||||
size_t InitialDataSize) {
|
||||
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Runtime must be initialized.");
|
||||
DSPRINT0(DSFLAG_INIT,
|
||||
"Entering __kmpc_initialize_data_sharing_environment\n");
|
||||
|
||||
unsigned WID = getWarpId();
|
||||
DSPRINT(DSFLAG_INIT, "Warp ID: %d\n", WID);
|
||||
DSPRINT(DSFLAG_INIT, "Warp ID: %u\n", WID);
|
||||
|
||||
omptarget_nvptx_TeamDescr *teamDescr =
|
||||
&omptarget_nvptx_threadPrivateContext->TeamContext();
|
||||
__kmpc_data_sharing_slot *RootS = teamDescr->RootS(WID, IsMasterThread());
|
||||
__kmpc_data_sharing_slot *RootS =
|
||||
teamDescr->RootS(WID, IsMasterThread(isSPMDMode()));
|
||||
|
||||
DataSharingState.SlotPtr[WID] = RootS;
|
||||
DataSharingState.StackPtr[WID] = (void *)&RootS->Data[0];
|
||||
|
||||
// We don't need to initialize the frame and active threads.
|
||||
|
||||
DSPRINT(DSFLAG_INIT, "Initial data size: %08x \n", InitialDataSize);
|
||||
DSPRINT(DSFLAG_INIT, "Root slot at: %016llx \n", (long long)RootS);
|
||||
DSPRINT(DSFLAG_INIT, "Initial data size: %08x \n", (unsigned)InitialDataSize);
|
||||
DSPRINT(DSFLAG_INIT, "Root slot at: %016llx \n", (unsigned long long)RootS);
|
||||
DSPRINT(DSFLAG_INIT, "Root slot data-end at: %016llx \n",
|
||||
(long long)RootS->DataEnd);
|
||||
DSPRINT(DSFLAG_INIT, "Root slot next at: %016llx \n", (long long)RootS->Next);
|
||||
(unsigned long long)RootS->DataEnd);
|
||||
DSPRINT(DSFLAG_INIT, "Root slot next at: %016llx \n",
|
||||
(unsigned long long)RootS->Next);
|
||||
DSPRINT(DSFLAG_INIT, "Shared slot ptr at: %016llx \n",
|
||||
(long long)DataSharingState.SlotPtr[WID]);
|
||||
(unsigned long long)DataSharingState.SlotPtr[WID]);
|
||||
DSPRINT(DSFLAG_INIT, "Shared stack ptr at: %016llx \n",
|
||||
(long long)DataSharingState.StackPtr[WID]);
|
||||
(unsigned long long)DataSharingState.StackPtr[WID]);
|
||||
|
||||
DSPRINT0(DSFLAG_INIT, "Exiting __kmpc_initialize_data_sharing_environment\n");
|
||||
}
|
||||
|
||||
EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
__kmpc_data_sharing_slot **SavedSharedSlot, void **SavedSharedStack,
|
||||
void **SavedSharedFrame, int32_t *SavedActiveThreads,
|
||||
void **SavedSharedFrame, __kmpc_impl_lanemask_t *SavedActiveThreads,
|
||||
size_t SharingDataSize, size_t SharingDefaultDataSize,
|
||||
int16_t IsOMPRuntimeInitialized) {
|
||||
|
||||
@@ -121,16 +107,17 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
if (!IsOMPRuntimeInitialized)
|
||||
return (void *)&DataSharingState;
|
||||
|
||||
DSPRINT(DSFLAG, "Data Size %016llx\n", SharingDataSize);
|
||||
DSPRINT(DSFLAG, "Default Data Size %016llx\n", SharingDefaultDataSize);
|
||||
DSPRINT(DSFLAG, "Data Size %016llx\n", (unsigned long long)SharingDataSize);
|
||||
DSPRINT(DSFLAG, "Default Data Size %016llx\n",
|
||||
(unsigned long long)SharingDefaultDataSize);
|
||||
|
||||
unsigned WID = getWarpId();
|
||||
unsigned CurActiveThreads = getActiveThreadsMask();
|
||||
__kmpc_impl_lanemask_t CurActiveThreads = __kmpc_impl_activemask();
|
||||
|
||||
__kmpc_data_sharing_slot *&SlotP = DataSharingState.SlotPtr[WID];
|
||||
void *&StackP = DataSharingState.StackPtr[WID];
|
||||
void *&FrameP = DataSharingState.FramePtr[WID];
|
||||
int32_t &ActiveT = DataSharingState.ActiveThreads[WID];
|
||||
void * volatile &FrameP = DataSharingState.FramePtr[WID];
|
||||
__kmpc_impl_lanemask_t &ActiveT = DataSharingState.ActiveThreads[WID];
|
||||
|
||||
DSPRINT0(DSFLAG, "Save current slot/stack values.\n");
|
||||
// Save the current values.
|
||||
@@ -139,11 +126,11 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
*SavedSharedFrame = FrameP;
|
||||
*SavedActiveThreads = ActiveT;
|
||||
|
||||
DSPRINT(DSFLAG, "Warp ID: %d\n", WID);
|
||||
DSPRINT(DSFLAG, "Saved slot ptr at: %016llx \n", (long long)SlotP);
|
||||
DSPRINT(DSFLAG, "Saved stack ptr at: %016llx \n", (long long)StackP);
|
||||
DSPRINT(DSFLAG, "Warp ID: %u\n", WID);
|
||||
DSPRINT(DSFLAG, "Saved slot ptr at: %016llx \n", (unsigned long long)SlotP);
|
||||
DSPRINT(DSFLAG, "Saved stack ptr at: %016llx \n", (unsigned long long)StackP);
|
||||
DSPRINT(DSFLAG, "Saved frame ptr at: %016llx \n", (long long)FrameP);
|
||||
DSPRINT(DSFLAG, "Active threads: %08x \n", ActiveT);
|
||||
DSPRINT(DSFLAG, "Active threads: %08x \n", (unsigned)ActiveT);
|
||||
|
||||
// Only the warp active master needs to grow the stack.
|
||||
if (IsWarpMasterActiveThread()) {
|
||||
@@ -161,12 +148,16 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
const uintptr_t RequiredEndAddress =
|
||||
CurrentStartAddress + (uintptr_t)SharingDataSize;
|
||||
|
||||
DSPRINT(DSFLAG, "Data Size %016llx\n", SharingDataSize);
|
||||
DSPRINT(DSFLAG, "Default Data Size %016llx\n", SharingDefaultDataSize);
|
||||
DSPRINT(DSFLAG, "Current Start Address %016llx\n", CurrentStartAddress);
|
||||
DSPRINT(DSFLAG, "Current End Address %016llx\n", CurrentEndAddress);
|
||||
DSPRINT(DSFLAG, "Required End Address %016llx\n", RequiredEndAddress);
|
||||
DSPRINT(DSFLAG, "Active Threads %08x\n", ActiveT);
|
||||
DSPRINT(DSFLAG, "Data Size %016llx\n", (unsigned long long)SharingDataSize);
|
||||
DSPRINT(DSFLAG, "Default Data Size %016llx\n",
|
||||
(unsigned long long)SharingDefaultDataSize);
|
||||
DSPRINT(DSFLAG, "Current Start Address %016llx\n",
|
||||
(unsigned long long)CurrentStartAddress);
|
||||
DSPRINT(DSFLAG, "Current End Address %016llx\n",
|
||||
(unsigned long long)CurrentEndAddress);
|
||||
DSPRINT(DSFLAG, "Required End Address %016llx\n",
|
||||
(unsigned long long)RequiredEndAddress);
|
||||
DSPRINT(DSFLAG, "Active Threads %08x\n", (unsigned)ActiveT);
|
||||
|
||||
// If we require a new slot, allocate it and initialize it (or attempt to
|
||||
// reuse one). Also, set the shared stack and slot pointers to the new
|
||||
@@ -184,11 +175,11 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
(uintptr_t)(&ExistingSlot->Data[0]);
|
||||
if (ExistingSlotSize >= NewSize) {
|
||||
DSPRINT(DSFLAG, "Reusing stack slot %016llx\n",
|
||||
(long long)ExistingSlot);
|
||||
(unsigned long long)ExistingSlot);
|
||||
NewSlot = ExistingSlot;
|
||||
} else {
|
||||
DSPRINT(DSFLAG, "Cleaning up -failed reuse - %016llx\n",
|
||||
(long long)SlotP->Next);
|
||||
(unsigned long long)SlotP->Next);
|
||||
free(ExistingSlot);
|
||||
}
|
||||
}
|
||||
@@ -197,7 +188,7 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
NewSlot = (__kmpc_data_sharing_slot *)malloc(
|
||||
sizeof(__kmpc_data_sharing_slot) + NewSize);
|
||||
DSPRINT(DSFLAG, "New slot allocated %016llx (data size=%016llx)\n",
|
||||
(long long)NewSlot, NewSize);
|
||||
(unsigned long long)NewSlot, NewSize);
|
||||
}
|
||||
|
||||
NewSlot->Next = 0;
|
||||
@@ -213,7 +204,7 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
// not eliminate them because that may be used to return data.
|
||||
if (SlotP->Next) {
|
||||
DSPRINT(DSFLAG, "Cleaning up - old not required - %016llx\n",
|
||||
(long long)SlotP->Next);
|
||||
(unsigned long long)SlotP->Next);
|
||||
free(SlotP->Next);
|
||||
SlotP->Next = 0;
|
||||
}
|
||||
@@ -234,7 +225,7 @@ EXTERN void *__kmpc_data_sharing_environment_begin(
|
||||
|
||||
EXTERN void __kmpc_data_sharing_environment_end(
|
||||
__kmpc_data_sharing_slot **SavedSharedSlot, void **SavedSharedStack,
|
||||
void **SavedSharedFrame, int32_t *SavedActiveThreads,
|
||||
void **SavedSharedFrame, __kmpc_impl_lanemask_t *SavedActiveThreads,
|
||||
int32_t IsEntryPoint) {
|
||||
|
||||
DSPRINT0(DSFLAG, "Entering __kmpc_data_sharing_environment_end\n");
|
||||
@@ -247,8 +238,9 @@ EXTERN void __kmpc_data_sharing_environment_end(
|
||||
|
||||
// The master thread cleans the saved slot, because this is an environment
|
||||
// only for the master.
|
||||
__kmpc_data_sharing_slot *S =
|
||||
IsMasterThread() ? *SavedSharedSlot : DataSharingState.SlotPtr[WID];
|
||||
__kmpc_data_sharing_slot *S = IsMasterThread(isSPMDMode())
|
||||
? *SavedSharedSlot
|
||||
: DataSharingState.SlotPtr[WID];
|
||||
|
||||
if (S->Next) {
|
||||
free(S->Next);
|
||||
@@ -260,7 +252,7 @@ EXTERN void __kmpc_data_sharing_environment_end(
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t CurActive = getActiveThreadsMask();
|
||||
__kmpc_impl_lanemask_t CurActive = __kmpc_impl_activemask();
|
||||
|
||||
// Only the warp master can restore the stack and frame information, and only
|
||||
// if there are no other threads left behind in this environment (i.e. the
|
||||
@@ -268,32 +260,35 @@ EXTERN void __kmpc_data_sharing_environment_end(
|
||||
// assume that threads will converge right after the call site that started
|
||||
// the environment.
|
||||
if (IsWarpMasterActiveThread()) {
|
||||
int32_t &ActiveT = DataSharingState.ActiveThreads[WID];
|
||||
__kmpc_impl_lanemask_t &ActiveT = DataSharingState.ActiveThreads[WID];
|
||||
|
||||
DSPRINT0(DSFLAG, "Before restoring the stack\n");
|
||||
// Zero the bits in the mask. If it is still different from zero, then we
|
||||
// have other threads that will return after the current ones.
|
||||
ActiveT &= ~CurActive;
|
||||
|
||||
DSPRINT(DSFLAG, "Active threads: %08x; New mask: %08x\n", CurActive,
|
||||
ActiveT);
|
||||
DSPRINT(DSFLAG, "Active threads: %08x; New mask: %08x\n",
|
||||
(unsigned)CurActive, (unsigned)ActiveT);
|
||||
|
||||
if (!ActiveT) {
|
||||
// No other active threads? Great, lets restore the stack.
|
||||
|
||||
__kmpc_data_sharing_slot *&SlotP = DataSharingState.SlotPtr[WID];
|
||||
void *&StackP = DataSharingState.StackPtr[WID];
|
||||
void *&FrameP = DataSharingState.FramePtr[WID];
|
||||
void * volatile &FrameP = DataSharingState.FramePtr[WID];
|
||||
|
||||
SlotP = *SavedSharedSlot;
|
||||
StackP = *SavedSharedStack;
|
||||
FrameP = *SavedSharedFrame;
|
||||
ActiveT = *SavedActiveThreads;
|
||||
|
||||
DSPRINT(DSFLAG, "Restored slot ptr at: %016llx \n", (long long)SlotP);
|
||||
DSPRINT(DSFLAG, "Restored stack ptr at: %016llx \n", (long long)StackP);
|
||||
DSPRINT(DSFLAG, "Restored frame ptr at: %016llx \n", (long long)FrameP);
|
||||
DSPRINT(DSFLAG, "Active threads: %08x \n", ActiveT);
|
||||
DSPRINT(DSFLAG, "Restored slot ptr at: %016llx \n",
|
||||
(unsigned long long)SlotP);
|
||||
DSPRINT(DSFLAG, "Restored stack ptr at: %016llx \n",
|
||||
(unsigned long long)StackP);
|
||||
DSPRINT(DSFLAG, "Restored frame ptr at: %016llx \n",
|
||||
(unsigned long long)FrameP);
|
||||
DSPRINT(DSFLAG, "Active threads: %08x \n", (unsigned)ActiveT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,9 +314,9 @@ __kmpc_get_data_sharing_environment_frame(int32_t SourceThreadID,
|
||||
|
||||
unsigned SourceWID = SourceThreadID / WARPSIZE;
|
||||
|
||||
DSPRINT(DSFLAG, "Source warp: %d\n", SourceWID);
|
||||
DSPRINT(DSFLAG, "Source warp: %u\n", SourceWID);
|
||||
|
||||
void *P = DataSharingState.FramePtr[SourceWID];
|
||||
void * volatile P = DataSharingState.FramePtr[SourceWID];
|
||||
DSPRINT0(DSFLAG, "Exiting __kmpc_get_data_sharing_environment_frame\n");
|
||||
return P;
|
||||
}
|
||||
@@ -330,7 +325,8 @@ __kmpc_get_data_sharing_environment_frame(int32_t SourceThreadID,
|
||||
// Runtime functions for trunk data sharing scheme.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE void data_sharing_init_stack_common() {
|
||||
INLINE static void data_sharing_init_stack_common() {
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Runtime must be initialized.");
|
||||
omptarget_nvptx_TeamDescr *teamDescr =
|
||||
&omptarget_nvptx_threadPrivateContext->TeamContext();
|
||||
|
||||
@@ -346,6 +342,7 @@ INLINE void data_sharing_init_stack_common() {
|
||||
// initialization). This function is called only by the MASTER thread of each
|
||||
// team in non-SPMD mode.
|
||||
EXTERN void __kmpc_data_sharing_init_stack() {
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Runtime must be initialized.");
|
||||
// This function initializes the stack pointer with the pointer to the
|
||||
// statically allocated shared memory slots. The size of a shared memory
|
||||
// slot is pre-determined to be 256 bytes.
|
||||
@@ -357,6 +354,7 @@ EXTERN void __kmpc_data_sharing_init_stack() {
|
||||
// once at the beginning of a data sharing context (coincides with the kernel
|
||||
// initialization). This function is called in SPMD mode only.
|
||||
EXTERN void __kmpc_data_sharing_init_stack_spmd() {
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Runtime must be initialized.");
|
||||
// This function initializes the stack pointer with the pointer to the
|
||||
// statically allocated shared memory slots. The size of a shared memory
|
||||
// slot is pre-determined to be 256 bytes.
|
||||
@@ -366,34 +364,28 @@ EXTERN void __kmpc_data_sharing_init_stack_spmd() {
|
||||
__threadfence_block();
|
||||
}
|
||||
|
||||
// Called at the time of the kernel initialization. This is used to initilize
|
||||
// the list of references to shared variables and to pre-allocate global storage
|
||||
// for holding the globalized variables.
|
||||
//
|
||||
// By default the globalized variables are stored in global memory. If the
|
||||
// UseSharedMemory is set to true, the runtime will attempt to use shared memory
|
||||
// as long as the size requested fits the pre-allocated size.
|
||||
EXTERN void* __kmpc_data_sharing_push_stack(size_t DataSize,
|
||||
int16_t UseSharedMemory) {
|
||||
// Frame pointer must be visible to all workers in the same warp.
|
||||
unsigned WID = getWarpId();
|
||||
void *&FrameP = DataSharingState.FramePtr[WID];
|
||||
INLINE static void* data_sharing_push_stack_common(size_t PushSize) {
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Expected initialized runtime.");
|
||||
|
||||
// Only warp active master threads manage the stack.
|
||||
if (IsWarpMasterActiveThread()) {
|
||||
bool IsWarpMaster = (GetThreadIdInBlock() % WARPSIZE) == 0;
|
||||
|
||||
// Add worst-case padding to DataSize so that future stack allocations are
|
||||
// correctly aligned.
|
||||
const size_t Alignment = 8;
|
||||
PushSize = (PushSize + (Alignment - 1)) / Alignment * Alignment;
|
||||
|
||||
// Frame pointer must be visible to all workers in the same warp.
|
||||
const unsigned WID = getWarpId();
|
||||
void *FrameP = 0;
|
||||
__kmpc_impl_lanemask_t CurActive = __kmpc_impl_activemask();
|
||||
|
||||
if (IsWarpMaster) {
|
||||
// SlotP will point to either the shared memory slot or an existing
|
||||
// global memory slot.
|
||||
__kmpc_data_sharing_slot *&SlotP = DataSharingState.SlotPtr[WID];
|
||||
void *&StackP = DataSharingState.StackPtr[WID];
|
||||
|
||||
// Compute the total memory footprint of the requested data.
|
||||
// The master thread requires a stack only for itself. A worker
|
||||
// thread (which at this point is a warp master) will require
|
||||
// space for the variables of each thread in the warp,
|
||||
// i.e. one DataSize chunk per warp lane.
|
||||
// TODO: change WARPSIZE to the number of active threads in the warp.
|
||||
size_t PushSize = IsMasterThread() ? DataSize : WARPSIZE * DataSize;
|
||||
|
||||
// Check if we have room for the data in the current slot.
|
||||
const uintptr_t StartAddress = (uintptr_t)StackP;
|
||||
const uintptr_t EndAddress = (uintptr_t)SlotP->DataEnd;
|
||||
@@ -429,20 +421,51 @@ EXTERN void* __kmpc_data_sharing_push_stack(size_t DataSize,
|
||||
// The stack pointer always points to the next free stack frame.
|
||||
StackP = &NewSlot->Data[0] + PushSize;
|
||||
// The frame pointer always points to the beginning of the frame.
|
||||
FrameP = &NewSlot->Data[0];
|
||||
FrameP = DataSharingState.FramePtr[WID] = &NewSlot->Data[0];
|
||||
} else {
|
||||
// Add the data chunk to the current slot. The frame pointer is set to
|
||||
// point to the start of the new frame held in StackP.
|
||||
FrameP = StackP;
|
||||
FrameP = DataSharingState.FramePtr[WID] = StackP;
|
||||
// Reset stack pointer to the requested address.
|
||||
StackP = (void *)RequestedEndAddress;
|
||||
}
|
||||
}
|
||||
// Get address from lane 0.
|
||||
int *FP = (int *)&FrameP;
|
||||
FP[0] = __kmpc_impl_shfl_sync(CurActive, FP[0], 0);
|
||||
if (sizeof(FrameP) == 8)
|
||||
FP[1] = __kmpc_impl_shfl_sync(CurActive, FP[1], 0);
|
||||
|
||||
__threadfence_block();
|
||||
return FrameP;
|
||||
}
|
||||
|
||||
EXTERN void *__kmpc_data_sharing_coalesced_push_stack(size_t DataSize,
|
||||
int16_t UseSharedMemory) {
|
||||
return data_sharing_push_stack_common(DataSize);
|
||||
}
|
||||
|
||||
// Called at the time of the kernel initialization. This is used to initilize
|
||||
// the list of references to shared variables and to pre-allocate global storage
|
||||
// for holding the globalized variables.
|
||||
//
|
||||
// By default the globalized variables are stored in global memory. If the
|
||||
// UseSharedMemory is set to true, the runtime will attempt to use shared memory
|
||||
// as long as the size requested fits the pre-allocated size.
|
||||
EXTERN void *__kmpc_data_sharing_push_stack(size_t DataSize,
|
||||
int16_t UseSharedMemory) {
|
||||
// Compute the total memory footprint of the requested data.
|
||||
// The master thread requires a stack only for itself. A worker
|
||||
// thread (which at this point is a warp master) will require
|
||||
// space for the variables of each thread in the warp,
|
||||
// i.e. one DataSize chunk per warp lane.
|
||||
// TODO: change WARPSIZE to the number of active threads in the warp.
|
||||
size_t PushSize = (isRuntimeUninitialized() || IsMasterThread(isSPMDMode()))
|
||||
? DataSize
|
||||
: WARPSIZE * DataSize;
|
||||
|
||||
// Compute the start address of the frame of each thread in the warp.
|
||||
uintptr_t FrameStartAddress = (uintptr_t)FrameP;
|
||||
uintptr_t FrameStartAddress =
|
||||
(uintptr_t) data_sharing_push_stack_common(PushSize);
|
||||
FrameStartAddress += (uintptr_t) (getLaneId() * DataSize);
|
||||
return (void *)FrameStartAddress;
|
||||
}
|
||||
@@ -453,7 +476,11 @@ EXTERN void* __kmpc_data_sharing_push_stack(size_t DataSize,
|
||||
// reclaim all outstanding global memory slots since it is
|
||||
// likely we have reached the end of the kernel.
|
||||
EXTERN void __kmpc_data_sharing_pop_stack(void *FrameStart) {
|
||||
if (IsWarpMasterActiveThread()) {
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Expected initialized runtime.");
|
||||
|
||||
__threadfence_block();
|
||||
|
||||
if (GetThreadIdInBlock() % WARPSIZE == 0) {
|
||||
unsigned WID = getWarpId();
|
||||
|
||||
// Current slot
|
||||
@@ -462,13 +489,13 @@ EXTERN void __kmpc_data_sharing_pop_stack(void *FrameStart) {
|
||||
// Pointer to next available stack.
|
||||
void *&StackP = DataSharingState.StackPtr[WID];
|
||||
|
||||
// Pop the frame.
|
||||
StackP = FrameStart;
|
||||
|
||||
// If the current slot is empty, we need to free the slot after the
|
||||
// pop.
|
||||
bool SlotEmpty = (StackP == &SlotP->Data[0]);
|
||||
|
||||
// Pop the frame.
|
||||
StackP = FrameStart;
|
||||
|
||||
if (SlotEmpty && SlotP->Prev) {
|
||||
// Before removing the slot we need to reset StackP.
|
||||
StackP = SlotP->PrevSlotStackPtr;
|
||||
@@ -479,8 +506,6 @@ EXTERN void __kmpc_data_sharing_pop_stack(void *FrameStart) {
|
||||
SlotP->Next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
__threadfence_block();
|
||||
}
|
||||
|
||||
// Begin a data sharing context. Maintain a list of references to shared
|
||||
@@ -511,3 +536,46 @@ EXTERN void __kmpc_end_sharing_variables() {
|
||||
EXTERN void __kmpc_get_shared_variables(void ***GlobalArgs) {
|
||||
*GlobalArgs = omptarget_nvptx_globalArgs.GetArgs();
|
||||
}
|
||||
|
||||
// This function is used to init static memory manager. This manager is used to
|
||||
// manage statically allocated global memory. This memory is allocated by the
|
||||
// compiler and used to correctly implement globalization of the variables in
|
||||
// target, teams and distribute regions.
|
||||
EXTERN void __kmpc_get_team_static_memory(int16_t isSPMDExecutionMode,
|
||||
const void *buf, size_t size,
|
||||
int16_t is_shared,
|
||||
const void **frame) {
|
||||
if (is_shared) {
|
||||
*frame = buf;
|
||||
return;
|
||||
}
|
||||
if (isSPMDExecutionMode) {
|
||||
if (GetThreadIdInBlock() == 0) {
|
||||
*frame = omptarget_nvptx_simpleMemoryManager.Acquire(buf, size);
|
||||
}
|
||||
__kmpc_impl_syncthreads();
|
||||
return;
|
||||
}
|
||||
ASSERT0(LT_FUSSY, GetThreadIdInBlock() == GetMasterThreadID(),
|
||||
"Must be called only in the target master thread.");
|
||||
*frame = omptarget_nvptx_simpleMemoryManager.Acquire(buf, size);
|
||||
__threadfence();
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_restore_team_static_memory(int16_t isSPMDExecutionMode,
|
||||
int16_t is_shared) {
|
||||
if (is_shared)
|
||||
return;
|
||||
if (isSPMDExecutionMode) {
|
||||
__kmpc_impl_syncthreads();
|
||||
if (GetThreadIdInBlock() == 0) {
|
||||
omptarget_nvptx_simpleMemoryManager.Release();
|
||||
}
|
||||
return;
|
||||
}
|
||||
__threadfence();
|
||||
ASSERT0(LT_FUSSY, GetThreadIdInBlock() == GetMasterThreadID(),
|
||||
"Must be called only in the target master thread.");
|
||||
omptarget_nvptx_simpleMemoryManager.Release();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------- debug.h - NVPTX OpenMP debug macros ----------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -127,9 +126,29 @@
|
||||
|
||||
#if OMPTARGET_NVPTX_DEBUG || OMPTARGET_NVPTX_TEST || OMPTARGET_NVPTX_WARNING
|
||||
#include <stdio.h>
|
||||
#include "option.h"
|
||||
|
||||
template <typename... Arguments>
|
||||
NOINLINE static void log(const char *fmt, Arguments... parameters) {
|
||||
printf(fmt, (int)blockIdx.x, (int)threadIdx.x, (int)(threadIdx.x / WARPSIZE),
|
||||
(int)(threadIdx.x & 0x1F), parameters...);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if OMPTARGET_NVPTX_TEST
|
||||
#include <assert.h>
|
||||
|
||||
template <typename... Arguments>
|
||||
NOINLINE static void check(bool cond, const char *fmt,
|
||||
Arguments... parameters) {
|
||||
if (!cond)
|
||||
printf(fmt, (int)blockIdx.x, (int)threadIdx.x,
|
||||
(int)(threadIdx.x / WARPSIZE), (int)(threadIdx.x & 0x1F),
|
||||
parameters...);
|
||||
assert(cond);
|
||||
}
|
||||
|
||||
NOINLINE static void check(bool cond) { assert(cond); }
|
||||
#endif
|
||||
|
||||
// set flags that are tested (inclusion properties)
|
||||
@@ -164,16 +183,14 @@
|
||||
#define PRINT0(_flag, _str) \
|
||||
{ \
|
||||
if (omptarget_device_environment.debug_level && DON(_flag)) { \
|
||||
printf("<b %2d, t %4d, w %2d, l %2d>: " _str, blockIdx.x, threadIdx.x, \
|
||||
threadIdx.x / WARPSIZE, threadIdx.x & 0x1F); \
|
||||
log("<b %2d, t %4d, w %2d, l %2d>: " _str); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRINT(_flag, _str, _args...) \
|
||||
{ \
|
||||
if (omptarget_device_environment.debug_level && DON(_flag)) { \
|
||||
printf("<b %2d, t %4d, w %2d, l %2d>: " _str, blockIdx.x, threadIdx.x, \
|
||||
threadIdx.x / WARPSIZE, threadIdx.x & 0x1F, _args); \
|
||||
log("<b %2d, t %4d, w %2d, l %2d>: " _str, _args); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
@@ -201,13 +218,13 @@
|
||||
#define ASSERT0(_flag, _cond, _str) \
|
||||
{ \
|
||||
if (TON(_flag)) { \
|
||||
assert(_cond); \
|
||||
check(_cond); \
|
||||
} \
|
||||
}
|
||||
#define ASSERT(_flag, _cond, _str, _args...) \
|
||||
{ \
|
||||
if (TON(_flag)) { \
|
||||
assert(_cond); \
|
||||
check(_cond); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -216,18 +233,15 @@
|
||||
#define TON(_flag) ((OMPTARGET_NVPTX_TEST) & (_flag))
|
||||
#define ASSERT0(_flag, _cond, _str) \
|
||||
{ \
|
||||
if (TON(_flag) && !(_cond)) { \
|
||||
printf("<b %3d, t %4d, w %2d, l %2d> ASSERT: " _str "\n", blockIdx.x, \
|
||||
threadIdx.x, threadIdx.x / WARPSIZE, threadIdx.x & 0x1F); \
|
||||
assert(_cond); \
|
||||
if (TON(_flag)) { \
|
||||
check((_cond), "<b %3d, t %4d, w %2d, l %2d> ASSERT: " _str "\n"); \
|
||||
} \
|
||||
}
|
||||
#define ASSERT(_flag, _cond, _str, _args...) \
|
||||
{ \
|
||||
if (TON(_flag) && !(_cond)) { \
|
||||
printf("<b %3d, t %4d, w %2d, l %d2> ASSERT: " _str "\n", blockIdx.x, \
|
||||
threadIdx.x, threadIdx.x / WARPSIZE, threadIdx.x & 0x1F, _args); \
|
||||
assert(_cond); \
|
||||
if (TON(_flag)) { \
|
||||
check((_cond), "<b %3d, t %4d, w %2d, l %d2> ASSERT: " _str "\n", \
|
||||
_args); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -253,15 +267,13 @@
|
||||
#define WARNING0(_flag, _str) \
|
||||
{ \
|
||||
if (WON(_flag)) { \
|
||||
printf("<b %2d, t %4d, w %2d, l %2d> WARNING: " _str, blockIdx.x, \
|
||||
threadIdx.x, threadIdx.x / WARPSIZE, threadIdx.x & 0x1F); \
|
||||
log("<b %2d, t %4d, w %2d, l %2d> WARNING: " _str); \
|
||||
} \
|
||||
}
|
||||
#define WARNING(_flag, _str, _args...) \
|
||||
{ \
|
||||
if (WON(_flag)) { \
|
||||
printf("<b %2d, t %4d, w %2d, l %2d> WARNING: " _str, blockIdx.x, \
|
||||
threadIdx.x, threadIdx.x / WARPSIZE, threadIdx.x & 0x1F, _args); \
|
||||
log("<b %2d, t %4d, w %2d, l %2d> WARNING: " _str, _args); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------ libcall.cu - NVPTX OpenMP user calls ----------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -31,61 +30,61 @@ EXTERN double omp_get_wtime(void) {
|
||||
}
|
||||
|
||||
EXTERN void omp_set_num_threads(int num) {
|
||||
// Ignore it for SPMD mode.
|
||||
if (isSPMDMode())
|
||||
return;
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Expected initialized runtime.");
|
||||
PRINT(LD_IO, "call omp_set_num_threads(num %d)\n", num);
|
||||
if (num <= 0) {
|
||||
WARNING0(LW_INPUT, "expected positive num; ignore\n");
|
||||
} else {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
currTaskDescr->NThreads() = num;
|
||||
} else if (parallelLevel[GetWarpId()] == 0) {
|
||||
nThreads = num;
|
||||
}
|
||||
}
|
||||
|
||||
EXTERN int omp_get_num_threads(void) {
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int rc = GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized());
|
||||
int rc = GetNumberOfOmpThreads(isSPMDMode());
|
||||
PRINT(LD_IO, "call omp_get_num_threads() return %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_max_threads(void) {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
int rc = 1; // default is 1 thread avail
|
||||
if (!currTaskDescr->InParallelRegion()) {
|
||||
// not currently in a parallel region... all are available
|
||||
rc = GetNumberOfProcsInTeam();
|
||||
ASSERT0(LT_FUSSY, rc >= 0, "bad number of threads");
|
||||
}
|
||||
if (parallelLevel[GetWarpId()] > 0)
|
||||
// We're already in parallel region.
|
||||
return 1; // default is 1 thread avail
|
||||
// Not currently in a parallel region, return what was set.
|
||||
int rc = 1;
|
||||
if (parallelLevel[GetWarpId()] == 0)
|
||||
rc = nThreads;
|
||||
ASSERT0(LT_FUSSY, rc >= 0, "bad number of threads");
|
||||
PRINT(LD_IO, "call omp_get_max_threads() return %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_thread_limit(void) {
|
||||
// per contention group.. meaning threads in current team
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
int rc = currTaskDescr->ThreadLimit();
|
||||
if (isSPMDMode())
|
||||
return GetNumberOfThreadsInBlock();
|
||||
int rc = threadLimit;
|
||||
PRINT(LD_IO, "call omp_get_thread_limit() return %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_thread_num() {
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int rc = GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized());
|
||||
bool isSPMDExecutionMode = isSPMDMode();
|
||||
int tid = GetLogicalThreadIdInBlock(isSPMDExecutionMode);
|
||||
int rc = GetOmpThreadId(tid, isSPMDExecutionMode);
|
||||
PRINT(LD_IO, "call omp_get_thread_num() returns %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_num_procs(void) {
|
||||
int rc = GetNumberOfProcsInDevice();
|
||||
int rc = GetNumberOfProcsInDevice(isSPMDMode());
|
||||
PRINT(LD_IO, "call omp_get_num_procs() returns %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN int omp_in_parallel(void) {
|
||||
int rc = 0;
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
if (currTaskDescr->InParallelRegion()) {
|
||||
rc = 1;
|
||||
}
|
||||
int rc = parallelLevel[GetWarpId()] > OMP_ACTIVE_PARALLEL_LEVEL ? 1 : 0;
|
||||
PRINT(LD_IO, "call omp_in_parallel() returns %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -101,22 +100,11 @@ EXTERN int omp_in_final(void) {
|
||||
}
|
||||
|
||||
EXTERN void omp_set_dynamic(int flag) {
|
||||
PRINT(LD_IO, "call omp_set_dynamic(%d)\n", flag);
|
||||
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
if (flag) {
|
||||
currTaskDescr->SetDynamic();
|
||||
} else {
|
||||
currTaskDescr->ClearDynamic();
|
||||
}
|
||||
PRINT(LD_IO, "call omp_set_dynamic(%d) is ignored (no support)\n", flag);
|
||||
}
|
||||
|
||||
EXTERN int omp_get_dynamic(void) {
|
||||
int rc = 0;
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
if (currTaskDescr->IsDynamic()) {
|
||||
rc = 1;
|
||||
}
|
||||
PRINT(LD_IO, "call omp_get_dynamic() returns %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -145,43 +133,28 @@ EXTERN int omp_get_max_active_levels(void) {
|
||||
}
|
||||
|
||||
EXTERN int omp_get_level(void) {
|
||||
int level = 0;
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
ASSERT0(LT_FUSSY, currTaskDescr,
|
||||
"do not expect fct to be called in a non-active thread");
|
||||
do {
|
||||
if (currTaskDescr->IsParallelConstruct()) {
|
||||
level++;
|
||||
}
|
||||
currTaskDescr = currTaskDescr->GetPrevTaskDescr();
|
||||
} while (currTaskDescr);
|
||||
int level = parallelLevel[GetWarpId()] & (OMP_ACTIVE_PARALLEL_LEVEL - 1);
|
||||
PRINT(LD_IO, "call omp_get_level() returns %d\n", level);
|
||||
return level;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_active_level(void) {
|
||||
int level = 0; // no active level parallelism
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
ASSERT0(LT_FUSSY, currTaskDescr,
|
||||
"do not expect fct to be called in a non-active thread");
|
||||
do {
|
||||
if (currTaskDescr->ThreadsInTeam() > 1) {
|
||||
// has a parallel with more than one thread in team
|
||||
level = 1;
|
||||
break;
|
||||
}
|
||||
currTaskDescr = currTaskDescr->GetPrevTaskDescr();
|
||||
} while (currTaskDescr);
|
||||
int level = parallelLevel[GetWarpId()] > OMP_ACTIVE_PARALLEL_LEVEL ? 1 : 0;
|
||||
PRINT(LD_IO, "call omp_get_active_level() returns %d\n", level)
|
||||
return level;
|
||||
}
|
||||
|
||||
EXTERN int omp_get_ancestor_thread_num(int level) {
|
||||
int rc = 0; // default at level 0
|
||||
if (level >= 0) {
|
||||
if (isSPMDMode())
|
||||
return level == 1 ? GetThreadIdInBlock() : 0;
|
||||
int rc = -1;
|
||||
// If level is 0 or all parallel regions are not active - return 0.
|
||||
unsigned parLevel = parallelLevel[GetWarpId()];
|
||||
if (level == 1 && parLevel > OMP_ACTIVE_PARALLEL_LEVEL) {
|
||||
int totLevel = omp_get_level();
|
||||
if (level <= totLevel) {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
getMyTopTaskDescriptor(/*isSPMDExecutionMode=*/false);
|
||||
int steps = totLevel - level;
|
||||
PRINT(LD_IO, "backtrack %d steps\n", steps);
|
||||
ASSERT0(LT_FUSSY, currTaskDescr,
|
||||
@@ -191,14 +164,14 @@ EXTERN int omp_get_ancestor_thread_num(int level) {
|
||||
// print current state
|
||||
omp_sched_t sched = currTaskDescr->GetRuntimeSched();
|
||||
PRINT(LD_ALL,
|
||||
"task descr %s %d: %s, in par %d, dyn %d, rt sched %d,"
|
||||
"task descr %s %d: %s, in par %d, rt sched %d,"
|
||||
" chunk %" PRIu64 "; tid %d, tnum %d, nthreads %d\n",
|
||||
"ancestor", steps,
|
||||
(currTaskDescr->IsParallelConstruct() ? "par" : "task"),
|
||||
currTaskDescr->InParallelRegion(), currTaskDescr->IsDynamic(),
|
||||
sched, currTaskDescr->RuntimeChunkSize(),
|
||||
currTaskDescr->ThreadId(), currTaskDescr->ThreadsInTeam(),
|
||||
currTaskDescr->NThreads());
|
||||
(int)currTaskDescr->InParallelRegion(), (int)sched,
|
||||
currTaskDescr->RuntimeChunkSize(),
|
||||
(int)currTaskDescr->ThreadId(), (int)threadsInTeam,
|
||||
(int)nThreads);
|
||||
}
|
||||
|
||||
if (currTaskDescr->IsParallelConstruct()) {
|
||||
@@ -213,6 +186,12 @@ EXTERN int omp_get_ancestor_thread_num(int level) {
|
||||
} while (currTaskDescr);
|
||||
ASSERT0(LT_FUSSY, !steps, "expected to find all steps");
|
||||
}
|
||||
} else if (level == 0 ||
|
||||
(level > 0 && parLevel < OMP_ACTIVE_PARALLEL_LEVEL &&
|
||||
level <= parLevel) ||
|
||||
(level > 1 && parLevel > OMP_ACTIVE_PARALLEL_LEVEL &&
|
||||
level <= (parLevel - OMP_ACTIVE_PARALLEL_LEVEL))) {
|
||||
rc = 0;
|
||||
}
|
||||
PRINT(LD_IO, "call omp_get_ancestor_thread_num(level %d) returns %d\n", level,
|
||||
rc)
|
||||
@@ -220,36 +199,36 @@ EXTERN int omp_get_ancestor_thread_num(int level) {
|
||||
}
|
||||
|
||||
EXTERN int omp_get_team_size(int level) {
|
||||
int rc = 1; // default at level 0
|
||||
if (level >= 0) {
|
||||
int totLevel = omp_get_level();
|
||||
if (level <= totLevel) {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
int steps = totLevel - level;
|
||||
ASSERT0(LT_FUSSY, currTaskDescr,
|
||||
"do not expect fct to be called in a non-active thread");
|
||||
do {
|
||||
if (currTaskDescr->IsParallelConstruct()) {
|
||||
if (!steps) {
|
||||
// found the level
|
||||
rc = currTaskDescr->ThreadsInTeam();
|
||||
break;
|
||||
}
|
||||
steps--;
|
||||
}
|
||||
currTaskDescr = currTaskDescr->GetPrevTaskDescr();
|
||||
} while (currTaskDescr);
|
||||
ASSERT0(LT_FUSSY, !steps, "expected to find all steps");
|
||||
}
|
||||
if (isSPMDMode())
|
||||
return level == 1 ? GetNumberOfThreadsInBlock() : 1;
|
||||
int rc = -1;
|
||||
unsigned parLevel = parallelLevel[GetWarpId()];
|
||||
// If level is 0 or all parallel regions are not active - return 1.
|
||||
if (level == 1 && parLevel > OMP_ACTIVE_PARALLEL_LEVEL) {
|
||||
rc = threadsInTeam;
|
||||
} else if (level == 0 ||
|
||||
(level > 0 && parLevel < OMP_ACTIVE_PARALLEL_LEVEL &&
|
||||
level <= parLevel) ||
|
||||
(level > 1 && parLevel > OMP_ACTIVE_PARALLEL_LEVEL &&
|
||||
level <= (parLevel - OMP_ACTIVE_PARALLEL_LEVEL))) {
|
||||
rc = 1;
|
||||
}
|
||||
PRINT(LD_IO, "call omp_get_team_size(level %d) returns %d\n", level, rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
EXTERN void omp_get_schedule(omp_sched_t *kind, int *modifier) {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
*kind = currTaskDescr->GetRuntimeSched();
|
||||
*modifier = currTaskDescr->RuntimeChunkSize();
|
||||
if (isRuntimeUninitialized()) {
|
||||
ASSERT0(LT_FUSSY, isSPMDMode(),
|
||||
"Expected SPMD mode only with uninitialized runtime.");
|
||||
*kind = omp_sched_static;
|
||||
*modifier = 1;
|
||||
} else {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
getMyTopTaskDescriptor(isSPMDMode());
|
||||
*kind = currTaskDescr->GetRuntimeSched();
|
||||
*modifier = currTaskDescr->RuntimeChunkSize();
|
||||
}
|
||||
PRINT(LD_IO, "call omp_get_schedule returns sched %d and modif %d\n",
|
||||
(int)*kind, *modifier);
|
||||
}
|
||||
@@ -257,8 +236,14 @@ EXTERN void omp_get_schedule(omp_sched_t *kind, int *modifier) {
|
||||
EXTERN void omp_set_schedule(omp_sched_t kind, int modifier) {
|
||||
PRINT(LD_IO, "call omp_set_schedule(sched %d, modif %d)\n", (int)kind,
|
||||
modifier);
|
||||
if (isRuntimeUninitialized()) {
|
||||
ASSERT0(LT_FUSSY, isSPMDMode(),
|
||||
"Expected SPMD mode only with uninitialized runtime.");
|
||||
return;
|
||||
}
|
||||
if (kind >= omp_sched_static && kind < omp_sched_auto) {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
getMyTopTaskDescriptor(isSPMDMode());
|
||||
currTaskDescr->SetRuntimeSched(kind);
|
||||
currTaskDescr->RuntimeChunkSize() = modifier;
|
||||
PRINT(LD_IOD, "omp_set_schedule did set sched %d & modif %" PRIu64 "\n",
|
||||
@@ -359,23 +344,21 @@ EXTERN int omp_get_max_task_priority(void) {
|
||||
#define SET 1
|
||||
|
||||
EXTERN void omp_init_lock(omp_lock_t *lock) {
|
||||
*lock = UNSET;
|
||||
omp_unset_lock(lock);
|
||||
PRINT0(LD_IO, "call omp_init_lock()\n");
|
||||
}
|
||||
|
||||
EXTERN void omp_destroy_lock(omp_lock_t *lock) {
|
||||
omp_unset_lock(lock);
|
||||
PRINT0(LD_IO, "call omp_destroy_lock()\n");
|
||||
}
|
||||
|
||||
EXTERN void omp_set_lock(omp_lock_t *lock) {
|
||||
// int atomicCAS(int* address, int compare, int val);
|
||||
// (old == compare ? val : old)
|
||||
int compare = UNSET;
|
||||
int val = SET;
|
||||
|
||||
// TODO: not sure spinning is a good idea here..
|
||||
while (atomicCAS(lock, compare, val) != UNSET) {
|
||||
|
||||
while (atomicCAS(lock, UNSET, SET) != UNSET) {
|
||||
clock_t start = clock();
|
||||
clock_t now;
|
||||
for (;;) {
|
||||
@@ -391,9 +374,7 @@ EXTERN void omp_set_lock(omp_lock_t *lock) {
|
||||
}
|
||||
|
||||
EXTERN void omp_unset_lock(omp_lock_t *lock) {
|
||||
int compare = SET;
|
||||
int val = UNSET;
|
||||
int old = atomicCAS(lock, compare, val);
|
||||
(void)atomicExch(lock, UNSET);
|
||||
|
||||
PRINT0(LD_IO, "call omp_unset_lock()\n");
|
||||
}
|
||||
@@ -401,10 +382,7 @@ EXTERN void omp_unset_lock(omp_lock_t *lock) {
|
||||
EXTERN int omp_test_lock(omp_lock_t *lock) {
|
||||
// int atomicCAS(int* address, int compare, int val);
|
||||
// (old == compare ? val : old)
|
||||
int compare = UNSET;
|
||||
int val = SET;
|
||||
|
||||
int ret = atomicCAS(lock, compare, val);
|
||||
int ret = atomicAdd(lock, 0);
|
||||
|
||||
PRINT(LD_IO, "call omp_test_lock() return %d\n", ret);
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------ loop.cu - NVPTX OpenMP loop constructs --------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -14,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
#include "target_impl.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -93,105 +93,89 @@ public:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Support for Static Init
|
||||
|
||||
INLINE static void for_static_init(int32_t schedtype, int32_t *plastiter,
|
||||
T *plower, T *pupper, ST *pstride,
|
||||
ST chunk, bool IsSPMDExecutionMode,
|
||||
bool IsRuntimeUninitialized) {
|
||||
INLINE static void for_static_init(int32_t gtid, int32_t schedtype,
|
||||
int32_t *plastiter, T *plower, T *pupper,
|
||||
ST *pstride, ST chunk,
|
||||
bool IsSPMDExecutionMode) {
|
||||
// When IsRuntimeUninitialized is true, we assume that the caller is
|
||||
// in an L0 parallel region and that all worker threads participate.
|
||||
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
|
||||
// Assume we are in teams region or that we use a single block
|
||||
// per target region
|
||||
ST numberOfActiveOMPThreads = GetNumberOfOmpThreads(
|
||||
tid, IsSPMDExecutionMode, IsRuntimeUninitialized);
|
||||
ST numberOfActiveOMPThreads = GetNumberOfOmpThreads(IsSPMDExecutionMode);
|
||||
|
||||
// All warps that are in excess of the maximum requested, do
|
||||
// not execute the loop
|
||||
PRINT(LD_LOOP,
|
||||
"OMP Thread %d: schedule type %d, chunk size = %lld, mytid "
|
||||
"%d, num tids %d\n",
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized),
|
||||
schedtype, P64(chunk),
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized),
|
||||
GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized));
|
||||
ASSERT0(
|
||||
LT_FUSSY,
|
||||
(GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized)) <
|
||||
(GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized)),
|
||||
"current thread is not needed here; error");
|
||||
(int)gtid, (int)schedtype, (long long)chunk, (int)gtid,
|
||||
(int)numberOfActiveOMPThreads);
|
||||
ASSERT0(LT_FUSSY, gtid < numberOfActiveOMPThreads,
|
||||
"current thread is not needed here; error");
|
||||
|
||||
// copy
|
||||
int lastiter = 0;
|
||||
T lb = *plower;
|
||||
T ub = *pupper;
|
||||
ST stride = *pstride;
|
||||
T entityId, numberOfEntities;
|
||||
// init
|
||||
switch (schedtype) {
|
||||
switch (SCHEDULE_WITHOUT_MODIFIERS(schedtype)) {
|
||||
case kmp_sched_static_chunk: {
|
||||
if (chunk > 0) {
|
||||
entityId =
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized);
|
||||
numberOfEntities = GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, gtid,
|
||||
numberOfActiveOMPThreads);
|
||||
break;
|
||||
}
|
||||
} // note: if chunk <=0, use nochunk
|
||||
case kmp_sched_static_balanced_chunk: {
|
||||
if (chunk > 0) {
|
||||
// round up to make sure the chunk is enough to cover all iterations
|
||||
T tripCount = ub - lb + 1; // +1 because ub is inclusive
|
||||
T span = (tripCount + numberOfActiveOMPThreads - 1) /
|
||||
numberOfActiveOMPThreads;
|
||||
// perform chunk adjustment
|
||||
chunk = (span + chunk - 1) & ~(chunk - 1);
|
||||
|
||||
ASSERT0(LT_FUSSY, ub >= lb, "ub must be >= lb.");
|
||||
T oldUb = ub;
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, gtid,
|
||||
numberOfActiveOMPThreads);
|
||||
if (ub > oldUb)
|
||||
ub = oldUb;
|
||||
break;
|
||||
}
|
||||
} // note: if chunk <=0, use nochunk
|
||||
case kmp_sched_static_nochunk: {
|
||||
entityId =
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized);
|
||||
numberOfEntities = GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized);
|
||||
ForStaticNoChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
ForStaticNoChunk(lastiter, lb, ub, stride, chunk, gtid,
|
||||
numberOfActiveOMPThreads);
|
||||
break;
|
||||
}
|
||||
case kmp_sched_distr_static_chunk: {
|
||||
if (chunk > 0) {
|
||||
entityId = GetOmpTeamId();
|
||||
numberOfEntities = GetNumberOfOmpTeams();
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, GetOmpTeamId(),
|
||||
GetNumberOfOmpTeams());
|
||||
break;
|
||||
} // note: if chunk <=0, use nochunk
|
||||
}
|
||||
case kmp_sched_distr_static_nochunk: {
|
||||
entityId = GetOmpTeamId();
|
||||
numberOfEntities = GetNumberOfOmpTeams();
|
||||
|
||||
ForStaticNoChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
ForStaticNoChunk(lastiter, lb, ub, stride, chunk, GetOmpTeamId(),
|
||||
GetNumberOfOmpTeams());
|
||||
break;
|
||||
}
|
||||
case kmp_sched_distr_static_chunk_sched_static_chunkone: {
|
||||
entityId =
|
||||
GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized) *
|
||||
GetOmpTeamId() +
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized);
|
||||
numberOfEntities = GetNumberOfOmpTeams() *
|
||||
GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk,
|
||||
numberOfActiveOMPThreads * GetOmpTeamId() + gtid,
|
||||
GetNumberOfOmpTeams() * numberOfActiveOMPThreads);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ASSERT(LT_FUSSY, FALSE, "unknown schedtype %d", schedtype);
|
||||
ASSERT(LT_FUSSY, FALSE, "unknown schedtype %d", (int)schedtype);
|
||||
PRINT(LD_LOOP, "unknown schedtype %d, revert back to static chunk\n",
|
||||
schedtype);
|
||||
entityId =
|
||||
GetOmpThreadId(tid, IsSPMDExecutionMode, IsRuntimeUninitialized);
|
||||
numberOfEntities = GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, entityId,
|
||||
numberOfEntities);
|
||||
(int)schedtype);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, gtid,
|
||||
numberOfActiveOMPThreads);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// copy back
|
||||
@@ -200,11 +184,11 @@ public:
|
||||
*pupper = ub;
|
||||
*pstride = stride;
|
||||
PRINT(LD_LOOP,
|
||||
"Got sched: Active %d, total %d: lb %lld, ub %lld, stride %lld\n",
|
||||
GetNumberOfOmpThreads(tid, IsSPMDExecutionMode,
|
||||
IsRuntimeUninitialized),
|
||||
GetNumberOfWorkersInTeam(), P64(*plower), P64(*pupper),
|
||||
P64(*pstride));
|
||||
"Got sched: Active %d, total %d: lb %lld, ub %lld, stride %lld, last "
|
||||
"%d\n",
|
||||
(int)numberOfActiveOMPThreads, (int)GetNumberOfWorkersInTeam(),
|
||||
(long long)(*plower), (long long)(*pupper), (long long)(*pstride),
|
||||
(int)lastiter);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -215,18 +199,21 @@ public:
|
||||
schedule <= kmp_sched_ordered_last;
|
||||
}
|
||||
|
||||
INLINE static void dispatch_init(kmp_Indent *loc, int32_t threadId,
|
||||
INLINE static void dispatch_init(kmp_Ident *loc, int32_t threadId,
|
||||
kmp_sched_t schedule, T lb, T ub, ST st,
|
||||
ST chunk) {
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
if (checkRuntimeUninitialized(loc)) {
|
||||
// In SPMD mode no need to check parallelism level - dynamic scheduling
|
||||
// may appear only in L2 parallel regions with lightweight runtime.
|
||||
ASSERT0(LT_FUSSY, checkSPMDMode(loc), "Expected non-SPMD mode.");
|
||||
return;
|
||||
}
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor(tid);
|
||||
T tnum = currTaskDescr->ThreadsInTeam();
|
||||
T tnum = GetNumberOfOmpThreads(checkSPMDMode(loc));
|
||||
T tripCount = ub - lb + 1; // +1 because ub is inclusive
|
||||
ASSERT0(
|
||||
LT_FUSSY,
|
||||
GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized()) <
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
"current thread is not needed here; error");
|
||||
ASSERT0(LT_FUSSY, threadId < tnum,
|
||||
"current thread is not needed here; error");
|
||||
|
||||
/* Currently just ignore the monotonic and non-monotonic modifiers
|
||||
* (the compiler isn't producing them * yet anyway).
|
||||
@@ -244,7 +231,7 @@ public:
|
||||
__kmpc_barrier(loc, threadId);
|
||||
PRINT(LD_LOOP,
|
||||
"go sequential as tnum=%ld, trip count %lld, ordered sched=%d\n",
|
||||
(long)tnum, P64(tripCount), schedule);
|
||||
(long)tnum, (long long)tripCount, (int)schedule);
|
||||
schedule = kmp_sched_static_chunk;
|
||||
chunk = tripCount; // one thread gets the whole loop
|
||||
} else if (schedule == kmp_sched_runtime) {
|
||||
@@ -270,18 +257,20 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
PRINT(LD_LOOP, "Runtime sched is %d with chunk %lld\n", schedule,
|
||||
P64(chunk));
|
||||
PRINT(LD_LOOP, "Runtime sched is %d with chunk %lld\n", (int)schedule,
|
||||
(long long)chunk);
|
||||
} else if (schedule == kmp_sched_auto) {
|
||||
schedule = kmp_sched_static_chunk;
|
||||
chunk = 1;
|
||||
PRINT(LD_LOOP, "Auto sched is %d with chunk %lld\n", schedule,
|
||||
P64(chunk));
|
||||
PRINT(LD_LOOP, "Auto sched is %d with chunk %lld\n", (int)schedule,
|
||||
(long long)chunk);
|
||||
} else {
|
||||
PRINT(LD_LOOP, "Dyn sched is %d with chunk %lld\n", schedule, P64(chunk));
|
||||
PRINT(LD_LOOP, "Dyn sched is %d with chunk %lld\n", (int)schedule,
|
||||
(long long)chunk);
|
||||
ASSERT(LT_FUSSY,
|
||||
schedule == kmp_sched_dynamic || schedule == kmp_sched_guided,
|
||||
"unknown schedule %d & chunk %lld\n", schedule, P64(chunk));
|
||||
"unknown schedule %d & chunk %lld\n", (int)schedule,
|
||||
(long long)chunk);
|
||||
}
|
||||
|
||||
// init schedules
|
||||
@@ -294,9 +283,7 @@ public:
|
||||
// compute static chunk
|
||||
ST stride;
|
||||
int lastiter = 0;
|
||||
ForStaticChunk(
|
||||
lastiter, lb, ub, stride, chunk,
|
||||
GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized()), tnum);
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, threadId, tnum);
|
||||
// save computed params
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(tid) = chunk;
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid) = lb;
|
||||
@@ -304,11 +291,44 @@ public:
|
||||
PRINT(LD_LOOP,
|
||||
"dispatch init (static chunk) : num threads = %d, ub = %" PRId64
|
||||
", next lower bound = %llu, stride = %llu\n",
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
(int)tnum,
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->Stride(tid));
|
||||
(unsigned long long)
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
(unsigned long long)omptarget_nvptx_threadPrivateContext->Stride(
|
||||
tid));
|
||||
} else if (schedule == kmp_sched_static_balanced_chunk) {
|
||||
ASSERT0(LT_FUSSY, chunk > 0, "bad chunk value");
|
||||
// save sched state
|
||||
omptarget_nvptx_threadPrivateContext->ScheduleType(tid) = schedule;
|
||||
// save ub
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid) = ub;
|
||||
// compute static chunk
|
||||
ST stride;
|
||||
int lastiter = 0;
|
||||
// round up to make sure the chunk is enough to cover all iterations
|
||||
T span = (tripCount + tnum - 1) / tnum;
|
||||
// perform chunk adjustment
|
||||
chunk = (span + chunk - 1) & ~(chunk - 1);
|
||||
|
||||
T oldUb = ub;
|
||||
ForStaticChunk(lastiter, lb, ub, stride, chunk, threadId, tnum);
|
||||
ASSERT0(LT_FUSSY, ub >= lb, "ub must be >= lb.");
|
||||
if (ub > oldUb)
|
||||
ub = oldUb;
|
||||
// save computed params
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(tid) = chunk;
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid) = lb;
|
||||
omptarget_nvptx_threadPrivateContext->Stride(tid) = stride;
|
||||
PRINT(LD_LOOP,
|
||||
"dispatch init (static chunk) : num threads = %d, ub = %" PRId64
|
||||
", next lower bound = %llu, stride = %llu\n",
|
||||
(int)tnum,
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid),
|
||||
(unsigned long long)
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
(unsigned long long)omptarget_nvptx_threadPrivateContext->Stride(
|
||||
tid));
|
||||
} else if (schedule == kmp_sched_static_nochunk) {
|
||||
ASSERT0(LT_FUSSY, chunk == 0, "bad chunk value");
|
||||
// save sched state
|
||||
@@ -318,9 +338,7 @@ public:
|
||||
// compute static chunk
|
||||
ST stride;
|
||||
int lastiter = 0;
|
||||
ForStaticNoChunk(
|
||||
lastiter, lb, ub, stride, chunk,
|
||||
GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized()), tnum);
|
||||
ForStaticNoChunk(lastiter, lb, ub, stride, chunk, threadId, tnum);
|
||||
// save computed params
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(tid) = chunk;
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid) = lb;
|
||||
@@ -328,43 +346,69 @@ public:
|
||||
PRINT(LD_LOOP,
|
||||
"dispatch init (static nochunk) : num threads = %d, ub = %" PRId64
|
||||
", next lower bound = %llu, stride = %llu\n",
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
(int)tnum,
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->Stride(tid));
|
||||
|
||||
(unsigned long long)
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
(unsigned long long)omptarget_nvptx_threadPrivateContext->Stride(
|
||||
tid));
|
||||
} else if (schedule == kmp_sched_dynamic || schedule == kmp_sched_guided) {
|
||||
__kmpc_barrier(loc, threadId);
|
||||
// save sched state
|
||||
int teamId = GetOmpTeamId();
|
||||
// save data
|
||||
omptarget_nvptx_threadPrivateContext->ScheduleType(tid) = schedule;
|
||||
if (GetThreadIdInBlock() == 0) {
|
||||
if (chunk < 1)
|
||||
chunk = 1;
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(teamId) = chunk;
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(teamId) = ub;
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(teamId) = lb;
|
||||
if (chunk < 1)
|
||||
chunk = 1;
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(tid) = chunk;
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid) = ub;
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid) = lb;
|
||||
__kmpc_barrier(loc, threadId);
|
||||
if (tid == 0) {
|
||||
omptarget_nvptx_threadPrivateContext->Cnt() = 0;
|
||||
__threadfence_block();
|
||||
}
|
||||
__kmpc_barrier(loc, threadId);
|
||||
PRINT(LD_LOOP,
|
||||
"dispatch init (dyn) : num threads = %d, lb = %llu, ub = %" PRId64
|
||||
", chunk %" PRIu64 "\n",
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(teamId),
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(teamId),
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(teamId));
|
||||
(int)tnum,
|
||||
(unsigned long long)
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->Chunk(tid));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Support for dispatch next
|
||||
|
||||
INLINE static uint64_t Shuffle(__kmpc_impl_lanemask_t active, int64_t val,
|
||||
int leader) {
|
||||
uint32_t lo, hi;
|
||||
__kmpc_impl_unpack(val, lo, hi);
|
||||
hi = __kmpc_impl_shfl_sync(active, hi, leader);
|
||||
lo = __kmpc_impl_shfl_sync(active, lo, leader);
|
||||
return __kmpc_impl_pack(lo, hi);
|
||||
}
|
||||
|
||||
INLINE static uint64_t NextIter() {
|
||||
__kmpc_impl_lanemask_t active = __kmpc_impl_activemask();
|
||||
uint32_t leader = __kmpc_impl_ffs(active) - 1;
|
||||
uint32_t change = __kmpc_impl_popc(active);
|
||||
__kmpc_impl_lanemask_t lane_mask_lt = __kmpc_impl_lanemask_lt();
|
||||
unsigned int rank = __kmpc_impl_popc(active & lane_mask_lt);
|
||||
uint64_t warp_res;
|
||||
if (rank == 0) {
|
||||
warp_res = atomicAdd(
|
||||
(unsigned long long *)&omptarget_nvptx_threadPrivateContext->Cnt(),
|
||||
change);
|
||||
}
|
||||
warp_res = Shuffle(active, warp_res, leader);
|
||||
return warp_res + rank;
|
||||
}
|
||||
|
||||
INLINE static int DynamicNextChunk(T &lb, T &ub, T chunkSize,
|
||||
int64_t &loopLowerBound,
|
||||
T loopUpperBound) {
|
||||
// calculate lower bound for all lanes in the warp
|
||||
lb = atomicAdd((unsigned long long *)&loopLowerBound,
|
||||
(unsigned long long)chunkSize);
|
||||
T loopLowerBound, T loopUpperBound) {
|
||||
T N = NextIter();
|
||||
lb = loopLowerBound + N * chunkSize;
|
||||
ub = lb + chunkSize - 1; // Clang uses i <= ub
|
||||
|
||||
// 3 result cases:
|
||||
@@ -374,39 +418,42 @@ public:
|
||||
// c. lb and ub >= loopUpperBound: empty chunk --> FINISHED
|
||||
// a.
|
||||
if (lb <= loopUpperBound && ub < loopUpperBound) {
|
||||
PRINT(LD_LOOPD, "lb %lld, ub %lld, loop ub %lld; not finished\n", P64(lb),
|
||||
P64(ub), P64(loopUpperBound));
|
||||
PRINT(LD_LOOPD, "lb %lld, ub %lld, loop ub %lld; not finished\n",
|
||||
(long long)lb, (long long)ub, (long long)loopUpperBound);
|
||||
return NOT_FINISHED;
|
||||
}
|
||||
// b.
|
||||
if (lb <= loopUpperBound) {
|
||||
PRINT(LD_LOOPD, "lb %lld, ub %lld, loop ub %lld; clip to loop ub\n",
|
||||
P64(lb), P64(ub), P64(loopUpperBound));
|
||||
(long long)lb, (long long)ub, (long long)loopUpperBound);
|
||||
ub = loopUpperBound;
|
||||
return LAST_CHUNK;
|
||||
}
|
||||
// c. if we are here, we are in case 'c'
|
||||
lb = loopUpperBound + 2;
|
||||
ub = loopUpperBound + 1;
|
||||
PRINT(LD_LOOPD, "lb %lld, ub %lld, loop ub %lld; finished\n", P64(lb),
|
||||
P64(ub), P64(loopUpperBound));
|
||||
PRINT(LD_LOOPD, "lb %lld, ub %lld, loop ub %lld; finished\n", (long long)lb,
|
||||
(long long)ub, (long long)loopUpperBound);
|
||||
return FINISHED;
|
||||
}
|
||||
|
||||
// On Pascal, with inlining of the runtime into the user application,
|
||||
// this code deadlocks. This is probably because different threads
|
||||
// in a warp cannot make independent progress.
|
||||
NOINLINE static int dispatch_next(int32_t *plast, T *plower, T *pupper,
|
||||
ST *pstride) {
|
||||
INLINE static int dispatch_next(kmp_Ident *loc, int32_t gtid, int32_t *plast,
|
||||
T *plower, T *pupper, ST *pstride) {
|
||||
if (checkRuntimeUninitialized(loc)) {
|
||||
// In SPMD mode no need to check parallelism level - dynamic scheduling
|
||||
// may appear only in L2 parallel regions with lightweight runtime.
|
||||
ASSERT0(LT_FUSSY, checkSPMDMode(loc), "Expected non-SPMD mode.");
|
||||
if (*plast)
|
||||
return DISPATCH_FINISHED;
|
||||
*plast = 1;
|
||||
return DISPATCH_NOTFINISHED;
|
||||
}
|
||||
// ID of a thread in its own warp
|
||||
|
||||
// automatically selects thread or warp ID based on selected implementation
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
ASSERT0(
|
||||
LT_FUSSY,
|
||||
GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized()) <
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
"current thread is not needed here; error");
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
ASSERT0(LT_FUSSY, gtid < GetNumberOfOmpThreads(checkSPMDMode(loc)),
|
||||
"current thread is not needed here; error");
|
||||
// retrieve schedule
|
||||
kmp_sched_t schedule =
|
||||
omptarget_nvptx_threadPrivateContext->ScheduleType(tid);
|
||||
@@ -419,7 +466,7 @@ public:
|
||||
// finished?
|
||||
if (myLb > ub) {
|
||||
PRINT(LD_LOOP, "static loop finished with myLb %lld, ub %lld\n",
|
||||
P64(myLb), P64(ub));
|
||||
(long long)myLb, (long long)ub);
|
||||
return DISPATCH_FINISHED;
|
||||
}
|
||||
// not finished, save current bounds
|
||||
@@ -435,18 +482,17 @@ public:
|
||||
ST stride = omptarget_nvptx_threadPrivateContext->Stride(tid);
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid) = myLb + stride;
|
||||
PRINT(LD_LOOP, "static loop continues with myLb %lld, myUb %lld\n",
|
||||
P64(*plower), P64(*pupper));
|
||||
(long long)*plower, (long long)*pupper);
|
||||
return DISPATCH_NOTFINISHED;
|
||||
}
|
||||
ASSERT0(LT_FUSSY,
|
||||
schedule == kmp_sched_dynamic || schedule == kmp_sched_guided,
|
||||
"bad sched");
|
||||
T myLb, myUb;
|
||||
int teamId = GetOmpTeamId();
|
||||
int finished = DynamicNextChunk(
|
||||
myLb, myUb, omptarget_nvptx_threadPrivateContext->Chunk(teamId),
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(teamId),
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(teamId));
|
||||
myLb, myUb, omptarget_nvptx_threadPrivateContext->Chunk(tid),
|
||||
omptarget_nvptx_threadPrivateContext->NextLowerBound(tid),
|
||||
omptarget_nvptx_threadPrivateContext->LoopUpperBound(tid));
|
||||
|
||||
if (finished == FINISHED)
|
||||
return DISPATCH_FINISHED;
|
||||
@@ -458,10 +504,11 @@ public:
|
||||
*pstride = 1;
|
||||
|
||||
PRINT(LD_LOOP,
|
||||
"Got sched: active %d, total %d: lb %lld, ub %lld, stride = %lld\n",
|
||||
GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized()),
|
||||
GetNumberOfWorkersInTeam(), P64(*plower), P64(*pupper),
|
||||
P64(*pstride));
|
||||
"Got sched: active %d, total %d: lb %lld, ub %lld, stride = %lld, "
|
||||
"last %d\n",
|
||||
(int)GetNumberOfOmpThreads(isSPMDMode()),
|
||||
(int)GetNumberOfWorkersInTeam(), (long long)*plower,
|
||||
(long long)*pupper, (long long)*pstride, (int)*plast);
|
||||
return DISPATCH_NOTFINISHED;
|
||||
}
|
||||
|
||||
@@ -479,7 +526,7 @@ public:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init
|
||||
EXTERN void __kmpc_dispatch_init_4(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_dispatch_init_4(kmp_Ident *loc, int32_t tid,
|
||||
int32_t schedule, int32_t lb, int32_t ub,
|
||||
int32_t st, int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_init_4\n");
|
||||
@@ -487,7 +534,7 @@ EXTERN void __kmpc_dispatch_init_4(kmp_Indent *loc, int32_t tid,
|
||||
loc, tid, (kmp_sched_t)schedule, lb, ub, st, chunk);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_init_4u(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_dispatch_init_4u(kmp_Ident *loc, int32_t tid,
|
||||
int32_t schedule, uint32_t lb, uint32_t ub,
|
||||
int32_t st, int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_init_4u\n");
|
||||
@@ -495,7 +542,7 @@ EXTERN void __kmpc_dispatch_init_4u(kmp_Indent *loc, int32_t tid,
|
||||
loc, tid, (kmp_sched_t)schedule, lb, ub, st, chunk);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_init_8(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_dispatch_init_8(kmp_Ident *loc, int32_t tid,
|
||||
int32_t schedule, int64_t lb, int64_t ub,
|
||||
int64_t st, int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_init_8\n");
|
||||
@@ -503,7 +550,7 @@ EXTERN void __kmpc_dispatch_init_8(kmp_Indent *loc, int32_t tid,
|
||||
loc, tid, (kmp_sched_t)schedule, lb, ub, st, chunk);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_init_8u(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_dispatch_init_8u(kmp_Ident *loc, int32_t tid,
|
||||
int32_t schedule, uint64_t lb, uint64_t ub,
|
||||
int64_t st, int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_init_8u\n");
|
||||
@@ -512,53 +559,53 @@ EXTERN void __kmpc_dispatch_init_8u(kmp_Indent *loc, int32_t tid,
|
||||
}
|
||||
|
||||
// next
|
||||
EXTERN int __kmpc_dispatch_next_4(kmp_Indent *loc, int32_t tid, int32_t *p_last,
|
||||
EXTERN int __kmpc_dispatch_next_4(kmp_Ident *loc, int32_t tid, int32_t *p_last,
|
||||
int32_t *p_lb, int32_t *p_ub, int32_t *p_st) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_next_4\n");
|
||||
return omptarget_nvptx_LoopSupport<int32_t, int32_t>::dispatch_next(
|
||||
p_last, p_lb, p_ub, p_st);
|
||||
loc, tid, p_last, p_lb, p_ub, p_st);
|
||||
}
|
||||
|
||||
EXTERN int __kmpc_dispatch_next_4u(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN int __kmpc_dispatch_next_4u(kmp_Ident *loc, int32_t tid,
|
||||
int32_t *p_last, uint32_t *p_lb,
|
||||
uint32_t *p_ub, int32_t *p_st) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_next_4u\n");
|
||||
return omptarget_nvptx_LoopSupport<uint32_t, int32_t>::dispatch_next(
|
||||
p_last, p_lb, p_ub, p_st);
|
||||
loc, tid, p_last, p_lb, p_ub, p_st);
|
||||
}
|
||||
|
||||
EXTERN int __kmpc_dispatch_next_8(kmp_Indent *loc, int32_t tid, int32_t *p_last,
|
||||
EXTERN int __kmpc_dispatch_next_8(kmp_Ident *loc, int32_t tid, int32_t *p_last,
|
||||
int64_t *p_lb, int64_t *p_ub, int64_t *p_st) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_next_8\n");
|
||||
return omptarget_nvptx_LoopSupport<int64_t, int64_t>::dispatch_next(
|
||||
p_last, p_lb, p_ub, p_st);
|
||||
loc, tid, p_last, p_lb, p_ub, p_st);
|
||||
}
|
||||
|
||||
EXTERN int __kmpc_dispatch_next_8u(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN int __kmpc_dispatch_next_8u(kmp_Ident *loc, int32_t tid,
|
||||
int32_t *p_last, uint64_t *p_lb,
|
||||
uint64_t *p_ub, int64_t *p_st) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_next_8u\n");
|
||||
return omptarget_nvptx_LoopSupport<uint64_t, int64_t>::dispatch_next(
|
||||
p_last, p_lb, p_ub, p_st);
|
||||
loc, tid, p_last, p_lb, p_ub, p_st);
|
||||
}
|
||||
|
||||
// fini
|
||||
EXTERN void __kmpc_dispatch_fini_4(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_dispatch_fini_4(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_fini_4\n");
|
||||
omptarget_nvptx_LoopSupport<int32_t, int32_t>::dispatch_fini();
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_fini_4u(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_dispatch_fini_4u(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_fini_4u\n");
|
||||
omptarget_nvptx_LoopSupport<uint32_t, int32_t>::dispatch_fini();
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_fini_8(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_dispatch_fini_8(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_fini_8\n");
|
||||
omptarget_nvptx_LoopSupport<int64_t, int64_t>::dispatch_fini();
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_dispatch_fini_8u(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_dispatch_fini_8u(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_dispatch_fini_8u\n");
|
||||
omptarget_nvptx_LoopSupport<uint64_t, int64_t>::dispatch_fini();
|
||||
}
|
||||
@@ -567,151 +614,143 @@ EXTERN void __kmpc_dispatch_fini_8u(kmp_Indent *loc, int32_t tid) {
|
||||
// KMP interface implementation (static loops)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_for_static_init_4(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_4(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4\n");
|
||||
omptarget_nvptx_LoopSupport<int32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk, isSPMDMode(),
|
||||
isRuntimeUninitialized());
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
checkSPMDMode(loc));
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_for_static_init_4u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_4u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
uint32_t *plower, uint32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4u\n");
|
||||
omptarget_nvptx_LoopSupport<uint32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk, isSPMDMode(),
|
||||
isRuntimeUninitialized());
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
checkSPMDMode(loc));
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_for_static_init_8(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_8(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8\n");
|
||||
omptarget_nvptx_LoopSupport<int64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk, isSPMDMode(),
|
||||
isRuntimeUninitialized());
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
checkSPMDMode(loc));
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_for_static_init_8u(kmp_Indent *loc, int32_t global_tid,
|
||||
EXTERN void __kmpc_for_static_init_8u(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
uint64_t *plower, uint64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8u\n");
|
||||
omptarget_nvptx_LoopSupport<uint64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk, isSPMDMode(),
|
||||
isRuntimeUninitialized());
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
checkSPMDMode(loc));
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_4_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper,
|
||||
int32_t *pstride, int32_t incr,
|
||||
int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4_simple_spmd\n");
|
||||
omptarget_nvptx_LoopSupport<int32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4u_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_4u_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype,
|
||||
int32_t *plastiter, uint32_t *plower,
|
||||
uint32_t *pupper, int32_t *pstride,
|
||||
int32_t incr, int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4u_simple_spmd\n");
|
||||
omptarget_nvptx_LoopSupport<uint32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_8_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype, int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper,
|
||||
int64_t *pstride, int64_t incr,
|
||||
int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8_simple_spmd\n");
|
||||
omptarget_nvptx_LoopSupport<int64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8u_simple_spmd(kmp_Indent *loc, int32_t global_tid,
|
||||
void __kmpc_for_static_init_8u_simple_spmd(kmp_Ident *loc, int32_t global_tid,
|
||||
int32_t schedtype,
|
||||
int32_t *plastiter, uint64_t *plower,
|
||||
uint64_t *pupper, int64_t *pstride,
|
||||
int64_t incr, int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8u_simple_spmd\n");
|
||||
omptarget_nvptx_LoopSupport<uint64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
int32_t *plower, int32_t *pupper, int32_t *pstride, int32_t incr,
|
||||
int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4_simple_generic\n");
|
||||
omptarget_nvptx_LoopSupport<int32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_4u_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
uint32_t *plower, uint32_t *pupper, int32_t *pstride, int32_t incr,
|
||||
int32_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_4u_simple_generic\n");
|
||||
omptarget_nvptx_LoopSupport<uint32_t, int32_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
int64_t *plower, int64_t *pupper, int64_t *pstride, int64_t incr,
|
||||
int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8_simple_generic\n");
|
||||
omptarget_nvptx_LoopSupport<int64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
void __kmpc_for_static_init_8u_simple_generic(
|
||||
kmp_Indent *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t schedtype, int32_t *plastiter,
|
||||
uint64_t *plower, uint64_t *pupper, int64_t *pstride, int64_t incr,
|
||||
int64_t chunk) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_init_8u_simple_generic\n");
|
||||
omptarget_nvptx_LoopSupport<uint64_t, int64_t>::for_static_init(
|
||||
schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false,
|
||||
/*IsRuntimeUninitialized=*/true);
|
||||
global_tid, schedtype, plastiter, plower, pupper, pstride, chunk,
|
||||
/*IsSPMDExecutionMode=*/false);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_for_static_fini(kmp_Indent *loc, int32_t global_tid) {
|
||||
EXTERN void __kmpc_for_static_fini(kmp_Ident *loc, int32_t global_tid) {
|
||||
PRINT0(LD_IO, "call kmpc_for_static_fini\n");
|
||||
}
|
||||
|
||||
@@ -733,19 +772,18 @@ INLINE void syncWorkersInGenericMode(uint32_t NumThreads) {
|
||||
}
|
||||
}; // namespace
|
||||
|
||||
EXTERN void __kmpc_reduce_conditional_lastprivate(kmp_Indent *loc, int32_t gtid,
|
||||
EXTERN void __kmpc_reduce_conditional_lastprivate(kmp_Ident *loc, int32_t gtid,
|
||||
int32_t varNum, void *array) {
|
||||
PRINT0(LD_IO, "call to __kmpc_reduce_conditional_lastprivate(...)\n");
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc),
|
||||
"Expected non-SPMD mode + initialized runtime.");
|
||||
|
||||
omptarget_nvptx_TeamDescr &teamDescr = getMyTeamDescriptor();
|
||||
int tid = GetOmpThreadId(GetLogicalThreadIdInBlock(), isSPMDMode(),
|
||||
isRuntimeUninitialized());
|
||||
uint32_t NumThreads = GetNumberOfOmpThreads(
|
||||
GetLogicalThreadIdInBlock(), isSPMDMode(), isRuntimeUninitialized());
|
||||
uint32_t NumThreads = GetNumberOfOmpThreads(checkSPMDMode(loc));
|
||||
uint64_t *Buffer = teamDescr.getLastprivateIterBuffer();
|
||||
for (unsigned i = 0; i < varNum; i++) {
|
||||
// Reset buffer.
|
||||
if (tid == 0)
|
||||
if (gtid == 0)
|
||||
*Buffer = 0; // Reset to minimum loop iteration value.
|
||||
|
||||
// Barrier.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//===--- nvptx_interface.h - OpenMP interface definitions -------- CUDA -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _NVPTX_INTERFACE_H_
|
||||
#define _NVPTX_INTERFACE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define EXTERN extern "C" __device__
|
||||
typedef uint32_t __kmpc_impl_lanemask_t;
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------ omp_data.cu - NVPTX OpenMP GPU objects --------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -27,6 +26,15 @@ __device__
|
||||
omptarget_nvptx_Queue<omptarget_nvptx_ThreadPrivateContext, OMP_STATE_COUNT>
|
||||
omptarget_nvptx_device_State[MAX_SM];
|
||||
|
||||
__device__ omptarget_nvptx_SimpleMemoryManager
|
||||
omptarget_nvptx_simpleMemoryManager;
|
||||
__device__ __shared__ uint32_t usedMemIdx;
|
||||
__device__ __shared__ uint32_t usedSlotIdx;
|
||||
|
||||
__device__ __shared__ uint8_t parallelLevel[MAX_THREADS_PER_TEAM / WARPSIZE];
|
||||
__device__ __shared__ uint16_t threadLimit;
|
||||
__device__ __shared__ uint16_t threadsInTeam;
|
||||
__device__ __shared__ uint16_t nThreads;
|
||||
// Pointer to this team's OpenMP state object
|
||||
__device__ __shared__
|
||||
omptarget_nvptx_ThreadPrivateContext *omptarget_nvptx_threadPrivateContext;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--- omptarget-nvptx.cu - NVPTX OpenMP GPU initialization ---- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -12,6 +11,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
#include "target_impl.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// global data tables
|
||||
@@ -21,23 +21,11 @@ extern __device__
|
||||
omptarget_nvptx_Queue<omptarget_nvptx_ThreadPrivateContext, OMP_STATE_COUNT>
|
||||
omptarget_nvptx_device_State[MAX_SM];
|
||||
|
||||
extern __device__ __shared__
|
||||
omptarget_nvptx_ThreadPrivateContext *omptarget_nvptx_threadPrivateContext;
|
||||
|
||||
//
|
||||
// The team master sets the outlined function and its arguments in these
|
||||
// variables to communicate with the workers. Since they are in shared memory,
|
||||
// there is one copy of these variables for each kernel, instance, and team.
|
||||
//
|
||||
extern volatile __device__ __shared__ omptarget_nvptx_WorkFn
|
||||
omptarget_nvptx_workFn;
|
||||
extern __device__ __shared__ uint32_t execution_param;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// init entry points
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE unsigned smid() {
|
||||
INLINE static unsigned smid() {
|
||||
unsigned id;
|
||||
asm("mov.u32 %0, %%smid;" : "=r"(id));
|
||||
return id;
|
||||
@@ -53,13 +41,11 @@ EXTERN void __kmpc_kernel_init_params(void *Ptr) {
|
||||
EXTERN void __kmpc_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime) {
|
||||
PRINT(LD_IO, "call to __kmpc_kernel_init with version %f\n",
|
||||
OMPTARGET_NVPTX_VERSION);
|
||||
|
||||
if (!RequiresOMPRuntime) {
|
||||
// If OMP runtime is not required don't initialize OMP state.
|
||||
setExecutionParameters(Generic, RuntimeUninitialized);
|
||||
return;
|
||||
}
|
||||
ASSERT0(LT_FUSSY, RequiresOMPRuntime,
|
||||
"Generic always requires initialized runtime.");
|
||||
setExecutionParameters(Generic, RuntimeInitialized);
|
||||
for (int I = 0; I < MAX_THREADS_PER_TEAM / WARPSIZE; ++I)
|
||||
parallelLevel[I] = 0;
|
||||
|
||||
int threadIdInBlock = GetThreadIdInBlock();
|
||||
ASSERT0(LT_FUSSY, threadIdInBlock == GetMasterThreadID(),
|
||||
@@ -68,14 +54,12 @@ EXTERN void __kmpc_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime) {
|
||||
|
||||
// Get a state object from the queue.
|
||||
int slot = smid() % MAX_SM;
|
||||
usedSlotIdx = slot;
|
||||
omptarget_nvptx_threadPrivateContext =
|
||||
omptarget_nvptx_device_State[slot].Dequeue();
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
|
||||
omptarget_nvptx_threadPrivateContext->SetSourceQueue(slot);
|
||||
#endif
|
||||
|
||||
// init thread private
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(/*isSPMDExecutionMode=*/false);
|
||||
omptarget_nvptx_threadPrivateContext->InitThreadPrivateContext(threadId);
|
||||
|
||||
// init team context
|
||||
@@ -90,21 +74,18 @@ EXTERN void __kmpc_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime) {
|
||||
// set number of threads and thread limit in team to started value
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
currTaskDescr->NThreads() = GetNumberOfWorkersInTeam();
|
||||
currTaskDescr->ThreadLimit() = ThreadLimit;
|
||||
nThreads = GetNumberOfWorkersInTeam();
|
||||
threadLimit = ThreadLimit;
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_kernel_deinit(int16_t IsOMPRuntimeInitialized) {
|
||||
if (IsOMPRuntimeInitialized) {
|
||||
// Enqueue omp state object for use by another team.
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
|
||||
int slot = omptarget_nvptx_threadPrivateContext->GetSourceQueue();
|
||||
#else
|
||||
int slot = smid() % MAX_SM;
|
||||
#endif
|
||||
omptarget_nvptx_device_State[slot].Enqueue(
|
||||
omptarget_nvptx_threadPrivateContext);
|
||||
}
|
||||
PRINT0(LD_IO, "call to __kmpc_kernel_deinit\n");
|
||||
ASSERT0(LT_FUSSY, IsOMPRuntimeInitialized,
|
||||
"Generic always requires initialized runtime.");
|
||||
// Enqueue omp state object for use by another team.
|
||||
int slot = usedSlotIdx;
|
||||
omptarget_nvptx_device_State[slot].Enqueue(
|
||||
omptarget_nvptx_threadPrivateContext);
|
||||
// Done with work. Kill the workers.
|
||||
omptarget_nvptx_workFn = 0;
|
||||
}
|
||||
@@ -113,33 +94,39 @@ EXTERN void __kmpc_spmd_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime,
|
||||
int16_t RequiresDataSharing) {
|
||||
PRINT0(LD_IO, "call to __kmpc_spmd_kernel_init\n");
|
||||
|
||||
setExecutionParameters(Spmd, RequiresOMPRuntime ? RuntimeInitialized
|
||||
: RuntimeUninitialized);
|
||||
int threadId = GetThreadIdInBlock();
|
||||
if (threadId == 0) {
|
||||
usedSlotIdx = smid() % MAX_SM;
|
||||
parallelLevel[0] =
|
||||
1 + (GetNumberOfThreadsInBlock() > 1 ? OMP_ACTIVE_PARALLEL_LEVEL : 0);
|
||||
} else if (GetLaneId() == 0) {
|
||||
parallelLevel[GetWarpId()] =
|
||||
1 + (GetNumberOfThreadsInBlock() > 1 ? OMP_ACTIVE_PARALLEL_LEVEL : 0);
|
||||
}
|
||||
if (!RequiresOMPRuntime) {
|
||||
// If OMP runtime is not required don't initialize OMP state.
|
||||
setExecutionParameters(Spmd, RuntimeUninitialized);
|
||||
// Runtime is not required - exit.
|
||||
__kmpc_impl_syncthreads();
|
||||
return;
|
||||
}
|
||||
setExecutionParameters(Spmd, RuntimeInitialized);
|
||||
|
||||
//
|
||||
// Team Context Initialization.
|
||||
//
|
||||
// In SPMD mode there is no master thread so use any cuda thread for team
|
||||
// context initialization.
|
||||
int threadId = GetThreadIdInBlock();
|
||||
if (threadId == 0) {
|
||||
// Get a state object from the queue.
|
||||
int slot = smid() % MAX_SM;
|
||||
omptarget_nvptx_threadPrivateContext =
|
||||
omptarget_nvptx_device_State[slot].Dequeue();
|
||||
omptarget_nvptx_device_State[usedSlotIdx].Dequeue();
|
||||
|
||||
omptarget_nvptx_TeamDescr &currTeamDescr = getMyTeamDescriptor();
|
||||
omptarget_nvptx_WorkDescr &workDescr = getMyWorkDescriptor();
|
||||
// init team context
|
||||
currTeamDescr.InitTeamDescr();
|
||||
// init counters (copy start to init)
|
||||
workDescr.CounterGroup().Reset();
|
||||
}
|
||||
__syncthreads();
|
||||
__kmpc_impl_syncthreads();
|
||||
|
||||
omptarget_nvptx_TeamDescr &currTeamDescr = getMyTeamDescriptor();
|
||||
omptarget_nvptx_WorkDescr &workDescr = getMyWorkDescriptor();
|
||||
@@ -150,22 +137,18 @@ EXTERN void __kmpc_spmd_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime,
|
||||
omptarget_nvptx_TaskDescr *newTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->Level1TaskDescr(threadId);
|
||||
ASSERT0(LT_FUSSY, newTaskDescr, "expected a task descr");
|
||||
newTaskDescr->InitLevelOneTaskDescr(ThreadLimit,
|
||||
currTeamDescr.LevelZeroTaskDescr());
|
||||
newTaskDescr->ThreadLimit() = ThreadLimit;
|
||||
newTaskDescr->InitLevelOneTaskDescr(currTeamDescr.LevelZeroTaskDescr());
|
||||
// install new top descriptor
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(threadId,
|
||||
newTaskDescr);
|
||||
|
||||
// init thread private from init value
|
||||
workDescr.CounterGroup().Init(
|
||||
omptarget_nvptx_threadPrivateContext->Priv(threadId));
|
||||
PRINT(LD_PAR,
|
||||
"thread will execute parallel region with id %d in a team of "
|
||||
"%d threads\n",
|
||||
newTaskDescr->ThreadId(), newTaskDescr->ThreadsInTeam());
|
||||
(int)newTaskDescr->ThreadId(), (int)ThreadLimit);
|
||||
|
||||
if (RequiresDataSharing && threadId % WARPSIZE == 0) {
|
||||
if (RequiresDataSharing && GetLaneId() == 0) {
|
||||
// Warp master innitializes data sharing environment.
|
||||
unsigned WID = threadId / WARPSIZE;
|
||||
__kmpc_data_sharing_slot *RootS = currTeamDescr.RootS(
|
||||
@@ -175,14 +158,21 @@ EXTERN void __kmpc_spmd_kernel_init(int ThreadLimit, int16_t RequiresOMPRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_spmd_kernel_deinit() {
|
||||
EXTERN __attribute__((deprecated)) void __kmpc_spmd_kernel_deinit() {
|
||||
__kmpc_spmd_kernel_deinit_v2(isRuntimeInitialized());
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_spmd_kernel_deinit_v2(int16_t RequiresOMPRuntime) {
|
||||
// We're not going to pop the task descr stack of each thread since
|
||||
// there are no more parallel regions in SPMD mode.
|
||||
__syncthreads();
|
||||
if (!RequiresOMPRuntime)
|
||||
return;
|
||||
|
||||
__kmpc_impl_syncthreads();
|
||||
int threadId = GetThreadIdInBlock();
|
||||
if (threadId == 0) {
|
||||
// Enqueue omp state object for use by another team.
|
||||
int slot = smid() % MAX_SM;
|
||||
int slot = usedSlotIdx;
|
||||
omptarget_nvptx_device_State[slot].Enqueue(
|
||||
omptarget_nvptx_threadPrivateContext);
|
||||
}
|
||||
@@ -190,5 +180,6 @@ EXTERN void __kmpc_spmd_kernel_deinit() {
|
||||
|
||||
// Return true if the current target region is executed in SPMD mode.
|
||||
EXTERN int8_t __kmpc_is_spmd_exec_mode() {
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_is_spmd_exec_mode\n");
|
||||
return isSPMDMode();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===---- omptarget-nvptx.h - NVPTX OpenMP GPU initialization ---- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -26,7 +25,6 @@
|
||||
#include <math.h>
|
||||
|
||||
// local includes
|
||||
#include "counter_group.h"
|
||||
#include "debug.h" // debug
|
||||
#include "interface.h" // interfaces with omp, compiler, and user
|
||||
#include "option.h" // choices we have
|
||||
@@ -47,23 +45,6 @@
|
||||
#define BARRIER_COUNTER 0
|
||||
#define ORDERED_COUNTER 1
|
||||
|
||||
// Macros for Cuda intrinsics
|
||||
// In Cuda 9.0, the *_sync() version takes an extra argument 'mask'.
|
||||
// Also, __ballot(1) in Cuda 8.0 is replaced with __activemask().
|
||||
#if defined(CUDART_VERSION) && CUDART_VERSION >= 9000
|
||||
#define __SHFL_SYNC(mask, var, srcLane) __shfl_sync((mask), (var), (srcLane))
|
||||
#define __SHFL_DOWN_SYNC(mask, var, delta, width) \
|
||||
__shfl_down_sync((mask), (var), (delta), (width))
|
||||
#define __BALLOT_SYNC(mask, predicate) __ballot_sync((mask), (predicate))
|
||||
#define __ACTIVEMASK() __activemask()
|
||||
#else
|
||||
#define __SHFL_SYNC(mask, var, srcLane) __shfl((var), (srcLane))
|
||||
#define __SHFL_DOWN_SYNC(mask, var, delta, width) \
|
||||
__shfl_down((var), (delta), (width))
|
||||
#define __BALLOT_SYNC(mask, predicate) __ballot((predicate))
|
||||
#define __ACTIVEMASK() __ballot(1)
|
||||
#endif
|
||||
|
||||
// arguments needed for L0 parallelism only.
|
||||
class omptarget_nvptx_SharedArgs {
|
||||
public:
|
||||
@@ -91,7 +72,7 @@ public:
|
||||
}
|
||||
}
|
||||
// Called by all threads.
|
||||
INLINE void **GetArgs() { return args; };
|
||||
INLINE void **GetArgs() const { return args; };
|
||||
private:
|
||||
// buffer of pre-allocated arguments.
|
||||
void *buffer[MAX_SHARED_ARGS];
|
||||
@@ -102,7 +83,8 @@ private:
|
||||
uint32_t nArgs;
|
||||
};
|
||||
|
||||
extern __device__ __shared__ omptarget_nvptx_SharedArgs omptarget_nvptx_globalArgs;
|
||||
extern __device__ __shared__ omptarget_nvptx_SharedArgs
|
||||
omptarget_nvptx_globalArgs;
|
||||
|
||||
// Data sharing related quantities, need to match what is used in the compiler.
|
||||
enum DATA_SHARING_SIZES {
|
||||
@@ -114,6 +96,8 @@ enum DATA_SHARING_SIZES {
|
||||
DS_Worker_Warp_Slot_Size = WARPSIZE * DS_Slot_Size,
|
||||
// The maximum number of warps in use
|
||||
DS_Max_Warp_Number = 32,
|
||||
// The size of the preallocated shared memory buffer per team
|
||||
DS_Shared_Memory_Size = 128,
|
||||
};
|
||||
|
||||
// Data structure to keep in shared memory that traces the current slot, stack,
|
||||
@@ -122,8 +106,8 @@ enum DATA_SHARING_SIZES {
|
||||
struct DataSharingStateTy {
|
||||
__kmpc_data_sharing_slot *SlotPtr[DS_Max_Warp_Number];
|
||||
void *StackPtr[DS_Max_Warp_Number];
|
||||
void *FramePtr[DS_Max_Warp_Number];
|
||||
int32_t ActiveThreads[DS_Max_Warp_Number];
|
||||
void * volatile FramePtr[DS_Max_Warp_Number];
|
||||
__kmpc_impl_lanemask_t ActiveThreads[DS_Max_Warp_Number];
|
||||
};
|
||||
// Additional worker slot type which is initialized with the default worker slot
|
||||
// size of 4*32 bytes.
|
||||
@@ -151,43 +135,31 @@ extern __device__ __shared__ DataSharingStateTy DataSharingState;
|
||||
class omptarget_nvptx_TaskDescr {
|
||||
public:
|
||||
// methods for flags
|
||||
INLINE omp_sched_t GetRuntimeSched();
|
||||
INLINE omp_sched_t GetRuntimeSched() const;
|
||||
INLINE void SetRuntimeSched(omp_sched_t sched);
|
||||
INLINE int IsDynamic() { return items.flags & TaskDescr_IsDynamic; }
|
||||
INLINE void SetDynamic() {
|
||||
items.flags = items.flags | TaskDescr_IsDynamic;
|
||||
}
|
||||
INLINE void ClearDynamic() {
|
||||
items.flags = items.flags & (~TaskDescr_IsDynamic);
|
||||
}
|
||||
INLINE int InParallelRegion() { return items.flags & TaskDescr_InPar; }
|
||||
INLINE int InL2OrHigherParallelRegion() {
|
||||
INLINE int InParallelRegion() const { return items.flags & TaskDescr_InPar; }
|
||||
INLINE int InL2OrHigherParallelRegion() const {
|
||||
return items.flags & TaskDescr_InParL2P;
|
||||
}
|
||||
INLINE int IsParallelConstruct() {
|
||||
INLINE int IsParallelConstruct() const {
|
||||
return items.flags & TaskDescr_IsParConstr;
|
||||
}
|
||||
INLINE int IsTaskConstruct() { return !IsParallelConstruct(); }
|
||||
INLINE int IsTaskConstruct() const { return !IsParallelConstruct(); }
|
||||
// methods for other fields
|
||||
INLINE uint16_t &NThreads() { return items.nthreads; }
|
||||
INLINE uint16_t &ThreadLimit() { return items.threadlimit; }
|
||||
INLINE uint16_t &ThreadId() { return items.threadId; }
|
||||
INLINE uint16_t &ThreadsInTeam() { return items.threadsInTeam; }
|
||||
INLINE uint64_t &RuntimeChunkSize() { return items.runtimeChunkSize; }
|
||||
INLINE omptarget_nvptx_TaskDescr *GetPrevTaskDescr() { return prev; }
|
||||
INLINE omptarget_nvptx_TaskDescr *GetPrevTaskDescr() const { return prev; }
|
||||
INLINE void SetPrevTaskDescr(omptarget_nvptx_TaskDescr *taskDescr) {
|
||||
prev = taskDescr;
|
||||
}
|
||||
// init & copy
|
||||
INLINE void InitLevelZeroTaskDescr();
|
||||
INLINE void InitLevelOneTaskDescr(uint16_t tnum,
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr);
|
||||
INLINE void InitLevelOneTaskDescr(omptarget_nvptx_TaskDescr *parentTaskDescr);
|
||||
INLINE void Copy(omptarget_nvptx_TaskDescr *sourceTaskDescr);
|
||||
INLINE void CopyData(omptarget_nvptx_TaskDescr *sourceTaskDescr);
|
||||
INLINE void CopyParent(omptarget_nvptx_TaskDescr *parentTaskDescr);
|
||||
INLINE void CopyForExplicitTask(omptarget_nvptx_TaskDescr *parentTaskDescr);
|
||||
INLINE void CopyToWorkDescr(omptarget_nvptx_TaskDescr *masterTaskDescr,
|
||||
uint16_t tnum);
|
||||
INLINE void CopyToWorkDescr(omptarget_nvptx_TaskDescr *masterTaskDescr);
|
||||
INLINE void CopyFromWorkDescr(omptarget_nvptx_TaskDescr *workTaskDescr);
|
||||
INLINE void CopyConvergentParent(omptarget_nvptx_TaskDescr *parentTaskDescr,
|
||||
uint16_t tid, uint16_t tnum);
|
||||
@@ -195,15 +167,13 @@ public:
|
||||
INLINE void RestoreLoopData() const;
|
||||
|
||||
private:
|
||||
// bits for flags: (7 used, 1 free)
|
||||
// bits for flags: (6 used, 2 free)
|
||||
// 3 bits (SchedMask) for runtime schedule
|
||||
// 1 bit (IsDynamic) for dynamic schedule (false = static)
|
||||
// 1 bit (InPar) if this thread has encountered one or more parallel region
|
||||
// 1 bit (IsParConstr) if ICV for a parallel region (false = explicit task)
|
||||
// 1 bit (InParL2+) if this thread has encountered L2 or higher parallel
|
||||
// region
|
||||
static const uint8_t TaskDescr_SchedMask = (0x1 | 0x2 | 0x4);
|
||||
static const uint8_t TaskDescr_IsDynamic = 0x8;
|
||||
static const uint8_t TaskDescr_InPar = 0x10;
|
||||
static const uint8_t TaskDescr_IsParConstr = 0x20;
|
||||
static const uint8_t TaskDescr_InParL2P = 0x40;
|
||||
@@ -219,10 +189,7 @@ private:
|
||||
struct TaskDescr_items {
|
||||
uint8_t flags; // 6 bit used (see flag above)
|
||||
uint8_t unused;
|
||||
uint16_t nthreads; // thread num for subsequent parallel regions
|
||||
uint16_t threadlimit; // thread limit ICV
|
||||
uint16_t threadId; // thread id
|
||||
uint16_t threadsInTeam; // threads in current team
|
||||
uint64_t runtimeChunkSize; // runtime chunk size
|
||||
} items;
|
||||
omptarget_nvptx_TaskDescr *prev;
|
||||
@@ -242,15 +209,10 @@ class omptarget_nvptx_WorkDescr {
|
||||
|
||||
public:
|
||||
// access to data
|
||||
INLINE omptarget_nvptx_CounterGroup &CounterGroup() { return cg; }
|
||||
INLINE omptarget_nvptx_TaskDescr *WorkTaskDescr() { return &masterTaskICV; }
|
||||
// init
|
||||
INLINE void InitWorkDescr();
|
||||
|
||||
private:
|
||||
omptarget_nvptx_CounterGroup cg; // for barrier (no other needed)
|
||||
omptarget_nvptx_TaskDescr masterTaskICV;
|
||||
bool hasCancel;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -264,7 +226,6 @@ public:
|
||||
INLINE omptarget_nvptx_WorkDescr &WorkDescr() {
|
||||
return workDescrForActiveParallel;
|
||||
}
|
||||
INLINE omp_lock_t *CriticalLock() { return &criticalLock; }
|
||||
INLINE uint64_t *getLastprivateIterBuffer() { return &lastprivateIterBuffer; }
|
||||
|
||||
// init
|
||||
@@ -316,7 +277,6 @@ private:
|
||||
levelZeroTaskDescr; // icv for team master initial thread
|
||||
omptarget_nvptx_WorkDescr
|
||||
workDescrForActiveParallel; // one, ONLY for the active par
|
||||
omp_lock_t criticalLock;
|
||||
uint64_t lastprivateIterBuffer;
|
||||
|
||||
__align__(16)
|
||||
@@ -338,7 +298,7 @@ public:
|
||||
omptarget_nvptx_TaskDescr *taskICV) {
|
||||
topTaskDescr[tid] = taskICV;
|
||||
}
|
||||
INLINE omptarget_nvptx_TaskDescr *GetTopLevelTaskDescr(int tid);
|
||||
INLINE omptarget_nvptx_TaskDescr *GetTopLevelTaskDescr(int tid) const;
|
||||
// parallel
|
||||
INLINE uint16_t &NumThreadsForNextParallel(int tid) {
|
||||
return nextRegion.tnum[tid];
|
||||
@@ -347,9 +307,6 @@ public:
|
||||
INLINE uint16_t &SimdLimitForNextSimd(int tid) {
|
||||
return nextRegion.slim[tid];
|
||||
}
|
||||
// sync
|
||||
INLINE Counter &Priv(int tid) { return priv[tid]; }
|
||||
INLINE void IncrementPriv(int tid, Counter val) { priv[tid] += val; }
|
||||
// schedule (for dispatch)
|
||||
INLINE kmp_sched_t &ScheduleType(int tid) { return schedule[tid]; }
|
||||
INLINE int64_t &Chunk(int tid) { return chunk[tid]; }
|
||||
@@ -360,8 +317,7 @@ public:
|
||||
INLINE omptarget_nvptx_TeamDescr &TeamContext() { return teamContext; }
|
||||
|
||||
INLINE void InitThreadPrivateContext(int tid);
|
||||
INLINE void SetSourceQueue(uint64_t Src) { SourceQueue = Src; }
|
||||
INLINE uint64_t GetSourceQueue() { return SourceQueue; }
|
||||
INLINE uint64_t &Cnt() { return cnt; }
|
||||
|
||||
private:
|
||||
// team context for this team
|
||||
@@ -377,8 +333,6 @@ private:
|
||||
// simd limit
|
||||
uint16_t slim[MAX_THREADS_PER_TEAM];
|
||||
} nextRegion;
|
||||
// sync
|
||||
Counter priv[MAX_THREADS_PER_TEAM];
|
||||
// schedule (for dispatch)
|
||||
kmp_sched_t schedule[MAX_THREADS_PER_TEAM]; // remember schedule type for #for
|
||||
int64_t chunk[MAX_THREADS_PER_TEAM];
|
||||
@@ -386,8 +340,7 @@ private:
|
||||
// state for dispatch with dyn/guided OR static (never use both at a time)
|
||||
int64_t nextLowerBound[MAX_THREADS_PER_TEAM];
|
||||
int64_t stride[MAX_THREADS_PER_TEAM];
|
||||
// Queue to which this object must be returned.
|
||||
uint64_t SourceQueue;
|
||||
uint64_t cnt;
|
||||
};
|
||||
|
||||
/// Device envrionment data
|
||||
@@ -395,6 +348,22 @@ struct omptarget_device_environmentTy {
|
||||
int32_t debug_level;
|
||||
};
|
||||
|
||||
/// Memory manager for statically allocated memory.
|
||||
class omptarget_nvptx_SimpleMemoryManager {
|
||||
private:
|
||||
__align__(128) struct MemDataTy {
|
||||
volatile unsigned keys[OMP_STATE_COUNT];
|
||||
} MemData[MAX_SM];
|
||||
|
||||
INLINE static uint32_t hash(unsigned key) {
|
||||
return key & (OMP_STATE_COUNT - 1);
|
||||
}
|
||||
|
||||
public:
|
||||
INLINE void Release();
|
||||
INLINE const void *Acquire(const void *buf, size_t size);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// global device envrionment
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -407,8 +376,18 @@ extern __device__ omptarget_device_environmentTy omptarget_device_environment;
|
||||
// global data tables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern __device__ omptarget_nvptx_SimpleMemoryManager
|
||||
omptarget_nvptx_simpleMemoryManager;
|
||||
extern __device__ __shared__ uint32_t usedMemIdx;
|
||||
extern __device__ __shared__ uint32_t usedSlotIdx;
|
||||
extern __device__ __shared__ uint8_t
|
||||
parallelLevel[MAX_THREADS_PER_TEAM / WARPSIZE];
|
||||
extern __device__ __shared__ uint16_t threadLimit;
|
||||
extern __device__ __shared__ uint16_t threadsInTeam;
|
||||
extern __device__ __shared__ uint16_t nThreads;
|
||||
extern __device__ __shared__
|
||||
omptarget_nvptx_ThreadPrivateContext *omptarget_nvptx_threadPrivateContext;
|
||||
|
||||
extern __device__ __shared__ uint32_t execution_param;
|
||||
extern __device__ __shared__ void *ReductionScratchpadPtr;
|
||||
|
||||
@@ -427,14 +406,14 @@ extern volatile __device__ __shared__ omptarget_nvptx_WorkFn
|
||||
|
||||
INLINE omptarget_nvptx_TeamDescr &getMyTeamDescriptor();
|
||||
INLINE omptarget_nvptx_WorkDescr &getMyWorkDescriptor();
|
||||
INLINE omptarget_nvptx_TaskDescr *getMyTopTaskDescriptor();
|
||||
INLINE omptarget_nvptx_TaskDescr *
|
||||
getMyTopTaskDescriptor(bool isSPMDExecutionMode);
|
||||
INLINE omptarget_nvptx_TaskDescr *getMyTopTaskDescriptor(int globalThreadId);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// inlined implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "counter_groupi.h"
|
||||
#include "omptarget-nvptxi.h"
|
||||
#include "supporti.h"
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===---- omptarget-nvptxi.h - NVPTX OpenMP GPU initialization --- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -16,7 +15,7 @@
|
||||
// Task Descriptor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE omp_sched_t omptarget_nvptx_TaskDescr::GetRuntimeSched() {
|
||||
INLINE omp_sched_t omptarget_nvptx_TaskDescr::GetRuntimeSched() const {
|
||||
// sched starts from 1..4; encode it as 0..3; so add 1 here
|
||||
uint8_t rc = (items.flags & TaskDescr_SchedMask) + 1;
|
||||
return (omp_sched_t)rc;
|
||||
@@ -31,7 +30,8 @@ INLINE void omptarget_nvptx_TaskDescr::SetRuntimeSched(omp_sched_t sched) {
|
||||
items.flags |= val;
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_TaskDescr::InitLevelZeroTaskDescr() {
|
||||
INLINE void
|
||||
omptarget_nvptx_TaskDescr::InitLevelZeroTaskDescr() {
|
||||
// slow method
|
||||
// flag:
|
||||
// default sched is static,
|
||||
@@ -39,17 +39,14 @@ INLINE void omptarget_nvptx_TaskDescr::InitLevelZeroTaskDescr() {
|
||||
// not in parallel
|
||||
|
||||
items.flags = 0;
|
||||
items.nthreads = GetNumberOfProcsInTeam();
|
||||
; // threads: whatever was alloc by kernel
|
||||
items.threadId = 0; // is master
|
||||
items.threadsInTeam = 1; // sequential
|
||||
items.runtimeChunkSize = 1; // prefered chunking statik with chunk 1
|
||||
}
|
||||
|
||||
// This is called when all threads are started together in SPMD mode.
|
||||
// OMP directives include target parallel, target distribute parallel for, etc.
|
||||
INLINE void omptarget_nvptx_TaskDescr::InitLevelOneTaskDescr(
|
||||
uint16_t tnum, omptarget_nvptx_TaskDescr *parentTaskDescr) {
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr) {
|
||||
// slow method
|
||||
// flag:
|
||||
// default sched is static,
|
||||
@@ -58,10 +55,8 @@ INLINE void omptarget_nvptx_TaskDescr::InitLevelOneTaskDescr(
|
||||
|
||||
items.flags =
|
||||
TaskDescr_InPar | TaskDescr_IsParConstr; // set flag to parallel
|
||||
items.nthreads = 0; // # threads for subsequent parallel region
|
||||
items.threadId =
|
||||
GetThreadIdInBlock(); // get ids from cuda (only called for 1st level)
|
||||
items.threadsInTeam = tnum;
|
||||
items.runtimeChunkSize = 1; // prefered chunking statik with chunk 1
|
||||
prev = parentTaskDescr;
|
||||
}
|
||||
@@ -91,12 +86,11 @@ INLINE void omptarget_nvptx_TaskDescr::CopyForExplicitTask(
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_TaskDescr::CopyToWorkDescr(
|
||||
omptarget_nvptx_TaskDescr *masterTaskDescr, uint16_t tnum) {
|
||||
omptarget_nvptx_TaskDescr *masterTaskDescr) {
|
||||
CopyParent(masterTaskDescr);
|
||||
// overrwrite specific items;
|
||||
items.flags |=
|
||||
TaskDescr_InPar | TaskDescr_IsParConstr; // set flag to parallel
|
||||
items.threadsInTeam = tnum; // set number of threads
|
||||
}
|
||||
|
||||
INLINE void omptarget_nvptx_TaskDescr::CopyFromWorkDescr(
|
||||
@@ -121,7 +115,6 @@ INLINE void omptarget_nvptx_TaskDescr::CopyConvergentParent(
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr, uint16_t tid, uint16_t tnum) {
|
||||
CopyParent(parentTaskDescr);
|
||||
items.flags |= TaskDescr_InParL2P; // In L2+ parallelism
|
||||
items.threadsInTeam = tnum; // set number of threads
|
||||
items.threadId = tid;
|
||||
}
|
||||
|
||||
@@ -154,7 +147,7 @@ INLINE void omptarget_nvptx_TaskDescr::RestoreLoopData() const {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE omptarget_nvptx_TaskDescr *
|
||||
omptarget_nvptx_ThreadPrivateContext::GetTopLevelTaskDescr(int tid) {
|
||||
omptarget_nvptx_ThreadPrivateContext::GetTopLevelTaskDescr(int tid) const {
|
||||
ASSERT0(
|
||||
LT_FUSSY, tid < MAX_THREADS_PER_TEAM,
|
||||
"Getting top level, tid is larger than allocated data structure size");
|
||||
@@ -168,31 +161,17 @@ omptarget_nvptx_ThreadPrivateContext::InitThreadPrivateContext(int tid) {
|
||||
topTaskDescr[tid] = NULL;
|
||||
// no num threads value has been pushed
|
||||
nextRegion.tnum[tid] = 0;
|
||||
// priv counter init to zero
|
||||
priv[tid] = 0;
|
||||
// the following don't need to be init here; they are init when using dyn
|
||||
// sched
|
||||
// current_Event, events_Number, chunk, num_Iterations, schedule
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Work Descriptor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE void omptarget_nvptx_WorkDescr::InitWorkDescr() {
|
||||
cg.Clear(); // start and stop to zero too
|
||||
// threadsInParallelTeam does not need to be init (done in start parallel)
|
||||
hasCancel = FALSE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Team Descriptor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE void omptarget_nvptx_TeamDescr::InitTeamDescr() {
|
||||
levelZeroTaskDescr.InitLevelZeroTaskDescr();
|
||||
workDescrForActiveParallel.InitWorkDescr();
|
||||
// omp_init_lock(criticalLock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -213,6 +192,35 @@ INLINE omptarget_nvptx_TaskDescr *getMyTopTaskDescriptor(int threadId) {
|
||||
return omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
}
|
||||
|
||||
INLINE omptarget_nvptx_TaskDescr *getMyTopTaskDescriptor() {
|
||||
return getMyTopTaskDescriptor(GetLogicalThreadIdInBlock());
|
||||
INLINE omptarget_nvptx_TaskDescr *
|
||||
getMyTopTaskDescriptor(bool isSPMDExecutionMode) {
|
||||
return getMyTopTaskDescriptor(GetLogicalThreadIdInBlock(isSPMDExecutionMode));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory management runtime functions.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE void omptarget_nvptx_SimpleMemoryManager::Release() {
|
||||
ASSERT0(LT_FUSSY, usedSlotIdx < MAX_SM,
|
||||
"SlotIdx is too big or uninitialized.");
|
||||
ASSERT0(LT_FUSSY, usedMemIdx < OMP_STATE_COUNT,
|
||||
"MemIdx is too big or uninitialized.");
|
||||
MemDataTy &MD = MemData[usedSlotIdx];
|
||||
atomicExch((unsigned *)&MD.keys[usedMemIdx], 0);
|
||||
}
|
||||
|
||||
INLINE const void *omptarget_nvptx_SimpleMemoryManager::Acquire(const void *buf,
|
||||
size_t size) {
|
||||
ASSERT0(LT_FUSSY, usedSlotIdx < MAX_SM,
|
||||
"SlotIdx is too big or uninitialized.");
|
||||
const unsigned sm = usedSlotIdx;
|
||||
MemDataTy &MD = MemData[sm];
|
||||
unsigned i = hash(GetBlockIdInKernel());
|
||||
while (atomicCAS((unsigned *)&MD.keys[i], 0, 1) != 0) {
|
||||
i = hash(i + 1);
|
||||
}
|
||||
usedSlotIdx = sm;
|
||||
usedMemIdx = i;
|
||||
return static_cast<const char *>(buf) + (sm * OMP_STATE_COUNT + i) * size;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------ option.h - NVPTX OpenMP GPU options ------------ CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -13,6 +12,8 @@
|
||||
#ifndef _OPTION_H_
|
||||
#define _OPTION_H_
|
||||
|
||||
#include "interface.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Kernel options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -34,7 +35,10 @@
|
||||
|
||||
// Maximum number of omp state objects per SM allocated statically in global
|
||||
// memory.
|
||||
#if __CUDA_ARCH__ >= 600
|
||||
#if __CUDA_ARCH__ >= 700
|
||||
#define OMP_STATE_COUNT 32
|
||||
#define MAX_SM 84
|
||||
#elif __CUDA_ARCH__ >= 600
|
||||
#define OMP_STATE_COUNT 32
|
||||
#define MAX_SM 56
|
||||
#else
|
||||
@@ -42,23 +46,17 @@
|
||||
#define MAX_SM 16
|
||||
#endif
|
||||
|
||||
#define OMP_ACTIVE_PARALLEL_LEVEL 128
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// algo options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// data options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// decide if counters are 32 or 64 bit
|
||||
#define Counter unsigned long long
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// misc options (by def everythig here is device)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define EXTERN extern "C" __device__
|
||||
#define INLINE __inline__ __device__
|
||||
#define INLINE __forceinline__ __device__
|
||||
#define NOINLINE __noinline__ __device__
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===---- parallel.cu - NVPTX OpenMP parallel implementation ----- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -34,6 +33,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
#include "target_impl.h"
|
||||
|
||||
typedef struct ConvergentSimdJob {
|
||||
omptarget_nvptx_TaskDescr taskDescr;
|
||||
@@ -44,20 +44,20 @@ typedef struct ConvergentSimdJob {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for convergent simd (team of threads in a warp only)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
EXTERN bool __kmpc_kernel_convergent_simd(void *buffer, uint32_t Mask,
|
||||
EXTERN bool __kmpc_kernel_convergent_simd(void *buffer,
|
||||
__kmpc_impl_lanemask_t Mask,
|
||||
bool *IsFinal, int32_t *LaneSource,
|
||||
int32_t *LaneId, int32_t *NumLanes) {
|
||||
PRINT0(LD_IO, "call to __kmpc_kernel_convergent_simd\n");
|
||||
uint32_t ConvergentMask = Mask;
|
||||
int32_t ConvergentSize = __popc(ConvergentMask);
|
||||
uint32_t WorkRemaining = ConvergentMask >> (*LaneSource + 1);
|
||||
*LaneSource += __ffs(WorkRemaining);
|
||||
*IsFinal = __popc(WorkRemaining) == 1;
|
||||
uint32_t lanemask_lt;
|
||||
asm("mov.u32 %0, %%lanemask_lt;" : "=r"(lanemask_lt));
|
||||
*LaneId = __popc(ConvergentMask & lanemask_lt);
|
||||
__kmpc_impl_lanemask_t ConvergentMask = Mask;
|
||||
int32_t ConvergentSize = __kmpc_impl_popc(ConvergentMask);
|
||||
__kmpc_impl_lanemask_t WorkRemaining = ConvergentMask >> (*LaneSource + 1);
|
||||
*LaneSource += __kmpc_impl_ffs(WorkRemaining);
|
||||
*IsFinal = __kmpc_impl_popc(WorkRemaining) == 1;
|
||||
__kmpc_impl_lanemask_t lanemask_lt = __kmpc_impl_lanemask_lt();
|
||||
*LaneId = __kmpc_impl_popc(ConvergentMask & lanemask_lt);
|
||||
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(isSPMDMode());
|
||||
int sourceThreadId = (threadId & ~(WARPSIZE - 1)) + *LaneSource;
|
||||
|
||||
ConvergentSimdJob *job = (ConvergentSimdJob *)buffer;
|
||||
@@ -65,7 +65,7 @@ EXTERN bool __kmpc_kernel_convergent_simd(void *buffer, uint32_t Mask,
|
||||
omptarget_nvptx_threadPrivateContext->SimdLimitForNextSimd(threadId);
|
||||
job->slimForNextSimd = SimdLimit;
|
||||
|
||||
int32_t SimdLimitSource = __SHFL_SYNC(Mask, SimdLimit, *LaneSource);
|
||||
int32_t SimdLimitSource = __kmpc_impl_shfl_sync(Mask, SimdLimit, *LaneSource);
|
||||
// reset simdlimit to avoid propagating to successive #simd
|
||||
if (SimdLimitSource > 0 && threadId == sourceThreadId)
|
||||
omptarget_nvptx_threadPrivateContext->SimdLimitForNextSimd(threadId) = 0;
|
||||
@@ -76,7 +76,7 @@ EXTERN bool __kmpc_kernel_convergent_simd(void *buffer, uint32_t Mask,
|
||||
else
|
||||
*NumLanes = ConvergentSize;
|
||||
ASSERT(LT_FUSSY, *NumLanes > 0, "bad thread request of %d threads",
|
||||
*NumLanes);
|
||||
(int)*NumLanes);
|
||||
|
||||
// Set to true for lanes participating in the simd region.
|
||||
bool isActive = false;
|
||||
@@ -101,7 +101,7 @@ EXTERN bool __kmpc_kernel_convergent_simd(void *buffer, uint32_t Mask,
|
||||
EXTERN void __kmpc_kernel_end_convergent_simd(void *buffer) {
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_kernel_end_convergent_parallel\n");
|
||||
// pop stack
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(isSPMDMode());
|
||||
ConvergentSimdJob *job = (ConvergentSimdJob *)buffer;
|
||||
omptarget_nvptx_threadPrivateContext->SimdLimitForNextSimd(threadId) =
|
||||
job->slimForNextSimd;
|
||||
@@ -118,20 +118,20 @@ typedef struct ConvergentParallelJob {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for convergent parallelism (team of threads in a warp only)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer, uint32_t Mask,
|
||||
EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer,
|
||||
__kmpc_impl_lanemask_t Mask,
|
||||
bool *IsFinal,
|
||||
int32_t *LaneSource) {
|
||||
PRINT0(LD_IO, "call to __kmpc_kernel_convergent_parallel\n");
|
||||
uint32_t ConvergentMask = Mask;
|
||||
int32_t ConvergentSize = __popc(ConvergentMask);
|
||||
uint32_t WorkRemaining = ConvergentMask >> (*LaneSource + 1);
|
||||
*LaneSource += __ffs(WorkRemaining);
|
||||
*IsFinal = __popc(WorkRemaining) == 1;
|
||||
uint32_t lanemask_lt;
|
||||
asm("mov.u32 %0, %%lanemask_lt;" : "=r"(lanemask_lt));
|
||||
uint32_t OmpId = __popc(ConvergentMask & lanemask_lt);
|
||||
__kmpc_impl_lanemask_t ConvergentMask = Mask;
|
||||
int32_t ConvergentSize = __kmpc_impl_popc(ConvergentMask);
|
||||
__kmpc_impl_lanemask_t WorkRemaining = ConvergentMask >> (*LaneSource + 1);
|
||||
*LaneSource += __kmpc_impl_ffs(WorkRemaining);
|
||||
*IsFinal = __kmpc_impl_popc(WorkRemaining) == 1;
|
||||
__kmpc_impl_lanemask_t lanemask_lt = __kmpc_impl_lanemask_lt();
|
||||
uint32_t OmpId = __kmpc_impl_popc(ConvergentMask & lanemask_lt);
|
||||
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(isSPMDMode());
|
||||
int sourceThreadId = (threadId & ~(WARPSIZE - 1)) + *LaneSource;
|
||||
|
||||
ConvergentParallelJob *job = (ConvergentParallelJob *)buffer;
|
||||
@@ -139,7 +139,8 @@ EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer, uint32_t Mask,
|
||||
omptarget_nvptx_threadPrivateContext->NumThreadsForNextParallel(threadId);
|
||||
job->tnumForNextPar = NumThreadsClause;
|
||||
|
||||
int32_t NumThreadsSource = __SHFL_SYNC(Mask, NumThreadsClause, *LaneSource);
|
||||
int32_t NumThreadsSource =
|
||||
__kmpc_impl_shfl_sync(Mask, NumThreadsClause, *LaneSource);
|
||||
// reset numthreads to avoid propagating to successive #parallel
|
||||
if (NumThreadsSource > 0 && threadId == sourceThreadId)
|
||||
omptarget_nvptx_threadPrivateContext->NumThreadsForNextParallel(threadId) =
|
||||
@@ -152,7 +153,7 @@ EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer, uint32_t Mask,
|
||||
else
|
||||
NumThreads = ConvergentSize;
|
||||
ASSERT(LT_FUSSY, NumThreads > 0, "bad thread request of %d threads",
|
||||
NumThreads);
|
||||
(int)NumThreads);
|
||||
|
||||
// Set to true for workers participating in the parallel region.
|
||||
bool isActive = false;
|
||||
@@ -181,7 +182,7 @@ EXTERN bool __kmpc_kernel_convergent_parallel(void *buffer, uint32_t Mask,
|
||||
EXTERN void __kmpc_kernel_end_convergent_parallel(void *buffer) {
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_kernel_end_convergent_parallel\n");
|
||||
// pop stack
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(isSPMDMode());
|
||||
ConvergentParallelJob *job = (ConvergentParallelJob *)buffer;
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(
|
||||
threadId, job->convHeadTaskDescr);
|
||||
@@ -193,38 +194,50 @@ EXTERN void __kmpc_kernel_end_convergent_parallel(void *buffer) {
|
||||
// support for parallel that goes parallel (1 static level only)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// return number of cuda threads that participate to parallel
|
||||
// calculation has to consider simd implementation in nvptx
|
||||
// i.e. (num omp threads * num lanes)
|
||||
//
|
||||
// cudathreads =
|
||||
// if(num_threads != 0) {
|
||||
// if(thread_limit > 0) {
|
||||
// min (num_threads*numLanes ; thread_limit*numLanes);
|
||||
// } else {
|
||||
// min (num_threads*numLanes; blockDim.x)
|
||||
// }
|
||||
// } else {
|
||||
// if (thread_limit != 0) {
|
||||
// min (thread_limit*numLanes; blockDim.x)
|
||||
// } else { // no thread_limit, no num_threads, use all cuda threads
|
||||
// blockDim.x;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
INLINE static uint16_t determineNumberOfThreads(uint16_t NumThreadsClause,
|
||||
uint16_t NThreadsICV,
|
||||
uint16_t ThreadLimit) {
|
||||
uint16_t ThreadsRequested = NThreadsICV;
|
||||
if (NumThreadsClause != 0) {
|
||||
ThreadsRequested = NumThreadsClause;
|
||||
}
|
||||
|
||||
uint16_t ThreadsAvailable = GetNumberOfWorkersInTeam();
|
||||
if (ThreadLimit != 0 && ThreadLimit < ThreadsAvailable) {
|
||||
ThreadsAvailable = ThreadLimit;
|
||||
}
|
||||
|
||||
uint16_t NumThreads = ThreadsAvailable;
|
||||
if (ThreadsRequested != 0 && ThreadsRequested < NumThreads) {
|
||||
NumThreads = ThreadsRequested;
|
||||
}
|
||||
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
|
||||
// On Volta and newer architectures we require that all lanes in
|
||||
// a warp participate in the parallel region. Round down to a
|
||||
// multiple of WARPSIZE since it is legal to do so in OpenMP.
|
||||
if (NumThreads < WARPSIZE) {
|
||||
NumThreads = 1;
|
||||
} else {
|
||||
NumThreads = (NumThreads & ~((uint16_t)WARPSIZE - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
return NumThreads;
|
||||
}
|
||||
|
||||
// This routine is always called by the team master..
|
||||
EXTERN void __kmpc_kernel_prepare_parallel(void *WorkFn,
|
||||
int16_t IsOMPRuntimeInitialized) {
|
||||
PRINT0(LD_IO, "call to __kmpc_kernel_prepare_parallel\n");
|
||||
omptarget_nvptx_workFn = WorkFn;
|
||||
ASSERT0(LT_FUSSY, IsOMPRuntimeInitialized, "Expected initialized runtime.");
|
||||
|
||||
if (!IsOMPRuntimeInitialized)
|
||||
return;
|
||||
omptarget_nvptx_workFn = WorkFn;
|
||||
|
||||
// This routine is only called by the team master. The team master is
|
||||
// the first thread of the last warp. It always has the logical thread
|
||||
// id of 0 (since it is a shadow for the first worker thread).
|
||||
int threadId = 0;
|
||||
const int threadId = 0;
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
ASSERT0(LT_FUSSY, currTaskDescr, "expected a top task descr");
|
||||
@@ -235,80 +248,26 @@ EXTERN void __kmpc_kernel_prepare_parallel(void *WorkFn,
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t CudaThreadsForParallel = 0;
|
||||
uint16_t NumThreadsClause =
|
||||
uint16_t &NumThreadsClause =
|
||||
omptarget_nvptx_threadPrivateContext->NumThreadsForNextParallel(threadId);
|
||||
|
||||
// we cannot have more than block size
|
||||
uint16_t CudaThreadsAvail = GetNumberOfWorkersInTeam();
|
||||
uint16_t NumThreads =
|
||||
determineNumberOfThreads(NumThreadsClause, nThreads, threadLimit);
|
||||
|
||||
// currTaskDescr->ThreadLimit(): If non-zero, this is the limit as
|
||||
// specified by the thread_limit clause on the target directive.
|
||||
// GetNumberOfWorkersInTeam(): This is the number of workers available
|
||||
// in this kernel instance.
|
||||
//
|
||||
// E.g: If thread_limit is 33, the kernel is launched with 33+32=65
|
||||
// threads. The last warp is the master warp so in this case
|
||||
// GetNumberOfWorkersInTeam() returns 64.
|
||||
|
||||
// this is different from ThreadAvail of OpenMP because we may be
|
||||
// using some of the CUDA threads as SIMD lanes
|
||||
int NumLanes = 1;
|
||||
if (NumThreadsClause != 0) {
|
||||
// reset request to avoid propagating to successive #parallel
|
||||
omptarget_nvptx_threadPrivateContext->NumThreadsForNextParallel(threadId) =
|
||||
0;
|
||||
|
||||
// assume that thread_limit*numlanes is already <= CudaThreadsAvail
|
||||
// because that is already checked on the host side (CUDA offloading rtl)
|
||||
if (currTaskDescr->ThreadLimit() != 0)
|
||||
CudaThreadsForParallel =
|
||||
NumThreadsClause * NumLanes < currTaskDescr->ThreadLimit() * NumLanes
|
||||
? NumThreadsClause * NumLanes
|
||||
: currTaskDescr->ThreadLimit() * NumLanes;
|
||||
else {
|
||||
CudaThreadsForParallel = (NumThreadsClause * NumLanes > CudaThreadsAvail)
|
||||
? CudaThreadsAvail
|
||||
: NumThreadsClause * NumLanes;
|
||||
}
|
||||
} else {
|
||||
if (currTaskDescr->ThreadLimit() != 0) {
|
||||
CudaThreadsForParallel =
|
||||
(currTaskDescr->ThreadLimit() * NumLanes > CudaThreadsAvail)
|
||||
? CudaThreadsAvail
|
||||
: currTaskDescr->ThreadLimit() * NumLanes;
|
||||
} else
|
||||
CudaThreadsForParallel = CudaThreadsAvail;
|
||||
// Reset request to avoid propagating to successive #parallel
|
||||
NumThreadsClause = 0;
|
||||
}
|
||||
|
||||
#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 700
|
||||
// On Volta and newer architectures we require that all lanes in
|
||||
// a warp participate in the parallel region. Round down to a
|
||||
// multiple of WARPSIZE since it is legal to do so in OpenMP.
|
||||
// CudaThreadsAvail is the number of workers available in this
|
||||
// kernel instance and is greater than or equal to
|
||||
// currTaskDescr->ThreadLimit().
|
||||
if (CudaThreadsForParallel < CudaThreadsAvail) {
|
||||
CudaThreadsForParallel =
|
||||
(CudaThreadsForParallel < WARPSIZE)
|
||||
? 1
|
||||
: CudaThreadsForParallel & ~((uint16_t)WARPSIZE - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(LT_FUSSY, CudaThreadsForParallel > 0,
|
||||
"bad thread request of %d threads", CudaThreadsForParallel);
|
||||
ASSERT(LT_FUSSY, NumThreads > 0, "bad thread request of %d threads",
|
||||
(int)NumThreads);
|
||||
ASSERT0(LT_FUSSY, GetThreadIdInBlock() == GetMasterThreadID(),
|
||||
"only team master can create parallel");
|
||||
|
||||
// set number of threads on work descriptor
|
||||
// this is different from the number of cuda threads required for the parallel
|
||||
// region
|
||||
// Set number of threads on work descriptor.
|
||||
omptarget_nvptx_WorkDescr &workDescr = getMyWorkDescriptor();
|
||||
workDescr.WorkTaskDescr()->CopyToWorkDescr(currTaskDescr,
|
||||
CudaThreadsForParallel / NumLanes);
|
||||
// init counters (copy start to init)
|
||||
workDescr.CounterGroup().Reset();
|
||||
workDescr.WorkTaskDescr()->CopyToWorkDescr(currTaskDescr);
|
||||
threadsInTeam = NumThreads;
|
||||
}
|
||||
|
||||
// All workers call this function. Deactivate those not needed.
|
||||
@@ -320,15 +279,16 @@ EXTERN bool __kmpc_kernel_parallel(void **WorkFn,
|
||||
int16_t IsOMPRuntimeInitialized) {
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_kernel_parallel\n");
|
||||
|
||||
ASSERT0(LT_FUSSY, IsOMPRuntimeInitialized, "Expected initialized runtime.");
|
||||
|
||||
// Work function and arguments for L1 parallel region.
|
||||
*WorkFn = omptarget_nvptx_workFn;
|
||||
|
||||
if (!IsOMPRuntimeInitialized)
|
||||
return true;
|
||||
|
||||
// If this is the termination signal from the master, quit early.
|
||||
if (!*WorkFn)
|
||||
if (!*WorkFn) {
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_kernel_parallel finished\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only the worker threads call this routine and the master warp
|
||||
// never arrives here. Therefore, use the nvptx thread id.
|
||||
@@ -337,7 +297,7 @@ EXTERN bool __kmpc_kernel_parallel(void **WorkFn,
|
||||
// Set to true for workers participating in the parallel region.
|
||||
bool isActive = false;
|
||||
// Initialize state for active threads.
|
||||
if (threadId < workDescr.WorkTaskDescr()->ThreadsInTeam()) {
|
||||
if (threadId < threadsInTeam) {
|
||||
// init work descriptor from workdesccr
|
||||
omptarget_nvptx_TaskDescr *newTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->Level1TaskDescr(threadId);
|
||||
@@ -347,14 +307,22 @@ EXTERN bool __kmpc_kernel_parallel(void **WorkFn,
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(threadId,
|
||||
newTaskDescr);
|
||||
// init private from int value
|
||||
workDescr.CounterGroup().Init(
|
||||
omptarget_nvptx_threadPrivateContext->Priv(threadId));
|
||||
PRINT(LD_PAR,
|
||||
"thread will execute parallel region with id %d in a team of "
|
||||
"%d threads\n",
|
||||
newTaskDescr->ThreadId(), newTaskDescr->NThreads());
|
||||
(int)newTaskDescr->ThreadId(), (int)nThreads);
|
||||
|
||||
isActive = true;
|
||||
// Reconverge the threads at the end of the parallel region to correctly
|
||||
// handle parallel levels.
|
||||
// In Cuda9+ in non-SPMD mode we have either 1 worker thread or the whole
|
||||
// warp. If only 1 thread is active, not need to reconverge the threads.
|
||||
// If we have the whole warp, reconverge all the threads in the warp before
|
||||
// actually trying to change the parallel level. Otherwise, parallel level
|
||||
// can be changed incorrectly because of threads divergence.
|
||||
bool IsActiveParallelRegion = threadsInTeam != 1;
|
||||
IncParallelLevel(IsActiveParallelRegion,
|
||||
IsActiveParallelRegion ? __kmpc_impl_all_lanes : 1u);
|
||||
}
|
||||
|
||||
return isActive;
|
||||
@@ -363,23 +331,44 @@ EXTERN bool __kmpc_kernel_parallel(void **WorkFn,
|
||||
EXTERN void __kmpc_kernel_end_parallel() {
|
||||
// pop stack
|
||||
PRINT0(LD_IO | LD_PAR, "call to __kmpc_kernel_end_parallel\n");
|
||||
ASSERT0(LT_FUSSY, isRuntimeInitialized(), "Expected initialized runtime.");
|
||||
|
||||
// Only the worker threads call this routine and the master warp
|
||||
// never arrives here. Therefore, use the nvptx thread id.
|
||||
int threadId = GetThreadIdInBlock();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor(threadId);
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(
|
||||
threadId, currTaskDescr->GetPrevTaskDescr());
|
||||
|
||||
// Reconverge the threads at the end of the parallel region to correctly
|
||||
// handle parallel levels.
|
||||
// In Cuda9+ in non-SPMD mode we have either 1 worker thread or the whole
|
||||
// warp. If only 1 thread is active, not need to reconverge the threads.
|
||||
// If we have the whole warp, reconverge all the threads in the warp before
|
||||
// actually trying to change the parallel level. Otherwise, parallel level can
|
||||
// be changed incorrectly because of threads divergence.
|
||||
bool IsActiveParallelRegion = threadsInTeam != 1;
|
||||
DecParallelLevel(IsActiveParallelRegion,
|
||||
IsActiveParallelRegion ? __kmpc_impl_all_lanes : 1u);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for parallel that goes sequential
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_serialized_parallel(kmp_Indent *loc, uint32_t global_tid) {
|
||||
EXTERN void __kmpc_serialized_parallel(kmp_Ident *loc, uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_serialized_parallel\n");
|
||||
|
||||
IncParallelLevel(/*ActiveParallel=*/false, __kmpc_impl_activemask());
|
||||
|
||||
if (checkRuntimeUninitialized(loc)) {
|
||||
ASSERT0(LT_FUSSY, checkSPMDMode(loc),
|
||||
"Expected SPMD mode with uninitialized runtime.");
|
||||
return;
|
||||
}
|
||||
|
||||
// assume this is only called for nested parallel
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
|
||||
// unlike actual parallel, threads in the same team do not share
|
||||
// the workTaskDescr in this case and num threads is fixed to 1
|
||||
@@ -392,26 +381,33 @@ EXTERN void __kmpc_serialized_parallel(kmp_Indent *loc, uint32_t global_tid) {
|
||||
// it
|
||||
omptarget_nvptx_TaskDescr *newTaskDescr =
|
||||
(omptarget_nvptx_TaskDescr *)SafeMalloc(sizeof(omptarget_nvptx_TaskDescr),
|
||||
(char *)"new seq parallel task");
|
||||
"new seq parallel task");
|
||||
newTaskDescr->CopyParent(currTaskDescr);
|
||||
|
||||
// tweak values for serialized parallel case:
|
||||
// - each thread becomes ID 0 in its serialized parallel, and
|
||||
// - there is only one thread per team
|
||||
newTaskDescr->ThreadId() = 0;
|
||||
newTaskDescr->ThreadsInTeam() = 1;
|
||||
|
||||
// set new task descriptor as top
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(threadId,
|
||||
newTaskDescr);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_end_serialized_parallel(kmp_Indent *loc,
|
||||
EXTERN void __kmpc_end_serialized_parallel(kmp_Ident *loc,
|
||||
uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_end_serialized_parallel\n");
|
||||
|
||||
DecParallelLevel(/*ActiveParallel=*/false, __kmpc_impl_activemask());
|
||||
|
||||
if (checkRuntimeUninitialized(loc)) {
|
||||
ASSERT0(LT_FUSSY, checkSPMDMode(loc),
|
||||
"Expected SPMD mode with uninitialized runtime.");
|
||||
return;
|
||||
}
|
||||
|
||||
// pop stack
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
int threadId = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor(threadId);
|
||||
// set new top
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(
|
||||
@@ -422,58 +418,53 @@ EXTERN void __kmpc_end_serialized_parallel(kmp_Indent *loc,
|
||||
currTaskDescr->RestoreLoopData();
|
||||
}
|
||||
|
||||
EXTERN uint16_t __kmpc_parallel_level(kmp_Indent *loc, uint32_t global_tid) {
|
||||
EXTERN uint16_t __kmpc_parallel_level(kmp_Ident *loc, uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_parallel_level\n");
|
||||
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
if (currTaskDescr->InL2OrHigherParallelRegion())
|
||||
return 2;
|
||||
else if (currTaskDescr->InParallelRegion())
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return parallelLevel[GetWarpId()] & (OMP_ACTIVE_PARALLEL_LEVEL - 1);
|
||||
}
|
||||
|
||||
// This kmpc call returns the thread id across all teams. It's value is
|
||||
// cached by the compiler and used when calling the runtime. On nvptx
|
||||
// it's cheap to recalculate this value so we never use the result
|
||||
// of this call.
|
||||
EXTERN int32_t __kmpc_global_thread_num(kmp_Indent *loc) {
|
||||
return GetLogicalThreadIdInBlock();
|
||||
EXTERN int32_t __kmpc_global_thread_num(kmp_Ident *loc) {
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
return GetOmpThreadId(tid, checkSPMDMode(loc));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// push params
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_push_num_threads(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_push_num_threads(kmp_Ident *loc, int32_t tid,
|
||||
int32_t num_threads) {
|
||||
PRINT(LD_IO, "call kmpc_push_num_threads %d\n", num_threads);
|
||||
tid = GetLogicalThreadIdInBlock();
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc), "Runtime must be initialized.");
|
||||
tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_threadPrivateContext->NumThreadsForNextParallel(tid) =
|
||||
num_threads;
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_push_simd_limit(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_push_simd_limit(kmp_Ident *loc, int32_t tid,
|
||||
int32_t simd_limit) {
|
||||
PRINT(LD_IO, "call kmpc_push_simd_limit %d\n", simd_limit);
|
||||
tid = GetLogicalThreadIdInBlock();
|
||||
PRINT(LD_IO, "call kmpc_push_simd_limit %d\n", (int)simd_limit);
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc), "Runtime must be initialized.");
|
||||
tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_threadPrivateContext->SimdLimitForNextSimd(tid) = simd_limit;
|
||||
}
|
||||
|
||||
// Do nothing. The host guarantees we started the requested number of
|
||||
// teams and we only need inspection of gridDim.
|
||||
|
||||
EXTERN void __kmpc_push_num_teams(kmp_Indent *loc, int32_t tid,
|
||||
EXTERN void __kmpc_push_num_teams(kmp_Ident *loc, int32_t tid,
|
||||
int32_t num_teams, int32_t thread_limit) {
|
||||
PRINT(LD_IO, "call kmpc_push_num_teams %d\n", num_teams);
|
||||
PRINT(LD_IO, "call kmpc_push_num_teams %d\n", (int)num_teams);
|
||||
ASSERT0(LT_FUSSY, FALSE,
|
||||
"should never have anything with new teams on device");
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_push_proc_bind(kmp_Indent *loc, uint32_t tid,
|
||||
EXTERN void __kmpc_push_proc_bind(kmp_Ident *loc, uint32_t tid,
|
||||
int proc_bind) {
|
||||
PRINT(LD_IO, "call kmpc_push_proc_bind %d\n", proc_bind);
|
||||
PRINT(LD_IO, "call kmpc_push_proc_bind %d\n", (int)proc_bind);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//===---- reduction.cu - NVPTX OpenMP reduction implementation ---- CUDA
|
||||
//-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -16,53 +15,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
|
||||
// may eventually remove this
|
||||
EXTERN
|
||||
int32_t __gpu_block_reduce() {
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int nt = GetNumberOfOmpThreads(tid, isSPMDMode(), isRuntimeUninitialized());
|
||||
if (nt != blockDim.x)
|
||||
return 0;
|
||||
unsigned tnum = __ACTIVEMASK();
|
||||
if (tnum != (~0x0)) // assume swapSize is 32
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_reduce_gpu(kmp_Indent *loc, int32_t global_tid, int32_t num_vars,
|
||||
size_t reduce_size, void *reduce_data,
|
||||
void *reduce_array_size, kmp_ReductFctPtr *reductFct,
|
||||
kmp_CriticalName *lck) {
|
||||
int threadId = GetLogicalThreadIdInBlock();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr = getMyTopTaskDescriptor(threadId);
|
||||
int numthread;
|
||||
if (currTaskDescr->IsParallelConstruct()) {
|
||||
numthread =
|
||||
GetNumberOfOmpThreads(threadId, isSPMDMode(), isRuntimeUninitialized());
|
||||
} else {
|
||||
numthread = GetNumberOfOmpTeams();
|
||||
}
|
||||
|
||||
if (numthread == 1)
|
||||
return 1;
|
||||
if (!__gpu_block_reduce())
|
||||
return 2;
|
||||
if (threadIdx.x == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_reduce_combined(kmp_Indent *loc) {
|
||||
return threadIdx.x == 0 ? 2 : 0;
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_reduce_simd(kmp_Indent *loc) {
|
||||
return (threadIdx.x % 32 == 0) ? 1 : 0;
|
||||
}
|
||||
#include "target_impl.h"
|
||||
|
||||
EXTERN
|
||||
void __kmpc_nvptx_end_reduce(int32_t global_tid) {}
|
||||
@@ -71,19 +24,18 @@ EXTERN
|
||||
void __kmpc_nvptx_end_reduce_nowait(int32_t global_tid) {}
|
||||
|
||||
EXTERN int32_t __kmpc_shuffle_int32(int32_t val, int16_t delta, int16_t size) {
|
||||
return __SHFL_DOWN_SYNC(0xFFFFFFFF, val, delta, size);
|
||||
return __kmpc_impl_shfl_down_sync(__kmpc_impl_all_lanes, val, delta, size);
|
||||
}
|
||||
|
||||
EXTERN int64_t __kmpc_shuffle_int64(int64_t val, int16_t delta, int16_t size) {
|
||||
int lo, hi;
|
||||
asm volatile("mov.b64 {%0,%1}, %2;" : "=r"(lo), "=r"(hi) : "l"(val));
|
||||
hi = __SHFL_DOWN_SYNC(0xFFFFFFFF, hi, delta, size);
|
||||
lo = __SHFL_DOWN_SYNC(0xFFFFFFFF, lo, delta, size);
|
||||
asm volatile("mov.b64 %0, {%1,%2};" : "=l"(val) : "r"(lo), "r"(hi));
|
||||
return val;
|
||||
uint32_t lo, hi;
|
||||
__kmpc_impl_unpack(val, lo, hi);
|
||||
hi = __kmpc_impl_shfl_down_sync(__kmpc_impl_all_lanes, hi, delta, size);
|
||||
lo = __kmpc_impl_shfl_down_sync(__kmpc_impl_all_lanes, lo, delta, size);
|
||||
return __kmpc_impl_pack(lo, hi);
|
||||
}
|
||||
|
||||
static INLINE void gpu_regular_warp_reduce(void *reduce_data,
|
||||
INLINE static void gpu_regular_warp_reduce(void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct) {
|
||||
for (uint32_t mask = WARPSIZE / 2; mask > 0; mask /= 2) {
|
||||
shflFct(reduce_data, /*LaneId - not used= */ 0,
|
||||
@@ -91,7 +43,7 @@ static INLINE void gpu_regular_warp_reduce(void *reduce_data,
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void gpu_irregular_warp_reduce(void *reduce_data,
|
||||
INLINE static void gpu_irregular_warp_reduce(void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct,
|
||||
uint32_t size, uint32_t tid) {
|
||||
uint32_t curr_size;
|
||||
@@ -105,20 +57,18 @@ static INLINE void gpu_irregular_warp_reduce(void *reduce_data,
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE uint32_t
|
||||
INLINE static uint32_t
|
||||
gpu_irregular_simd_reduce(void *reduce_data, kmp_ShuffleReductFctPtr shflFct) {
|
||||
uint32_t lanemask_lt;
|
||||
uint32_t lanemask_gt;
|
||||
uint32_t size, remote_id, physical_lane_id;
|
||||
physical_lane_id = GetThreadIdInBlock() % WARPSIZE;
|
||||
asm("mov.u32 %0, %%lanemask_lt;" : "=r"(lanemask_lt));
|
||||
uint32_t Liveness = __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
uint32_t logical_lane_id = __popc(Liveness & lanemask_lt) * 2;
|
||||
asm("mov.u32 %0, %%lanemask_gt;" : "=r"(lanemask_gt));
|
||||
__kmpc_impl_lanemask_t lanemask_lt = __kmpc_impl_lanemask_lt();
|
||||
__kmpc_impl_lanemask_t Liveness = __kmpc_impl_activemask();
|
||||
uint32_t logical_lane_id = __kmpc_impl_popc(Liveness & lanemask_lt) * 2;
|
||||
__kmpc_impl_lanemask_t lanemask_gt = __kmpc_impl_lanemask_gt();
|
||||
do {
|
||||
Liveness = __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
remote_id = __ffs(Liveness & lanemask_gt);
|
||||
size = __popc(Liveness);
|
||||
Liveness = __kmpc_impl_activemask();
|
||||
remote_id = __kmpc_impl_ffs(Liveness & lanemask_gt);
|
||||
size = __kmpc_impl_popc(Liveness);
|
||||
logical_lane_id /= 2;
|
||||
shflFct(reduce_data, /*LaneId =*/logical_lane_id,
|
||||
/*Offset=*/remote_id - 1 - physical_lane_id, /*AlgoVersion=*/2);
|
||||
@@ -131,8 +81,8 @@ int32_t __kmpc_nvptx_simd_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct) {
|
||||
uint32_t Liveness = __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
if (Liveness == 0xffffffff) {
|
||||
__kmpc_impl_lanemask_t Liveness = __kmpc_impl_activemask();
|
||||
if (Liveness == __kmpc_impl_all_lanes) {
|
||||
gpu_regular_warp_reduce(reduce_data, shflFct);
|
||||
return GetThreadIdInBlock() % WARPSIZE ==
|
||||
0; // Result on lane 0 of the simd warp.
|
||||
@@ -143,15 +93,12 @@ int32_t __kmpc_nvptx_simd_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
}
|
||||
|
||||
INLINE
|
||||
int32_t nvptx_parallel_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct,
|
||||
bool isSPMDExecutionMode,
|
||||
bool isRuntimeUninitialized = false) {
|
||||
uint32_t BlockThreadId = GetLogicalThreadIdInBlock();
|
||||
uint32_t NumThreads = GetNumberOfOmpThreads(
|
||||
BlockThreadId, isSPMDExecutionMode, isRuntimeUninitialized);
|
||||
static int32_t nvptx_parallel_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct,
|
||||
bool isSPMDExecutionMode, bool isRuntimeUninitialized) {
|
||||
uint32_t BlockThreadId = GetLogicalThreadIdInBlock(isSPMDExecutionMode);
|
||||
uint32_t NumThreads = GetNumberOfOmpThreads(isSPMDExecutionMode);
|
||||
if (NumThreads == 1)
|
||||
return 1;
|
||||
/*
|
||||
@@ -192,17 +139,15 @@ int32_t nvptx_parallel_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
if (WarpId == 0)
|
||||
gpu_irregular_warp_reduce(reduce_data, shflFct, WarpsNeeded,
|
||||
BlockThreadId);
|
||||
|
||||
return BlockThreadId == 0;
|
||||
}
|
||||
return BlockThreadId == 0;
|
||||
#else
|
||||
uint32_t Liveness = __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
if (Liveness == 0xffffffff) // Full warp
|
||||
__kmpc_impl_lanemask_t Liveness = __kmpc_impl_activemask();
|
||||
if (Liveness == __kmpc_impl_all_lanes) // Full warp
|
||||
gpu_regular_warp_reduce(reduce_data, shflFct);
|
||||
else if (!(Liveness & (Liveness + 1))) // Partial warp but contiguous lanes
|
||||
gpu_irregular_warp_reduce(reduce_data, shflFct,
|
||||
/*LaneCount=*/__popc(Liveness),
|
||||
/*LaneCount=*/__kmpc_impl_popc(Liveness),
|
||||
/*LaneId=*/GetThreadIdInBlock() % WARPSIZE);
|
||||
else if (!isRuntimeUninitialized) // Dispersed lanes. Only threads in L2
|
||||
// parallel region may enter here; return
|
||||
@@ -231,55 +176,61 @@ int32_t nvptx_parallel_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
|
||||
// Get the OMP thread Id. This is different from BlockThreadId in the case of
|
||||
// an L2 parallel region.
|
||||
return GetOmpThreadId(BlockThreadId, isSPMDExecutionMode,
|
||||
isRuntimeUninitialized) == 0;
|
||||
return global_tid == 0;
|
||||
#endif // __CUDA_ARCH__ >= 700
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_nvptx_parallel_reduce_nowait(
|
||||
EXTERN __attribute__((deprecated)) int32_t __kmpc_nvptx_parallel_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct) {
|
||||
return nvptx_parallel_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct,
|
||||
/*isSPMDExecutionMode=*/isSPMDMode());
|
||||
isSPMDMode(), isRuntimeUninitialized());
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_nvptx_parallel_reduce_nowait_v2(
|
||||
kmp_Ident *loc, int32_t global_tid, int32_t num_vars, size_t reduce_size,
|
||||
void *reduce_data, kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct) {
|
||||
return nvptx_parallel_reduce_nowait(
|
||||
global_tid, num_vars, reduce_size, reduce_data, shflFct, cpyFct,
|
||||
checkSPMDMode(loc), checkRuntimeUninitialized(loc));
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_nvptx_parallel_reduce_nowait_simple_spmd(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct) {
|
||||
return nvptx_parallel_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct,
|
||||
/*isSPMDExecutionMode=*/true,
|
||||
/*isRuntimeUninitialized=*/true);
|
||||
return nvptx_parallel_reduce_nowait(
|
||||
global_tid, num_vars, reduce_size, reduce_data, shflFct, cpyFct,
|
||||
/*isSPMDExecutionMode=*/true, /*isRuntimeUninitialized=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
int32_t __kmpc_nvptx_parallel_reduce_nowait_simple_generic(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct) {
|
||||
return nvptx_parallel_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct,
|
||||
/*isSPMDExecutionMode=*/false,
|
||||
/*isRuntimeUninitialized=*/true);
|
||||
return nvptx_parallel_reduce_nowait(
|
||||
global_tid, num_vars, reduce_size, reduce_data, shflFct, cpyFct,
|
||||
/*isSPMDExecutionMode=*/false, /*isRuntimeUninitialized=*/true);
|
||||
}
|
||||
|
||||
INLINE
|
||||
int32_t nvptx_teams_reduce_nowait(
|
||||
int32_t global_tid, int32_t num_vars, size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct, kmp_InterWarpCopyFctPtr cpyFct,
|
||||
kmp_CopyToScratchpadFctPtr scratchFct, kmp_LoadReduceFctPtr ldFct,
|
||||
bool isSPMDExecutionMode, bool isRuntimeUninitialized = false) {
|
||||
uint32_t ThreadId = GetLogicalThreadIdInBlock();
|
||||
static int32_t nvptx_teams_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
size_t reduce_size, void *reduce_data,
|
||||
kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct,
|
||||
kmp_CopyToScratchpadFctPtr scratchFct,
|
||||
kmp_LoadReduceFctPtr ldFct,
|
||||
bool isSPMDExecutionMode) {
|
||||
uint32_t ThreadId = GetLogicalThreadIdInBlock(isSPMDExecutionMode);
|
||||
// In non-generic mode all workers participate in the teams reduction.
|
||||
// In generic mode only the team master participates in the teams
|
||||
// reduction because the workers are waiting for parallel work.
|
||||
uint32_t NumThreads =
|
||||
isSPMDExecutionMode
|
||||
? GetNumberOfOmpThreads(ThreadId, /*isSPMDExecutionMode=*/true,
|
||||
isRuntimeUninitialized)
|
||||
: /*Master thread only*/ 1;
|
||||
isSPMDExecutionMode ? GetNumberOfOmpThreads(/*isSPMDExecutionMode=*/true)
|
||||
: /*Master thread only*/ 1;
|
||||
uint32_t TeamId = GetBlockIdInKernel();
|
||||
uint32_t NumTeams = GetNumberOfBlocksInKernel();
|
||||
__shared__ volatile bool IsLastTeam;
|
||||
@@ -366,12 +317,12 @@ int32_t nvptx_teams_reduce_nowait(
|
||||
ldFct(reduce_data, scratchpad, i, NumTeams, /*Load and reduce*/ 1);
|
||||
|
||||
// Reduce across warps to the warp master.
|
||||
uint32_t Liveness = __BALLOT_SYNC(0xFFFFFFFF, true);
|
||||
if (Liveness == 0xffffffff) // Full warp
|
||||
__kmpc_impl_lanemask_t Liveness = __kmpc_impl_activemask();
|
||||
if (Liveness == __kmpc_impl_all_lanes) // Full warp
|
||||
gpu_regular_warp_reduce(reduce_data, shflFct);
|
||||
else // Partial warp but contiguous lanes
|
||||
gpu_irregular_warp_reduce(reduce_data, shflFct,
|
||||
/*LaneCount=*/__popc(Liveness),
|
||||
/*LaneCount=*/__kmpc_impl_popc(Liveness),
|
||||
/*LaneId=*/ThreadId % WARPSIZE);
|
||||
|
||||
// When we have more than [warpsize] number of threads
|
||||
@@ -401,7 +352,7 @@ int32_t __kmpc_nvptx_teams_reduce_nowait(int32_t global_tid, int32_t num_vars,
|
||||
kmp_LoadReduceFctPtr ldFct) {
|
||||
return nvptx_teams_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct, scratchFct,
|
||||
ldFct, /*isSPMDExecutionMode=*/isSPMDMode());
|
||||
ldFct, isSPMDMode());
|
||||
}
|
||||
|
||||
EXTERN
|
||||
@@ -411,9 +362,7 @@ int32_t __kmpc_nvptx_teams_reduce_nowait_simple_spmd(
|
||||
kmp_CopyToScratchpadFctPtr scratchFct, kmp_LoadReduceFctPtr ldFct) {
|
||||
return nvptx_teams_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct, scratchFct,
|
||||
ldFct,
|
||||
/*isSPMDExecutionMode=*/true,
|
||||
/*isRuntimeUninitialized=*/true);
|
||||
ldFct, /*isSPMDExecutionMode=*/true);
|
||||
}
|
||||
|
||||
EXTERN
|
||||
@@ -423,7 +372,163 @@ int32_t __kmpc_nvptx_teams_reduce_nowait_simple_generic(
|
||||
kmp_CopyToScratchpadFctPtr scratchFct, kmp_LoadReduceFctPtr ldFct) {
|
||||
return nvptx_teams_reduce_nowait(global_tid, num_vars, reduce_size,
|
||||
reduce_data, shflFct, cpyFct, scratchFct,
|
||||
ldFct,
|
||||
/*isSPMDExecutionMode=*/false,
|
||||
/*isRuntimeUninitialized=*/true);
|
||||
ldFct, /*isSPMDExecutionMode=*/false);
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait_simple(kmp_Ident *loc,
|
||||
int32_t global_tid,
|
||||
kmp_CriticalName *crit) {
|
||||
if (checkSPMDMode(loc) && GetThreadIdInBlock() != 0)
|
||||
return 0;
|
||||
// The master thread of the team actually does the reduction.
|
||||
while (atomicCAS((uint32_t *)crit, 0, 1))
|
||||
;
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXTERN void
|
||||
__kmpc_nvptx_teams_end_reduce_nowait_simple(kmp_Ident *loc, int32_t global_tid,
|
||||
kmp_CriticalName *crit) {
|
||||
__threadfence_system();
|
||||
(void)atomicExch((uint32_t *)crit, 0);
|
||||
}
|
||||
|
||||
INLINE static bool isMaster(kmp_Ident *loc, uint32_t ThreadId) {
|
||||
return checkGenericMode(loc) || IsTeamMaster(ThreadId);
|
||||
}
|
||||
|
||||
INLINE static uint32_t roundToWarpsize(uint32_t s) {
|
||||
if (s < WARPSIZE)
|
||||
return 1;
|
||||
return (s & ~(unsigned)(WARPSIZE - 1));
|
||||
}
|
||||
|
||||
__device__ static volatile uint32_t IterCnt = 0;
|
||||
__device__ static volatile uint32_t Cnt = 0;
|
||||
EXTERN int32_t __kmpc_nvptx_teams_reduce_nowait_v2(
|
||||
kmp_Ident *loc, int32_t global_tid, void *global_buffer,
|
||||
int32_t num_of_records, void *reduce_data, kmp_ShuffleReductFctPtr shflFct,
|
||||
kmp_InterWarpCopyFctPtr cpyFct, kmp_ListGlobalFctPtr lgcpyFct,
|
||||
kmp_ListGlobalFctPtr lgredFct, kmp_ListGlobalFctPtr glcpyFct,
|
||||
kmp_ListGlobalFctPtr glredFct) {
|
||||
|
||||
// Terminate all threads in non-SPMD mode except for the master thread.
|
||||
if (checkGenericMode(loc) && GetThreadIdInBlock() != GetMasterThreadID())
|
||||
return 0;
|
||||
|
||||
uint32_t ThreadId = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
|
||||
// In non-generic mode all workers participate in the teams reduction.
|
||||
// In generic mode only the team master participates in the teams
|
||||
// reduction because the workers are waiting for parallel work.
|
||||
uint32_t NumThreads =
|
||||
checkSPMDMode(loc) ? GetNumberOfOmpThreads(/*isSPMDExecutionMode=*/true)
|
||||
: /*Master thread only*/ 1;
|
||||
uint32_t TeamId = GetBlockIdInKernel();
|
||||
uint32_t NumTeams = GetNumberOfBlocksInKernel();
|
||||
__shared__ unsigned Bound;
|
||||
__shared__ unsigned ChunkTeamCount;
|
||||
|
||||
// Block progress for teams greater than the current upper
|
||||
// limit. We always only allow a number of teams less or equal
|
||||
// to the number of slots in the buffer.
|
||||
bool IsMaster = isMaster(loc, ThreadId);
|
||||
while (IsMaster) {
|
||||
// Atomic read
|
||||
Bound = atomicAdd((uint32_t *)&IterCnt, 0);
|
||||
if (TeamId < Bound + num_of_records)
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsMaster) {
|
||||
int ModBockId = TeamId % num_of_records;
|
||||
if (TeamId < num_of_records)
|
||||
lgcpyFct(global_buffer, ModBockId, reduce_data);
|
||||
else
|
||||
lgredFct(global_buffer, ModBockId, reduce_data);
|
||||
__threadfence_system();
|
||||
|
||||
// Increment team counter.
|
||||
// This counter is incremented by all teams in the current
|
||||
// BUFFER_SIZE chunk.
|
||||
ChunkTeamCount = atomicInc((uint32_t *)&Cnt, num_of_records - 1);
|
||||
}
|
||||
// Synchronize
|
||||
if (checkSPMDMode(loc))
|
||||
__kmpc_barrier(loc, global_tid);
|
||||
|
||||
// reduce_data is global or shared so before being reduced within the
|
||||
// warp we need to bring it in local memory:
|
||||
// local_reduce_data = reduce_data[i]
|
||||
//
|
||||
// Example for 3 reduction variables a, b, c (of potentially different
|
||||
// types):
|
||||
//
|
||||
// buffer layout (struct of arrays):
|
||||
// a, a, ..., a, b, b, ... b, c, c, ... c
|
||||
// |__________|
|
||||
// num_of_records
|
||||
//
|
||||
// local_data_reduce layout (struct):
|
||||
// a, b, c
|
||||
//
|
||||
// Each thread will have a local struct containing the values to be
|
||||
// reduced:
|
||||
// 1. do reduction within each warp.
|
||||
// 2. do reduction across warps.
|
||||
// 3. write the final result to the main reduction variable
|
||||
// by returning 1 in the thread holding the reduction result.
|
||||
|
||||
// Check if this is the very last team.
|
||||
unsigned NumRecs = min(NumTeams, num_of_records);
|
||||
if (ChunkTeamCount == NumTeams - Bound - 1) {
|
||||
//
|
||||
// Last team processing.
|
||||
//
|
||||
if (ThreadId >= NumRecs)
|
||||
return 0;
|
||||
NumThreads = roundToWarpsize(min(NumThreads, NumRecs));
|
||||
if (ThreadId >= NumThreads)
|
||||
return 0;
|
||||
|
||||
// Load from buffer and reduce.
|
||||
glcpyFct(global_buffer, ThreadId, reduce_data);
|
||||
for (uint32_t i = NumThreads + ThreadId; i < NumRecs; i += NumThreads)
|
||||
glredFct(global_buffer, i, reduce_data);
|
||||
|
||||
// Reduce across warps to the warp master.
|
||||
if (NumThreads > 1) {
|
||||
gpu_regular_warp_reduce(reduce_data, shflFct);
|
||||
|
||||
// When we have more than [warpsize] number of threads
|
||||
// a block reduction is performed here.
|
||||
uint32_t ActiveThreads = min(NumRecs, NumThreads);
|
||||
if (ActiveThreads > WARPSIZE) {
|
||||
uint32_t WarpsNeeded = (ActiveThreads + WARPSIZE - 1) / WARPSIZE;
|
||||
// Gather all the reduced values from each warp
|
||||
// to the first warp.
|
||||
cpyFct(reduce_data, WarpsNeeded);
|
||||
|
||||
uint32_t WarpId = ThreadId / WARPSIZE;
|
||||
if (WarpId == 0)
|
||||
gpu_irregular_warp_reduce(reduce_data, shflFct, WarpsNeeded,
|
||||
ThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMaster) {
|
||||
Cnt = 0;
|
||||
IterCnt = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (IsMaster && ChunkTeamCount == num_of_records - 1) {
|
||||
// Allow SIZE number of teams to proceed writing their
|
||||
// intermediate results to the global buffer.
|
||||
atomicAdd((uint32_t *)&IterCnt, num_of_records);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--------- statequeue.h - NVPTX OpenMP GPU State Queue ------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -35,14 +34,14 @@ private:
|
||||
static const uint32_t MAX_ID = (1u << 31) / SIZE / 2;
|
||||
INLINE uint32_t ENQUEUE_TICKET();
|
||||
INLINE uint32_t DEQUEUE_TICKET();
|
||||
INLINE uint32_t ID(uint32_t ticket);
|
||||
INLINE static uint32_t ID(uint32_t ticket);
|
||||
INLINE bool IsServing(uint32_t slot, uint32_t id);
|
||||
INLINE void PushElement(uint32_t slot, ElementType *element);
|
||||
INLINE ElementType *PopElement(uint32_t slot);
|
||||
INLINE void DoneServing(uint32_t slot, uint32_t id);
|
||||
|
||||
public:
|
||||
INLINE omptarget_nvptx_Queue(){};
|
||||
INLINE omptarget_nvptx_Queue() {}
|
||||
INLINE void Enqueue(ElementType *element);
|
||||
INLINE ElementType *Dequeue();
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------- state-queue.cu - NVPTX OpenMP GPU State Queue ------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -30,7 +29,8 @@ INLINE uint32_t omptarget_nvptx_Queue<ElementType, SIZE>::DEQUEUE_TICKET() {
|
||||
}
|
||||
|
||||
template <typename ElementType, uint32_t SIZE>
|
||||
INLINE uint32_t omptarget_nvptx_Queue<ElementType, SIZE>::ID(uint32_t ticket) {
|
||||
INLINE uint32_t
|
||||
omptarget_nvptx_Queue<ElementType, SIZE>::ID(uint32_t ticket) {
|
||||
return (ticket / SIZE) * 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--------- support.h - NVPTX OpenMP support functions -------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -11,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "target_impl.h"
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Execution Parameters
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -41,30 +41,34 @@ INLINE int GetThreadIdInBlock();
|
||||
INLINE int GetBlockIdInKernel();
|
||||
INLINE int GetNumberOfBlocksInKernel();
|
||||
INLINE int GetNumberOfThreadsInBlock();
|
||||
INLINE unsigned GetWarpId();
|
||||
INLINE unsigned GetLaneId();
|
||||
|
||||
// get global ids to locate tread/team info (constant regardless of OMP)
|
||||
INLINE int GetLogicalThreadIdInBlock();
|
||||
INLINE int GetLogicalThreadIdInBlock(bool isSPMDExecutionMode);
|
||||
INLINE int GetMasterThreadID();
|
||||
INLINE int GetNumberOfWorkersInTeam();
|
||||
|
||||
// get OpenMP thread and team ids
|
||||
INLINE int GetOmpThreadId(int threadId, bool isSPMDExecutionMode,
|
||||
bool isRuntimeUninitialized); // omp_thread_num
|
||||
INLINE int GetOmpThreadId(int threadId,
|
||||
bool isSPMDExecutionMode); // omp_thread_num
|
||||
INLINE int GetOmpTeamId(); // omp_team_num
|
||||
|
||||
// get OpenMP number of threads and team
|
||||
INLINE int
|
||||
GetNumberOfOmpThreads(int threadId, bool isSPMDExecutionMode,
|
||||
bool isRuntimeUninitialized); // omp_num_threads
|
||||
INLINE int GetNumberOfOmpTeams(); // omp_num_teams
|
||||
INLINE int GetNumberOfOmpThreads(bool isSPMDExecutionMode); // omp_num_threads
|
||||
INLINE int GetNumberOfOmpTeams(); // omp_num_teams
|
||||
|
||||
// get OpenMP number of procs
|
||||
INLINE int GetNumberOfProcsInTeam();
|
||||
INLINE int GetNumberOfProcsInDevice();
|
||||
INLINE int GetNumberOfProcsInTeam(bool isSPMDExecutionMode);
|
||||
INLINE int GetNumberOfProcsInDevice(bool isSPMDExecutionMode);
|
||||
|
||||
// masters
|
||||
INLINE int IsTeamMaster(int ompThreadId);
|
||||
|
||||
// Parallel level
|
||||
INLINE void IncParallelLevel(bool ActiveParallel, __kmpc_impl_lanemask_t Mask);
|
||||
INLINE void DecParallelLevel(bool ActiveParallel, __kmpc_impl_lanemask_t Mask);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===--------- supporti.h - NVPTX OpenMP support functions ------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -15,6 +14,8 @@
|
||||
// Execution Parameters
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "target_impl.h"
|
||||
|
||||
INLINE void setExecutionParameters(ExecutionMode EMode, RuntimeMode RMode) {
|
||||
execution_param = EMode;
|
||||
execution_param |= RMode;
|
||||
@@ -32,6 +33,59 @@ INLINE bool isRuntimeInitialized() {
|
||||
return (execution_param & RuntimeMask) == RuntimeInitialized;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Execution Modes based on location parameter fields
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE bool checkSPMDMode(kmp_Ident *loc) {
|
||||
if (!loc)
|
||||
return isSPMDMode();
|
||||
|
||||
// If SPMD is true then we are not in the UNDEFINED state so
|
||||
// we can return immediately.
|
||||
if (loc->reserved_2 & KMP_IDENT_SPMD_MODE)
|
||||
return true;
|
||||
|
||||
// If not in SPMD mode and runtime required is a valid
|
||||
// combination of flags so we can return immediately.
|
||||
if (!(loc->reserved_2 & KMP_IDENT_SIMPLE_RT_MODE))
|
||||
return false;
|
||||
|
||||
// We are in underfined state.
|
||||
return isSPMDMode();
|
||||
}
|
||||
|
||||
INLINE bool checkGenericMode(kmp_Ident *loc) {
|
||||
return !checkSPMDMode(loc);
|
||||
}
|
||||
|
||||
INLINE bool checkRuntimeUninitialized(kmp_Ident *loc) {
|
||||
if (!loc)
|
||||
return isRuntimeUninitialized();
|
||||
|
||||
// If runtime is required then we know we can't be
|
||||
// in the undefined mode. We can return immediately.
|
||||
if (!(loc->reserved_2 & KMP_IDENT_SIMPLE_RT_MODE))
|
||||
return false;
|
||||
|
||||
// If runtime is required then we need to check is in
|
||||
// SPMD mode or not. If not in SPMD mode then we end
|
||||
// up in the UNDEFINED state that marks the orphaned
|
||||
// functions.
|
||||
if (loc->reserved_2 & KMP_IDENT_SPMD_MODE)
|
||||
return true;
|
||||
|
||||
// Check if we are in an UNDEFINED state. Undefined is denoted by
|
||||
// non-SPMD + noRuntimeRequired which is a combination that
|
||||
// cannot actually happen. Undefined states is used to mark orphaned
|
||||
// functions.
|
||||
return isRuntimeUninitialized();
|
||||
}
|
||||
|
||||
INLINE bool checkRuntimeInitialized(kmp_Ident *loc) {
|
||||
return !checkRuntimeUninitialized(loc);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support: get info from machine
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -50,6 +104,10 @@ INLINE int GetNumberOfBlocksInKernel() { return gridDim.x; }
|
||||
|
||||
INLINE int GetNumberOfThreadsInBlock() { return blockDim.x; }
|
||||
|
||||
INLINE unsigned GetWarpId() { return threadIdx.x / WARPSIZE; }
|
||||
|
||||
INLINE unsigned GetLaneId() { return threadIdx.x & (WARPSIZE - 1); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Calls to the Generic Scheme Implementation Layer (assuming 1D layout)
|
||||
@@ -77,13 +135,11 @@ INLINE int GetNumberOfWorkersInTeam() { return GetMasterThreadID(); }
|
||||
// or a serial region by the master. If the master (whose CUDA thread
|
||||
// id is GetMasterThreadID()) calls this routine, we return 0 because
|
||||
// it is a shadow for the first worker.
|
||||
INLINE int GetLogicalThreadIdInBlock() {
|
||||
// return GetThreadIdInBlock() % GetMasterThreadID();
|
||||
|
||||
INLINE int GetLogicalThreadIdInBlock(bool isSPMDExecutionMode) {
|
||||
// Implemented using control flow (predication) instead of with a modulo
|
||||
// operation.
|
||||
int tid = GetThreadIdInBlock();
|
||||
if (isGenericMode() && tid >= GetMasterThreadID())
|
||||
if (!isSPMDExecutionMode && tid >= GetMasterThreadID())
|
||||
return 0;
|
||||
else
|
||||
return tid;
|
||||
@@ -95,36 +151,32 @@ INLINE int GetLogicalThreadIdInBlock() {
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE int GetOmpThreadId(int threadId, bool isSPMDExecutionMode,
|
||||
bool isRuntimeUninitialized) {
|
||||
INLINE int GetOmpThreadId(int threadId, bool isSPMDExecutionMode) {
|
||||
// omp_thread_num
|
||||
int rc;
|
||||
|
||||
if (isRuntimeUninitialized) {
|
||||
if ((parallelLevel[GetWarpId()] & (OMP_ACTIVE_PARALLEL_LEVEL - 1)) > 1) {
|
||||
rc = 0;
|
||||
} else if (isSPMDExecutionMode) {
|
||||
rc = GetThreadIdInBlock();
|
||||
if (!isSPMDExecutionMode && rc >= GetMasterThreadID())
|
||||
rc = 0;
|
||||
} else {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
ASSERT0(LT_FUSSY, currTaskDescr, "expected a top task descr");
|
||||
rc = currTaskDescr->ThreadId();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
INLINE int GetNumberOfOmpThreads(int threadId, bool isSPMDExecutionMode,
|
||||
bool isRuntimeUninitialized) {
|
||||
INLINE int GetNumberOfOmpThreads(bool isSPMDExecutionMode) {
|
||||
// omp_num_threads
|
||||
int rc;
|
||||
|
||||
if (isRuntimeUninitialized) {
|
||||
rc = isSPMDExecutionMode ? GetNumberOfThreadsInBlock()
|
||||
: GetNumberOfThreadsInBlock() - WARPSIZE;
|
||||
int Level = parallelLevel[GetWarpId()];
|
||||
if (Level != OMP_ACTIVE_PARALLEL_LEVEL + 1) {
|
||||
rc = 1;
|
||||
} else if (isSPMDExecutionMode) {
|
||||
rc = GetNumberOfThreadsInBlock();
|
||||
} else {
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(threadId);
|
||||
ASSERT0(LT_FUSSY, currTaskDescr, "expected a top task descr");
|
||||
rc = currTaskDescr->ThreadsInTeam();
|
||||
rc = threadsInTeam;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -148,17 +200,46 @@ INLINE int GetNumberOfOmpTeams() {
|
||||
|
||||
INLINE int IsTeamMaster(int ompThreadId) { return (ompThreadId == 0); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Parallel level
|
||||
|
||||
INLINE void IncParallelLevel(bool ActiveParallel, __kmpc_impl_lanemask_t Mask) {
|
||||
__kmpc_impl_syncwarp(Mask);
|
||||
__kmpc_impl_lanemask_t LaneMaskLt = __kmpc_impl_lanemask_lt();
|
||||
unsigned Rank = __kmpc_impl_popc(Mask & LaneMaskLt);
|
||||
if (Rank == 0) {
|
||||
parallelLevel[GetWarpId()] +=
|
||||
(1 + (ActiveParallel ? OMP_ACTIVE_PARALLEL_LEVEL : 0));
|
||||
__threadfence();
|
||||
}
|
||||
__kmpc_impl_syncwarp(Mask);
|
||||
}
|
||||
|
||||
INLINE void DecParallelLevel(bool ActiveParallel, __kmpc_impl_lanemask_t Mask) {
|
||||
__kmpc_impl_syncwarp(Mask);
|
||||
__kmpc_impl_lanemask_t LaneMaskLt = __kmpc_impl_lanemask_lt();
|
||||
unsigned Rank = __kmpc_impl_popc(Mask & LaneMaskLt);
|
||||
if (Rank == 0) {
|
||||
parallelLevel[GetWarpId()] -=
|
||||
(1 + (ActiveParallel ? OMP_ACTIVE_PARALLEL_LEVEL : 0));
|
||||
__threadfence();
|
||||
}
|
||||
__kmpc_impl_syncwarp(Mask);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// get OpenMP number of procs
|
||||
|
||||
// Get the number of processors in the device.
|
||||
INLINE int GetNumberOfProcsInDevice() {
|
||||
if (isGenericMode())
|
||||
INLINE int GetNumberOfProcsInDevice(bool isSPMDExecutionMode) {
|
||||
if (!isSPMDExecutionMode)
|
||||
return GetNumberOfWorkersInTeam();
|
||||
return GetNumberOfThreadsInBlock();
|
||||
}
|
||||
|
||||
INLINE int GetNumberOfProcsInTeam() { return GetNumberOfProcsInDevice(); }
|
||||
INLINE int GetNumberOfProcsInTeam(bool isSPMDExecutionMode) {
|
||||
return GetNumberOfProcsInDevice(isSPMDExecutionMode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory
|
||||
@@ -169,20 +250,20 @@ INLINE unsigned long PadBytes(unsigned long size,
|
||||
{
|
||||
// compute the necessary padding to satisfy alignment constraint
|
||||
ASSERT(LT_FUSSY, (alignment & (alignment - 1)) == 0,
|
||||
"alignment %ld is not a power of 2\n", alignment);
|
||||
"alignment %lu is not a power of 2\n", alignment);
|
||||
return (~(unsigned long)size + 1) & (alignment - 1);
|
||||
}
|
||||
|
||||
INLINE void *SafeMalloc(size_t size, const char *msg) // check if success
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
PRINT(LD_MEM, "malloc data of size %zu for %s: 0x%llx\n", size, msg, P64(ptr));
|
||||
ASSERT(LT_SAFETY, ptr, "failed to allocate %zu bytes for %s\n", size, msg);
|
||||
PRINT(LD_MEM, "malloc data of size %llu for %s: 0x%llx\n",
|
||||
(unsigned long long)size, msg, (unsigned long long)ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
INLINE void *SafeFree(void *ptr, const char *msg) {
|
||||
PRINT(LD_MEM, "free data ptr 0x%llx for %s\n", P64(ptr), msg);
|
||||
PRINT(LD_MEM, "free data ptr 0x%llx for %s\n", (unsigned long long)ptr, msg);
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------ sync.h - NVPTX OpenMP synchronizations --------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -12,16 +11,17 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "omptarget-nvptx.h"
|
||||
#include "target_impl.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// KMP Ordered calls
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_ordered(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_ordered(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_ordered\n");
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_end_ordered(kmp_Indent *loc, int32_t tid) {
|
||||
EXTERN void __kmpc_end_ordered(kmp_Ident *loc, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_end_ordered\n");
|
||||
}
|
||||
|
||||
@@ -33,27 +33,24 @@ EXTERN void __kmpc_end_ordered(kmp_Indent *loc, int32_t tid) {
|
||||
// FIXME: what if not all threads (warps) participate to the barrier?
|
||||
// We may need to implement it differently
|
||||
|
||||
EXTERN int32_t __kmpc_cancel_barrier(kmp_Indent *loc_ref, int32_t tid) {
|
||||
EXTERN int32_t __kmpc_cancel_barrier(kmp_Ident *loc_ref, int32_t tid) {
|
||||
PRINT0(LD_IO, "call kmpc_cancel_barrier\n");
|
||||
__kmpc_barrier(loc_ref, tid);
|
||||
PRINT0(LD_SYNC, "completed kmpc_cancel_barrier\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_barrier(kmp_Indent *loc_ref, int32_t tid) {
|
||||
if (isRuntimeUninitialized()) {
|
||||
if (isSPMDMode())
|
||||
__kmpc_barrier_simple_spmd(loc_ref, tid);
|
||||
else
|
||||
__kmpc_barrier_simple_generic(loc_ref, tid);
|
||||
EXTERN void __kmpc_barrier(kmp_Ident *loc_ref, int32_t tid) {
|
||||
if (checkRuntimeUninitialized(loc_ref)) {
|
||||
ASSERT0(LT_FUSSY, checkSPMDMode(loc_ref),
|
||||
"Expected SPMD mode with uninitialized runtime.");
|
||||
__kmpc_barrier_simple_spmd(loc_ref, tid);
|
||||
} else {
|
||||
tid = GetLogicalThreadIdInBlock();
|
||||
omptarget_nvptx_TaskDescr *currTaskDescr =
|
||||
omptarget_nvptx_threadPrivateContext->GetTopLevelTaskDescr(tid);
|
||||
int numberOfActiveOMPThreads = GetNumberOfOmpThreads(
|
||||
tid, isSPMDMode(), /*isRuntimeUninitialized=*/false);
|
||||
tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc_ref));
|
||||
int numberOfActiveOMPThreads =
|
||||
GetNumberOfOmpThreads(checkSPMDMode(loc_ref));
|
||||
if (numberOfActiveOMPThreads > 1) {
|
||||
if (isSPMDMode()) {
|
||||
if (checkSPMDMode(loc_ref)) {
|
||||
__kmpc_barrier_simple_spmd(loc_ref, tid);
|
||||
} else {
|
||||
// The #threads parameter must be rounded up to the WARPSIZE.
|
||||
@@ -62,10 +59,13 @@ EXTERN void __kmpc_barrier(kmp_Indent *loc_ref, int32_t tid) {
|
||||
|
||||
PRINT(LD_SYNC,
|
||||
"call kmpc_barrier with %d omp threads, sync parameter %d\n",
|
||||
numberOfActiveOMPThreads, threads);
|
||||
(int)numberOfActiveOMPThreads, (int)threads);
|
||||
// Barrier #1 is for synchronization among active threads.
|
||||
named_sync(L1_BARRIER, threads);
|
||||
}
|
||||
} else {
|
||||
// Still need to flush the memory per the standard.
|
||||
__kmpc_flush(loc_ref);
|
||||
} // numberOfActiveOMPThreads > 1
|
||||
PRINT0(LD_SYNC, "completed kmpc_barrier\n");
|
||||
}
|
||||
@@ -73,15 +73,15 @@ EXTERN void __kmpc_barrier(kmp_Indent *loc_ref, int32_t tid) {
|
||||
|
||||
// Emit a simple barrier call in SPMD mode. Assumes the caller is in an L0
|
||||
// parallel region and that all worker threads participate.
|
||||
EXTERN void __kmpc_barrier_simple_spmd(kmp_Indent *loc_ref, int32_t tid) {
|
||||
EXTERN void __kmpc_barrier_simple_spmd(kmp_Ident *loc_ref, int32_t tid) {
|
||||
PRINT0(LD_SYNC, "call kmpc_barrier_simple_spmd\n");
|
||||
__syncthreads();
|
||||
__kmpc_impl_syncthreads();
|
||||
PRINT0(LD_SYNC, "completed kmpc_barrier_simple_spmd\n");
|
||||
}
|
||||
|
||||
// Emit a simple barrier call in Generic mode. Assumes the caller is in an L0
|
||||
// parallel region and that all worker threads participate.
|
||||
EXTERN void __kmpc_barrier_simple_generic(kmp_Indent *loc_ref, int32_t tid) {
|
||||
EXTERN void __kmpc_barrier_simple_generic(kmp_Ident *loc_ref, int32_t tid) {
|
||||
int numberOfActiveOMPThreads = GetNumberOfThreadsInBlock() - WARPSIZE;
|
||||
// The #threads parameter must be rounded up to the WARPSIZE.
|
||||
int threads =
|
||||
@@ -90,7 +90,7 @@ EXTERN void __kmpc_barrier_simple_generic(kmp_Indent *loc_ref, int32_t tid) {
|
||||
PRINT(LD_SYNC,
|
||||
"call kmpc_barrier_simple_generic with %d omp threads, sync parameter "
|
||||
"%d\n",
|
||||
numberOfActiveOMPThreads, threads);
|
||||
(int)numberOfActiveOMPThreads, (int)threads);
|
||||
// Barrier #1 is for synchronization among active threads.
|
||||
named_sync(L1_BARRIER, threads);
|
||||
PRINT0(LD_SYNC, "completed kmpc_barrier_simple_generic\n");
|
||||
@@ -100,37 +100,30 @@ EXTERN void __kmpc_barrier_simple_generic(kmp_Indent *loc_ref, int32_t tid) {
|
||||
// KMP MASTER
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INLINE int32_t IsMaster() {
|
||||
// only the team master updates the state
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int ompThreadId = GetOmpThreadId(tid, isSPMDMode(), isRuntimeUninitialized());
|
||||
return IsTeamMaster(ompThreadId);
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_master(kmp_Indent *loc, int32_t global_tid) {
|
||||
EXTERN int32_t __kmpc_master(kmp_Ident *loc, int32_t global_tid) {
|
||||
PRINT0(LD_IO, "call kmpc_master\n");
|
||||
return IsMaster();
|
||||
return IsTeamMaster(global_tid);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_end_master(kmp_Indent *loc, int32_t global_tid) {
|
||||
EXTERN void __kmpc_end_master(kmp_Ident *loc, int32_t global_tid) {
|
||||
PRINT0(LD_IO, "call kmpc_end_master\n");
|
||||
ASSERT0(LT_FUSSY, IsMaster(), "expected only master here");
|
||||
ASSERT0(LT_FUSSY, IsTeamMaster(global_tid), "expected only master here");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// KMP SINGLE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN int32_t __kmpc_single(kmp_Indent *loc, int32_t global_tid) {
|
||||
EXTERN int32_t __kmpc_single(kmp_Ident *loc, int32_t global_tid) {
|
||||
PRINT0(LD_IO, "call kmpc_single\n");
|
||||
// decide to implement single with master; master get the single
|
||||
return IsMaster();
|
||||
return IsTeamMaster(global_tid);
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_end_single(kmp_Indent *loc, int32_t global_tid) {
|
||||
EXTERN void __kmpc_end_single(kmp_Ident *loc, int32_t global_tid) {
|
||||
PRINT0(LD_IO, "call kmpc_end_single\n");
|
||||
// decide to implement single with master: master get the single
|
||||
ASSERT0(LT_FUSSY, IsMaster(), "expected only master here");
|
||||
ASSERT0(LT_FUSSY, IsTeamMaster(global_tid), "expected only master here");
|
||||
// sync barrier is explicitely called... so that is not a problem
|
||||
}
|
||||
|
||||
@@ -138,16 +131,25 @@ EXTERN void __kmpc_end_single(kmp_Indent *loc, int32_t global_tid) {
|
||||
// Flush
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_flush(kmp_Indent *loc) {
|
||||
EXTERN void __kmpc_flush(kmp_Ident *loc) {
|
||||
PRINT0(LD_IO, "call kmpc_flush\n");
|
||||
__threadfence_block();
|
||||
__threadfence();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Vote
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN int32_t __kmpc_warp_active_thread_mask() {
|
||||
EXTERN __kmpc_impl_lanemask_t __kmpc_warp_active_thread_mask() {
|
||||
PRINT0(LD_IO, "call __kmpc_warp_active_thread_mask\n");
|
||||
return __ACTIVEMASK();
|
||||
return __kmpc_impl_activemask();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Syncwarp
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EXTERN void __kmpc_syncwarp(__kmpc_impl_lanemask_t Mask) {
|
||||
PRINT0(LD_IO, "call __kmpc_syncwarp\n");
|
||||
__kmpc_impl_syncwarp(Mask);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
//===------------ target_impl.h - NVPTX OpenMP GPU options ------- CUDA -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Definitions of target specific functions
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef _TARGET_IMPL_H_
|
||||
#define _TARGET_IMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "option.h"
|
||||
|
||||
INLINE void __kmpc_impl_unpack(uint64_t val, uint32_t &lo, uint32_t &hi) {
|
||||
asm volatile("mov.b64 {%0,%1}, %2;" : "=r"(lo), "=r"(hi) : "l"(val));
|
||||
}
|
||||
|
||||
INLINE uint64_t __kmpc_impl_pack(uint32_t lo, uint32_t hi) {
|
||||
uint64_t val;
|
||||
asm volatile("mov.b64 %0, {%1,%2};" : "=l"(val) : "r"(lo), "r"(hi));
|
||||
return val;
|
||||
}
|
||||
|
||||
static const __kmpc_impl_lanemask_t __kmpc_impl_all_lanes =
|
||||
UINT32_C(0xffffffff);
|
||||
|
||||
INLINE __kmpc_impl_lanemask_t __kmpc_impl_lanemask_lt() {
|
||||
__kmpc_impl_lanemask_t res;
|
||||
asm("mov.u32 %0, %%lanemask_lt;" : "=r"(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
INLINE __kmpc_impl_lanemask_t __kmpc_impl_lanemask_gt() {
|
||||
__kmpc_impl_lanemask_t res;
|
||||
asm("mov.u32 %0, %%lanemask_gt;" : "=r"(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
INLINE uint32_t __kmpc_impl_ffs(uint32_t x) { return __ffs(x); }
|
||||
|
||||
INLINE uint32_t __kmpc_impl_popc(uint32_t x) { return __popc(x); }
|
||||
|
||||
#ifndef CUDA_VERSION
|
||||
#error CUDA_VERSION macro is undefined, something wrong with cuda.
|
||||
#endif
|
||||
|
||||
// In Cuda 9.0, __ballot(1) from Cuda 8.0 is replaced with __activemask().
|
||||
|
||||
INLINE __kmpc_impl_lanemask_t __kmpc_impl_activemask() {
|
||||
#if CUDA_VERSION >= 9000
|
||||
return __activemask();
|
||||
#else
|
||||
return __ballot(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// In Cuda 9.0, the *_sync() version takes an extra argument 'mask'.
|
||||
|
||||
INLINE int32_t __kmpc_impl_shfl_sync(__kmpc_impl_lanemask_t Mask, int32_t Var,
|
||||
int32_t SrcLane) {
|
||||
#if CUDA_VERSION >= 9000
|
||||
return __shfl_sync(Mask, Var, SrcLane);
|
||||
#else
|
||||
return __shfl(Var, SrcLane);
|
||||
#endif // CUDA_VERSION
|
||||
}
|
||||
|
||||
INLINE int32_t __kmpc_impl_shfl_down_sync(__kmpc_impl_lanemask_t Mask,
|
||||
int32_t Var, uint32_t Delta,
|
||||
int32_t Width) {
|
||||
#if CUDA_VERSION >= 9000
|
||||
return __shfl_down_sync(Mask, Var, Delta, Width);
|
||||
#else
|
||||
return __shfl_down(Var, Delta, Width);
|
||||
#endif // CUDA_VERSION
|
||||
}
|
||||
|
||||
INLINE void __kmpc_impl_syncthreads() {
|
||||
// Use original __syncthreads if compiled by nvcc or clang >= 9.0.
|
||||
#if !defined(__clang__) || __clang_major__ >= 9
|
||||
__syncthreads();
|
||||
#else
|
||||
asm volatile("bar.sync %0;" : : "r"(0) : "memory");
|
||||
#endif // __clang__
|
||||
}
|
||||
|
||||
INLINE void __kmpc_impl_syncwarp(__kmpc_impl_lanemask_t Mask) {
|
||||
#if CUDA_VERSION >= 9000
|
||||
__syncwarp(Mask);
|
||||
#else
|
||||
// In Cuda < 9.0 no need to sync threads in warps.
|
||||
#endif // CUDA_VERSION
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
//===------------- task.h - NVPTX OpenMP tasks support ----------- CUDA -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -31,7 +30,7 @@
|
||||
#include "omptarget-nvptx.h"
|
||||
|
||||
EXTERN kmp_TaskDescr *__kmpc_omp_task_alloc(
|
||||
kmp_Indent *loc, // unused
|
||||
kmp_Ident *loc, // unused
|
||||
uint32_t global_tid, // unused
|
||||
int32_t flag, // unused (because in our impl, all are immediately exec
|
||||
size_t sizeOfTaskInclPrivate, size_t sizeOfSharedTable,
|
||||
@@ -39,14 +38,15 @@ EXTERN kmp_TaskDescr *__kmpc_omp_task_alloc(
|
||||
PRINT(LD_IO,
|
||||
"call __kmpc_omp_task_alloc(size priv&struct %lld, shared %lld, "
|
||||
"fct 0x%llx)\n",
|
||||
P64(sizeOfTaskInclPrivate), P64(sizeOfSharedTable), P64(taskSub));
|
||||
(long long)sizeOfTaskInclPrivate, (long long)sizeOfSharedTable,
|
||||
(unsigned long long)taskSub);
|
||||
// want task+priv to be a multiple of 8 bytes
|
||||
size_t padForTaskInclPriv = PadBytes(sizeOfTaskInclPrivate, sizeof(void *));
|
||||
sizeOfTaskInclPrivate += padForTaskInclPriv;
|
||||
size_t kmpSize = sizeOfTaskInclPrivate + sizeOfSharedTable;
|
||||
ASSERT(LT_FUSSY, sizeof(omptarget_nvptx_TaskDescr) % sizeof(void *) == 0,
|
||||
"need task descr of size %d to be a multiple of %d\n",
|
||||
sizeof(omptarget_nvptx_TaskDescr), sizeof(void *));
|
||||
(int)sizeof(omptarget_nvptx_TaskDescr), (int)sizeof(void *));
|
||||
size_t totSize = sizeof(omptarget_nvptx_TaskDescr) + kmpSize;
|
||||
omptarget_nvptx_ExplicitTaskDescr *newExplicitTaskDescr =
|
||||
(omptarget_nvptx_ExplicitTaskDescr *)SafeMalloc(
|
||||
@@ -63,24 +63,27 @@ EXTERN kmp_TaskDescr *__kmpc_omp_task_alloc(
|
||||
newKmpTaskDescr->sub = taskSub;
|
||||
newKmpTaskDescr->destructors = NULL;
|
||||
PRINT(LD_TASK, "return with task descr kmp: 0x%llx, omptarget-nvptx 0x%llx\n",
|
||||
P64(newKmpTaskDescr), P64(newExplicitTaskDescr));
|
||||
(unsigned long long)newKmpTaskDescr,
|
||||
(unsigned long long)newExplicitTaskDescr);
|
||||
|
||||
return newKmpTaskDescr;
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_omp_task(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_task(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr) {
|
||||
return __kmpc_omp_task_with_deps(loc, global_tid, newKmpTaskDescr, 0, 0, 0,
|
||||
0);
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr,
|
||||
int32_t depNum, void *depList,
|
||||
int32_t noAliasDepNum,
|
||||
void *noAliasDepList) {
|
||||
PRINT(LD_IO, "call to __kmpc_omp_task_with_deps(task 0x%llx)\n",
|
||||
P64(newKmpTaskDescr));
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc),
|
||||
"Runtime must be initialized.");
|
||||
// 1. get explict task descr from kmp task descr
|
||||
omptarget_nvptx_ExplicitTaskDescr *newExplicitTaskDescr =
|
||||
(omptarget_nvptx_ExplicitTaskDescr *)SUB_BYTES(
|
||||
@@ -92,7 +95,7 @@ EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
"bad assumptions");
|
||||
|
||||
// 2. push new context: update new task descriptor
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr = getMyTopTaskDescriptor(tid);
|
||||
newTaskDescr->CopyForExplicitTask(parentTaskDescr);
|
||||
// set new task descriptor as top
|
||||
@@ -100,10 +103,11 @@ EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
|
||||
// 3. call sub
|
||||
PRINT(LD_TASK, "call task sub 0x%llx(task descr 0x%llx)\n",
|
||||
P64(newKmpTaskDescr->sub), P64(newKmpTaskDescr));
|
||||
(unsigned long long)newKmpTaskDescr->sub,
|
||||
(unsigned long long)newKmpTaskDescr);
|
||||
newKmpTaskDescr->sub(0, newKmpTaskDescr);
|
||||
PRINT(LD_TASK, "return from call task sub 0x%llx()\n",
|
||||
P64(newKmpTaskDescr->sub));
|
||||
(unsigned long long)newKmpTaskDescr->sub);
|
||||
|
||||
// 4. pop context
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(tid,
|
||||
@@ -113,10 +117,12 @@ EXTERN int32_t __kmpc_omp_task_with_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_omp_task_begin_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_task_begin_if0(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr) {
|
||||
PRINT(LD_IO, "call to __kmpc_omp_task_begin_if0(task 0x%llx)\n",
|
||||
P64(newKmpTaskDescr));
|
||||
(unsigned long long)newKmpTaskDescr);
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc),
|
||||
"Runtime must be initialized.");
|
||||
// 1. get explict task descr from kmp task descr
|
||||
omptarget_nvptx_ExplicitTaskDescr *newExplicitTaskDescr =
|
||||
(omptarget_nvptx_ExplicitTaskDescr *)SUB_BYTES(
|
||||
@@ -128,7 +134,7 @@ EXTERN void __kmpc_omp_task_begin_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
"bad assumptions");
|
||||
|
||||
// 2. push new context: update new task descriptor
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr = getMyTopTaskDescriptor(tid);
|
||||
newTaskDescr->CopyForExplicitTask(parentTaskDescr);
|
||||
// set new task descriptor as top
|
||||
@@ -137,10 +143,12 @@ EXTERN void __kmpc_omp_task_begin_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
// 4 & 5 ... done in complete
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_omp_task_complete_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_task_complete_if0(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr) {
|
||||
PRINT(LD_IO, "call to __kmpc_omp_task_complete_if0(task 0x%llx)\n",
|
||||
P64(newKmpTaskDescr));
|
||||
(unsigned long long)newKmpTaskDescr);
|
||||
ASSERT0(LT_FUSSY, checkRuntimeInitialized(loc),
|
||||
"Runtime must be initialized.");
|
||||
// 1. get explict task descr from kmp task descr
|
||||
omptarget_nvptx_ExplicitTaskDescr *newExplicitTaskDescr =
|
||||
(omptarget_nvptx_ExplicitTaskDescr *)SUB_BYTES(
|
||||
@@ -154,44 +162,44 @@ EXTERN void __kmpc_omp_task_complete_if0(kmp_Indent *loc, uint32_t global_tid,
|
||||
omptarget_nvptx_TaskDescr *parentTaskDescr = newTaskDescr->GetPrevTaskDescr();
|
||||
// 3... noting to call... is inline
|
||||
// 4. pop context
|
||||
int tid = GetLogicalThreadIdInBlock();
|
||||
int tid = GetLogicalThreadIdInBlock(checkSPMDMode(loc));
|
||||
omptarget_nvptx_threadPrivateContext->SetTopLevelTaskDescr(tid,
|
||||
parentTaskDescr);
|
||||
// 5. free
|
||||
SafeFree(newExplicitTaskDescr, "explicit task descriptor");
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_omp_wait_deps(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_omp_wait_deps(kmp_Ident *loc, uint32_t global_tid,
|
||||
int32_t depNum, void *depList,
|
||||
int32_t noAliasDepNum, void *noAliasDepList) {
|
||||
PRINT0(LD_IO, "call to __kmpc_omp_wait_deps(..)\n");
|
||||
// nothing to do as all our tasks are executed as final
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_taskgroup(kmp_Indent *loc, uint32_t global_tid) {
|
||||
EXTERN void __kmpc_taskgroup(kmp_Ident *loc, uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_taskgroup(..)\n");
|
||||
// nothing to do as all our tasks are executed as final
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_end_taskgroup(kmp_Indent *loc, uint32_t global_tid) {
|
||||
EXTERN void __kmpc_end_taskgroup(kmp_Ident *loc, uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_end_taskgroup(..)\n");
|
||||
// nothing to do as all our tasks are executed as final
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_omp_taskyield(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN int32_t __kmpc_omp_taskyield(kmp_Ident *loc, uint32_t global_tid,
|
||||
int end_part) {
|
||||
PRINT0(LD_IO, "call to __kmpc_taskyield()\n");
|
||||
// do nothing: tasks are executed immediately, no yielding allowed
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN int32_t __kmpc_omp_taskwait(kmp_Indent *loc, uint32_t global_tid) {
|
||||
EXTERN int32_t __kmpc_omp_taskwait(kmp_Ident *loc, uint32_t global_tid) {
|
||||
PRINT0(LD_IO, "call to __kmpc_taskwait()\n");
|
||||
// nothing to do as all our tasks are executed as final
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN void __kmpc_taskloop(kmp_Indent *loc, uint32_t global_tid,
|
||||
EXTERN void __kmpc_taskloop(kmp_Ident *loc, uint32_t global_tid,
|
||||
kmp_TaskDescr *newKmpTaskDescr, int if_val,
|
||||
uint64_t *lb, uint64_t *ub, int64_t st, int nogroup,
|
||||
int32_t sched, uint64_t grainsize, void *task_dup) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
if(NOT OPENMP_TEST_COMPILER_ID STREQUAL "Clang")
|
||||
# Silently return, no need to annoy the user.
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(deps omptarget-nvptx omptarget omp)
|
||||
if(LIBOMPTARGET_NVPTX_ENABLE_BCLIB)
|
||||
set(deps ${deps} omptarget-nvptx-bc)
|
||||
endif()
|
||||
|
||||
# Don't run by default.
|
||||
set(EXCLUDE_FROM_ALL True)
|
||||
# Run with only one thread to only launch one application to the GPU at a time.
|
||||
add_openmp_testsuite(check-libomptarget-nvptx
|
||||
"Running libomptarget-nvptx tests" ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS ${deps} ARGS -j1)
|
||||
|
||||
set(LIBOMPTARGET_NVPTX_TEST_FLAGS "" CACHE STRING
|
||||
"Extra compiler flags to send to the test compiler.")
|
||||
set(LIBOMPTARGET_NVPTX_TEST_OPENMP_FLAGS
|
||||
"-fopenmp -fopenmp-targets=nvptx64-nvidia-cuda" CACHE STRING
|
||||
"OpenMP compiler flags to use for testing libomptarget-nvptx.")
|
||||
|
||||
# Configure the lit.site.cfg.in file
|
||||
set(AUTO_GEN_COMMENT "## Autogenerated by libomptarget-nvptx configuration.\n# Do not edit!")
|
||||
configure_file(lit.site.cfg.in lit.site.cfg @ONLY)
|
||||
@@ -0,0 +1,38 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const int MaxThreads = 1024;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int cancellation = -1, dynamic = -1, nested = -1, maxActiveLevels = -1;
|
||||
|
||||
#pragma omp target map(cancellation, dynamic, nested, maxActiveLevels)
|
||||
{
|
||||
// libomptarget-nvptx doesn't support cancellation.
|
||||
cancellation = omp_get_cancellation();
|
||||
|
||||
// No support for dynamic adjustment of the number of threads.
|
||||
omp_set_dynamic(1);
|
||||
dynamic = omp_get_dynamic();
|
||||
|
||||
// libomptarget-nvptx doesn't support nested parallelism.
|
||||
omp_set_nested(1);
|
||||
nested = omp_get_nested();
|
||||
|
||||
omp_set_max_active_levels(42);
|
||||
maxActiveLevels = omp_get_max_active_levels();
|
||||
}
|
||||
|
||||
// CHECK: cancellation = 0
|
||||
printf("cancellation = %d\n", cancellation);
|
||||
// CHECK: dynamic = 0
|
||||
printf("dynamic = %d\n", dynamic);
|
||||
// CHECK: nested = 0
|
||||
printf("nested = %d\n", nested);
|
||||
// CHECK: maxActiveLevels = 1
|
||||
printf("maxActiveLevels = %d\n", maxActiveLevels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int MaxThreadsL1 = -1, MaxThreadsL2 = -1;
|
||||
|
||||
#pragma omp declare reduction(unique:int \
|
||||
: omp_out = (omp_in == 1 ? omp_in : omp_out)) \
|
||||
initializer(omp_priv = -1)
|
||||
|
||||
// Non-SPMD mode.
|
||||
#pragma omp target teams map(MaxThreadsL1, MaxThreadsL2) thread_limit(32) \
|
||||
num_teams(1)
|
||||
{
|
||||
MaxThreadsL1 = omp_get_max_threads();
|
||||
#pragma omp parallel reduction(unique : MaxThreadsL2)
|
||||
{ MaxThreadsL2 = omp_get_max_threads(); }
|
||||
}
|
||||
|
||||
// CHECK: Non-SPMD MaxThreadsL1 = 32
|
||||
printf("Non-SPMD MaxThreadsL1 = %d\n", MaxThreadsL1);
|
||||
// CHECK: Non-SPMD MaxThreadsL2 = 1
|
||||
printf("Non-SPMD MaxThreadsL2 = %d\n", MaxThreadsL2);
|
||||
|
||||
// SPMD mode with full runtime
|
||||
MaxThreadsL2 = -1;
|
||||
#pragma omp target parallel reduction(unique : MaxThreadsL2)
|
||||
{ MaxThreadsL2 = omp_get_max_threads(); }
|
||||
|
||||
// CHECK: SPMD with full runtime MaxThreadsL2 = 1
|
||||
printf("SPMD with full runtime MaxThreadsL2 = %d\n", MaxThreadsL2);
|
||||
|
||||
// SPMD mode without runtime
|
||||
MaxThreadsL2 = -1;
|
||||
#pragma omp target parallel for reduction(unique : MaxThreadsL2)
|
||||
for (int I = 0; I < 2; ++I) {
|
||||
MaxThreadsL2 = omp_get_max_threads();
|
||||
}
|
||||
|
||||
// CHECK: SPMD without runtime MaxThreadsL2 = 1
|
||||
printf("SPMD without runtime MaxThreadsL2 = %d\n", MaxThreadsL2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ThreadLimitL0 = -1, ThreadLimitL1 = -1, ThreadLimitL2 = -1;
|
||||
|
||||
#pragma omp declare reduction(unique64:int \
|
||||
: omp_out = (omp_in == 64 ? omp_in : omp_out)) \
|
||||
initializer(omp_priv = -1)
|
||||
#pragma omp declare reduction(unique32:int \
|
||||
: omp_out = (omp_in == 32 ? omp_in : omp_out)) \
|
||||
initializer(omp_priv = -1)
|
||||
|
||||
// Non-SPMD mode.
|
||||
#pragma omp target teams map(ThreadLimitL0, ThreadLimitL1, ThreadLimitL2) \
|
||||
thread_limit(64) num_teams(1)
|
||||
{
|
||||
ThreadLimitL0 = omp_get_thread_limit();
|
||||
#pragma omp parallel reduction(unique64 \
|
||||
: ThreadLimitL1, ThreadLimitL2) num_threads(32)
|
||||
{
|
||||
ThreadLimitL1 = omp_get_thread_limit();
|
||||
#pragma omp parallel reduction(unique64 : ThreadLimitL2)
|
||||
{ ThreadLimitL2 = omp_get_thread_limit(); }
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: Non-SPMD ThreadLimitL0 = 64
|
||||
printf("Non-SPMD ThreadLimitL0 = %d\n", ThreadLimitL0);
|
||||
// CHECK: Non-SPMD ThreadLimitL1 = 64
|
||||
printf("Non-SPMD ThreadLimitL1 = %d\n", ThreadLimitL1);
|
||||
// CHECK: Non-SPMD ThreadLimitL2 = 64
|
||||
printf("Non-SPMD ThreadLimitL2 = %d\n", ThreadLimitL2);
|
||||
|
||||
// SPMD mode with full runtime
|
||||
ThreadLimitL1 = -1;
|
||||
ThreadLimitL2 = -1;
|
||||
#pragma omp target parallel reduction(unique32 \
|
||||
: ThreadLimitL1, ThreadLimitL2) \
|
||||
num_threads(32)
|
||||
{
|
||||
ThreadLimitL1 = omp_get_thread_limit();
|
||||
#pragma omp parallel reduction(unique32 : ThreadLimitL2)
|
||||
{ ThreadLimitL2 = omp_get_thread_limit(); }
|
||||
}
|
||||
|
||||
// CHECK: SPMD with full runtime ThreadLimitL1 = 32
|
||||
printf("SPMD with full runtime ThreadLimitL1 = %d\n", ThreadLimitL1);
|
||||
// CHECK: SPMD with full runtime ThreadLimitL2 = 32
|
||||
printf("SPMD with full runtime ThreadLimitL2 = %d\n", ThreadLimitL2);
|
||||
|
||||
// SPMD mode without runtime
|
||||
ThreadLimitL1 = -1;
|
||||
ThreadLimitL2 = -1;
|
||||
#pragma omp target parallel for reduction(unique32 \
|
||||
: ThreadLimitL1, ThreadLimitL2) \
|
||||
num_threads(32)
|
||||
for (int I = 0; I < 2; ++I) {
|
||||
ThreadLimitL1 = omp_get_thread_limit();
|
||||
#pragma omp parallel reduction(unique32 : ThreadLimitL2)
|
||||
{ ThreadLimitL2 = omp_get_thread_limit(); }
|
||||
}
|
||||
|
||||
// CHECK: SPMD without runtime ThreadLimitL1 = 32
|
||||
printf("SPMD without runtime ThreadLimitL1 = %d\n", ThreadLimitL1);
|
||||
// CHECK: SPMD without runtime ThreadLimitL2 = 32
|
||||
printf("SPMD without runtime ThreadLimitL2 = %d\n", ThreadLimitL2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma omp declare target
|
||||
static void putValueInParallel(int *ptr, int value) {
|
||||
#pragma omp parallel
|
||||
{
|
||||
*ptr = value;
|
||||
}
|
||||
}
|
||||
|
||||
static int getId() {
|
||||
int id;
|
||||
putValueInParallel(&id, omp_get_thread_num());
|
||||
return id;
|
||||
}
|
||||
#pragma omp end declare target
|
||||
|
||||
const int MaxThreads = 1024;
|
||||
const int Threads = 64;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int master;
|
||||
int check[MaxThreads];
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check[i] = 0;
|
||||
}
|
||||
|
||||
#pragma omp target map(master, check[:])
|
||||
{
|
||||
master = getId();
|
||||
|
||||
#pragma omp parallel num_threads(Threads)
|
||||
{
|
||||
check[omp_get_thread_num()] = getId();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: master = 0.
|
||||
printf("master = %d.\n", master);
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
if (i < Threads) {
|
||||
if (check[i] != i) {
|
||||
printf("invalid: check[%d] should be %d, is %d\n", i, i, check[i]);
|
||||
}
|
||||
} else if (check[i] != 0) {
|
||||
printf("invalid: check[%d] should be 0, is %d\n", i, check[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
|
||||
# Configuration file for the 'lit' test runner.
|
||||
|
||||
import os
|
||||
import lit.formats
|
||||
|
||||
# Tell pylint that we know config and lit_config exist somewhere.
|
||||
if 'PYLINT_IMPORT' in os.environ:
|
||||
config = object()
|
||||
lit_config = object()
|
||||
|
||||
def prepend_library_path(name, value, sep):
|
||||
if name in config.environment:
|
||||
config.environment[name] = value + sep + config.environment[name]
|
||||
else:
|
||||
config.environment[name] = value
|
||||
|
||||
# name: The name of this test suite.
|
||||
config.name = 'libomptarget-nvptx'
|
||||
|
||||
# suffixes: A list of file extensions to treat as test files.
|
||||
config.suffixes = ['.c', '.cpp', '.cc']
|
||||
|
||||
# test_source_root: The root path where tests are located.
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
|
||||
# test_exec_root: The root object directory where output is placed
|
||||
config.test_exec_root = config.binary_dir
|
||||
|
||||
# test format
|
||||
config.test_format = lit.formats.ShTest()
|
||||
|
||||
# compiler flags
|
||||
config.test_flags = " -I " + config.omp_header_directory + \
|
||||
" -L " + config.library_dir + \
|
||||
" --libomptarget-nvptx-path=" + config.library_dir;
|
||||
|
||||
if config.omp_host_rtl_directory:
|
||||
config.test_flags = config.test_flags + \
|
||||
" -L " + config.omp_host_rtl_directory
|
||||
|
||||
config.test_flags = config.test_flags + " " + config.test_extra_flags
|
||||
|
||||
# Setup environment to find dynamic library at runtime.
|
||||
prepend_library_path('LD_LIBRARY_PATH', config.library_dir, ":")
|
||||
prepend_library_path('LD_LIBRARY_PATH', config.omp_host_rtl_directory, ":")
|
||||
|
||||
# Forbid fallback to host.
|
||||
config.environment["OMP_TARGET_OFFLOAD"] = "MANDATORY"
|
||||
|
||||
# substitutions
|
||||
config.substitutions.append(("%compilexx-run-and-check",
|
||||
"%compilexx-and-run | " + config.libomptarget_filecheck + " %s"))
|
||||
config.substitutions.append(("%compile-run-and-check",
|
||||
"%compile-and-run | " + config.libomptarget_filecheck + " %s"))
|
||||
config.substitutions.append(("%compilexx-and-run", "%compilexx && %run"))
|
||||
config.substitutions.append(("%compile-and-run", "%compile && %run"))
|
||||
|
||||
config.substitutions.append(("%compilexx",
|
||||
"%clangxx %openmp_flags %flags %s -o %t"))
|
||||
config.substitutions.append(("%compile",
|
||||
"%clang %openmp_flags %flags %s -o %t"))
|
||||
|
||||
config.substitutions.append(("%clangxx", config.test_cxx_compiler))
|
||||
config.substitutions.append(("%clang", config.test_c_compiler))
|
||||
config.substitutions.append(("%openmp_flags", config.test_openmp_flags))
|
||||
config.substitutions.append(("%flags", config.test_flags))
|
||||
|
||||
config.substitutions.append(("%run", "%t"))
|
||||
@@ -0,0 +1,14 @@
|
||||
@AUTO_GEN_COMMENT@
|
||||
|
||||
config.test_c_compiler = "@OPENMP_TEST_C_COMPILER@"
|
||||
config.test_cxx_compiler = "@OPENMP_TEST_CXX_COMPILER@"
|
||||
config.test_openmp_flags = "@LIBOMPTARGET_NVPTX_TEST_OPENMP_FLAGS@"
|
||||
config.test_extra_flags = "@LIBOMPTARGET_NVPTX_TEST_FLAGS@"
|
||||
config.binary_dir = "@CMAKE_CURRENT_BINARY_DIR@"
|
||||
config.library_dir = "@LIBOMPTARGET_LIBRARY_DIR@"
|
||||
config.omp_header_directory = "@LIBOMPTARGET_OPENMP_HEADER_FOLDER@"
|
||||
config.omp_host_rtl_directory = "@LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER@"
|
||||
config.libomptarget_filecheck = "@OPENMP_FILECHECK_EXECUTABLE@"
|
||||
|
||||
# Let the main config do the real work.
|
||||
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
|
||||
@@ -0,0 +1,37 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int data, out, flag = 0;
|
||||
#pragma omp target teams num_teams(2) map(tofrom \
|
||||
: out) map(to \
|
||||
: data, flag) \
|
||||
thread_limit(1)
|
||||
#pragma omp parallel num_threads(1)
|
||||
{
|
||||
if (omp_get_team_num() == 0) {
|
||||
/* Write to the data buffer that will be read by thread in team 1 */
|
||||
data = 42;
|
||||
/* Flush data to thread in team 1 */
|
||||
#pragma omp barrier
|
||||
/* Set flag to release thread in team 1 */
|
||||
#pragma omp atomic write
|
||||
flag = 1;
|
||||
} else if (omp_get_team_num() == 1) {
|
||||
/* Loop until we see the update to the flag */
|
||||
int val;
|
||||
do {
|
||||
#pragma omp atomic read
|
||||
val = flag;
|
||||
} while (val < 1);
|
||||
out = data;
|
||||
#pragma omp barrier
|
||||
}
|
||||
}
|
||||
// CHECK: out=42.
|
||||
/* Value of out will be 42 */
|
||||
printf("out=%d.\n", out);
|
||||
return !(out == 42);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int data, out, flag = 0;
|
||||
#pragma omp target parallel num_threads(64) map(tofrom \
|
||||
: out, flag) map(to \
|
||||
: data)
|
||||
{
|
||||
if (omp_get_thread_num() == 0) {
|
||||
/* Write to the data buffer that will be read by thread */
|
||||
data = 42;
|
||||
/* Flush data to thread 32 */
|
||||
#pragma omp flush(data)
|
||||
/* Set flag to release thread 32 */
|
||||
#pragma omp atomic write
|
||||
flag = 1;
|
||||
} else if (omp_get_thread_num() == 32) {
|
||||
/* Loop until we see the update to the flag */
|
||||
int val;
|
||||
do {
|
||||
#pragma omp atomic read
|
||||
val = flag;
|
||||
} while (val < 1);
|
||||
out = data;
|
||||
#pragma omp flush(out)
|
||||
}
|
||||
}
|
||||
// CHECK: out=42.
|
||||
/* Value of out will be 42 */
|
||||
printf("out=%d.\n", out);
|
||||
return !(out == 42);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const int MaxThreads = 1024;
|
||||
const int NumThreads = 64;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int level = -1, activeLevel = -1;
|
||||
// The expected value is -1, initialize to different value.
|
||||
int ancestorTNumNeg = 1, teamSizeNeg = 1;
|
||||
int ancestorTNum0 = -1, teamSize0 = -1;
|
||||
// The expected value is -1, initialize to different value.
|
||||
int ancestorTNum1 = 1, teamSize1 = 1;
|
||||
int check1[MaxThreads];
|
||||
int check2[MaxThreads];
|
||||
int check3[MaxThreads];
|
||||
int check4[MaxThreads];
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check1[i] = check2[i] = check3[i] = check4[i] = 0;
|
||||
}
|
||||
|
||||
#pragma omp target map(level, activeLevel, ancestorTNumNeg, teamSizeNeg) \
|
||||
map(ancestorTNum0, teamSize0, ancestorTNum1, teamSize1) \
|
||||
map(check1[:], check2[:], check3[:], check4[:])
|
||||
{
|
||||
level = omp_get_level();
|
||||
activeLevel = omp_get_active_level();
|
||||
|
||||
// Expected to return -1.
|
||||
ancestorTNumNeg = omp_get_ancestor_thread_num(-1);
|
||||
teamSizeNeg = omp_get_team_size(-1);
|
||||
|
||||
// Expected to return 0 and 1.
|
||||
ancestorTNum0 = omp_get_ancestor_thread_num(0);
|
||||
teamSize0 = omp_get_team_size(0);
|
||||
|
||||
// Expected to return -1 because the requested level is larger than
|
||||
// the nest level.
|
||||
ancestorTNum1 = omp_get_ancestor_thread_num(1);
|
||||
teamSize1 = omp_get_team_size(1);
|
||||
|
||||
// Expecting active parallel region.
|
||||
#pragma omp parallel num_threads(NumThreads)
|
||||
{
|
||||
int id = omp_get_thread_num();
|
||||
// Multiply return value of omp_get_level by 5 to avoid that this test
|
||||
// passes if both API calls return wrong values.
|
||||
check1[id] += omp_get_level() * 5 + omp_get_active_level();
|
||||
|
||||
// Expected to return 0 and 1.
|
||||
check2[id] += omp_get_ancestor_thread_num(0) + 5 * omp_get_team_size(0);
|
||||
// Expected to return the current thread num.
|
||||
check2[id] += (omp_get_ancestor_thread_num(1) - id);
|
||||
// Exepcted to return the current number of threads.
|
||||
check2[id] += 3 * omp_get_team_size(1);
|
||||
// Expected to return -1, see above.
|
||||
check2[id] += omp_get_ancestor_thread_num(2) + omp_get_team_size(2);
|
||||
|
||||
// Expecting serialized parallel region.
|
||||
#pragma omp parallel
|
||||
{
|
||||
#pragma omp atomic
|
||||
check3[id] += omp_get_level() * 5 + omp_get_active_level();
|
||||
|
||||
// Expected to return 0 and 1.
|
||||
int check4Inc = omp_get_ancestor_thread_num(0) + 5 * omp_get_team_size(0);
|
||||
// Expected to return the parent thread num.
|
||||
check4Inc += (omp_get_ancestor_thread_num(1) - id);
|
||||
// Exepcted to return the number of threads in the active parallel region.
|
||||
check4Inc += 3 * omp_get_team_size(1);
|
||||
// Exptected to return 0 and 1.
|
||||
check4Inc += omp_get_ancestor_thread_num(2) + 3 * omp_get_team_size(2);
|
||||
// Expected to return -1, see above.
|
||||
check4Inc += omp_get_ancestor_thread_num(3) + omp_get_team_size(3);
|
||||
|
||||
#pragma omp atomic
|
||||
check4[id] += check4Inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: target: level = 0, activeLevel = 0
|
||||
printf("target: level = %d, activeLevel = %d\n", level, activeLevel);
|
||||
// CHECK: level = -1: ancestorTNum = -1, teamSize = -1
|
||||
printf("level = -1: ancestorTNum = %d, teamSize = %d\n", ancestorTNumNeg, teamSizeNeg);
|
||||
// CHECK: level = 0: ancestorTNum = 0, teamSize = 1
|
||||
printf("level = 0: ancestorTNum = %d, teamSize = %d\n", ancestorTNum0, teamSize0);
|
||||
// CHECK: level = 1: ancestorTNum = -1, teamSize = -1
|
||||
printf("level = 1: ancestorTNum = %d, teamSize = %d\n", ancestorTNum1, teamSize1);
|
||||
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
// Check active parallel region:
|
||||
// omp_get_level() = 1, omp_get_active_level() = 1
|
||||
const int Expected1 = 6;
|
||||
if (i < NumThreads) {
|
||||
if (check1[i] != Expected1) {
|
||||
printf("invalid: check1[%d] should be %d, is %d\n", i, Expected1, check1[i]);
|
||||
}
|
||||
} else if (check1[i] != 0) {
|
||||
printf("invalid: check1[%d] should be 0, is %d\n", i, check1[i]);
|
||||
}
|
||||
|
||||
// 5 * 1 + 3 * 64 - 1 - 1 (see above)
|
||||
const int Expected2 = 195;
|
||||
if (i < NumThreads) {
|
||||
if (check2[i] != Expected2) {
|
||||
printf("invalid: check2[%d] should be %d, is %d\n", i, Expected2, check2[i]);
|
||||
}
|
||||
} else if (check2[i] != 0) {
|
||||
printf("invalid: check2[%d] should be 0, is %d\n", i, check2[i]);
|
||||
}
|
||||
|
||||
// Check serialized parallel region:
|
||||
// omp_get_level() = 2, omp_get_active_level() = 1
|
||||
const int Expected3 = 11;
|
||||
if (i < NumThreads) {
|
||||
if (check3[i] != Expected3) {
|
||||
printf("invalid: check3[%d] should be %d, is %d\n", i, Expected3, check3[i]);
|
||||
}
|
||||
} else if (check3[i] != 0) {
|
||||
printf("invalid: check3[%d] should be 0, is %d\n", i, check3[i]);
|
||||
}
|
||||
|
||||
// 5 * 1 + 3 * 64 + 3 * 1 - 1 - 1 (see above)
|
||||
const int Expected4 = 198;
|
||||
if (i < NumThreads) {
|
||||
if (check4[i] != Expected4) {
|
||||
printf("invalid: check4[%d] should be %d, is %d\n", i, Expected4, check4[i]);
|
||||
}
|
||||
} else if (check4[i] != 0) {
|
||||
printf("invalid: check4[%d] should be 0, is %d\n", i, check4[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for paraller level in non-SPMD kernels.
|
||||
level = 0;
|
||||
#pragma omp target teams distribute num_teams(1) thread_limit(32) reduction(+:level)
|
||||
for (int i=0; i<5032; i+=32) {
|
||||
int ub = (i+32 > 5032) ? 5032 : i+32;
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
for (int j=i ; j < ub; j++) ;
|
||||
level += omp_get_level();
|
||||
}
|
||||
// CHECK: Integral level = 0.
|
||||
printf("Integral level = %d.\n", level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const int MaxThreads = 1024;
|
||||
const int NumThreads = 64;
|
||||
const int NumThreads1 = 1;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int inParallel = -1, numThreads = -1, threadNum = -1;
|
||||
int check1[MaxThreads];
|
||||
int check2[MaxThreads];
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check1[i] = check2[i] = 0;
|
||||
}
|
||||
|
||||
#pragma omp target map(inParallel, numThreads, threadNum, check1[:], check2[:])
|
||||
{
|
||||
inParallel = omp_in_parallel();
|
||||
numThreads = omp_get_num_threads();
|
||||
threadNum = omp_get_thread_num();
|
||||
|
||||
// Expecting active parallel region.
|
||||
#pragma omp parallel num_threads(NumThreads)
|
||||
{
|
||||
int id = omp_get_thread_num();
|
||||
check1[id] += omp_get_num_threads() + omp_in_parallel();
|
||||
|
||||
// Expecting serialized parallel region.
|
||||
#pragma omp parallel
|
||||
{
|
||||
// Expected to be 1.
|
||||
int nestedInParallel = omp_in_parallel();
|
||||
// Expected to be 1.
|
||||
int nestedNumThreads = omp_get_num_threads();
|
||||
// Expected to be 0.
|
||||
int nestedThreadNum = omp_get_thread_num();
|
||||
#pragma omp atomic
|
||||
check2[id] += nestedInParallel + nestedNumThreads + nestedThreadNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: target: inParallel = 0, numThreads = 1, threadNum = 0
|
||||
printf("target: inParallel = %d, numThreads = %d, threadNum = %d\n",
|
||||
inParallel, numThreads, threadNum);
|
||||
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
// Check that all threads reported
|
||||
// omp_get_num_threads() = 64, omp_in_parallel() = 1.
|
||||
int Expected = NumThreads + 1;
|
||||
if (i < NumThreads) {
|
||||
if (check1[i] != Expected) {
|
||||
printf("invalid: check1[%d] should be %d, is %d\n", i, Expected,
|
||||
check1[i]);
|
||||
}
|
||||
} else if (check1[i] != 0) {
|
||||
printf("invalid: check1[%d] should be 0, is %d\n", i, check1[i]);
|
||||
}
|
||||
|
||||
// Check serialized parallel region.
|
||||
if (i < NumThreads) {
|
||||
if (check2[i] != 2) {
|
||||
printf("invalid: check2[%d] should be 2, is %d\n", i, check2[i]);
|
||||
}
|
||||
} else if (check2[i] != 0) {
|
||||
printf("invalid: check2[%d] should be 0, is %d\n", i, check2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inParallel = -1;
|
||||
numThreads = -1;
|
||||
threadNum = -1;
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check1[i] = check2[i] = 0;
|
||||
}
|
||||
|
||||
#pragma omp target map(inParallel, numThreads, threadNum, check1[:], check2[:])
|
||||
{
|
||||
inParallel = omp_in_parallel();
|
||||
numThreads = omp_get_num_threads();
|
||||
threadNum = omp_get_thread_num();
|
||||
|
||||
// Expecting active parallel region.
|
||||
#pragma omp parallel num_threads(NumThreads1)
|
||||
{
|
||||
int id = omp_get_thread_num();
|
||||
check1[id] += omp_get_num_threads() + omp_in_parallel();
|
||||
|
||||
// Expecting serialized parallel region.
|
||||
#pragma omp parallel
|
||||
{
|
||||
// Expected to be 0.
|
||||
int nestedInParallel = omp_in_parallel();
|
||||
// Expected to be 1.
|
||||
int nestedNumThreads = omp_get_num_threads();
|
||||
// Expected to be 0.
|
||||
int nestedThreadNum = omp_get_thread_num();
|
||||
#pragma omp atomic
|
||||
check2[id] += nestedInParallel + nestedNumThreads + nestedThreadNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: target: inParallel = 0, numThreads = 1, threadNum = 0
|
||||
printf("target: inParallel = %d, numThreads = %d, threadNum = %d\n",
|
||||
inParallel, numThreads, threadNum);
|
||||
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
// Check that all threads reported
|
||||
// omp_get_num_threads() = 1, omp_in_parallel() = 0.
|
||||
int Expected = 1;
|
||||
if (i < NumThreads1) {
|
||||
if (check1[i] != Expected) {
|
||||
printf("invalid: check1[%d] should be %d, is %d\n", i, Expected,
|
||||
check1[i]);
|
||||
}
|
||||
} else if (check1[i] != 0) {
|
||||
printf("invalid: check1[%d] should be 0, is %d\n", i, check1[i]);
|
||||
}
|
||||
|
||||
// Check serialized parallel region.
|
||||
if (i < NumThreads1) {
|
||||
if (check2[i] != 1) {
|
||||
printf("invalid: check2[%d] should be 1, is %d\n", i, check2[i]);
|
||||
}
|
||||
} else if (check2[i] != 0) {
|
||||
printf("invalid: check2[%d] should be 0, is %d\n", i, check2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
const int WarpSize = 32;
|
||||
const int NumThreads1 = 1 * WarpSize;
|
||||
const int NumThreads2 = 2 * WarpSize;
|
||||
const int NumThreads3 = 3 * WarpSize;
|
||||
const int MaxThreads = 1024;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int check1[MaxThreads];
|
||||
int check2[MaxThreads];
|
||||
int check3[MaxThreads];
|
||||
int check4[MaxThreads];
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check1[i] = check2[i] = check3[i] = check4[i] = 0;
|
||||
}
|
||||
|
||||
int maxThreads1 = -1;
|
||||
int maxThreads2 = -1;
|
||||
int maxThreads3 = -1;
|
||||
|
||||
#pragma omp target map(check1[:], check2[:], check3[:], check4[:]) \
|
||||
map(maxThreads1, maxThreads2, maxThreads3)
|
||||
{
|
||||
#pragma omp parallel num_threads(NumThreads1)
|
||||
{
|
||||
check1[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
|
||||
// API method to set number of threads in parallel regions without
|
||||
// num_threads() clause.
|
||||
omp_set_num_threads(NumThreads2);
|
||||
maxThreads1 = omp_get_max_threads();
|
||||
#pragma omp parallel
|
||||
{
|
||||
check2[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
|
||||
maxThreads2 = omp_get_max_threads();
|
||||
|
||||
// num_threads() clause should override nthreads-var ICV.
|
||||
#pragma omp parallel num_threads(NumThreads3)
|
||||
{
|
||||
check3[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
|
||||
maxThreads3 = omp_get_max_threads();
|
||||
|
||||
// Effect from omp_set_num_threads() should still be visible.
|
||||
#pragma omp parallel
|
||||
{
|
||||
check4[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: maxThreads1 = 64
|
||||
printf("maxThreads1 = %d\n", maxThreads1);
|
||||
// CHECK: maxThreads2 = 64
|
||||
printf("maxThreads2 = %d\n", maxThreads2);
|
||||
// CHECK: maxThreads3 = 64
|
||||
printf("maxThreads3 = %d\n", maxThreads3);
|
||||
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
if (i < NumThreads1) {
|
||||
if (check1[i] != NumThreads1) {
|
||||
printf("invalid: check1[%d] should be %d, is %d\n", i, NumThreads1, check1[i]);
|
||||
}
|
||||
} else if (check1[i] != 0) {
|
||||
printf("invalid: check1[%d] should be 0, is %d\n", i, check1[i]);
|
||||
}
|
||||
|
||||
if (i < NumThreads2) {
|
||||
if (check2[i] != NumThreads2) {
|
||||
printf("invalid: check2[%d] should be %d, is %d\n", i, NumThreads2, check2[i]);
|
||||
}
|
||||
} else if (check2[i] != 0) {
|
||||
printf("invalid: check2[%d] should be 0, is %d\n", i, check2[i]);
|
||||
}
|
||||
|
||||
if (i < NumThreads3) {
|
||||
if (check3[i] != NumThreads3) {
|
||||
printf("invalid: check3[%d] should be %d, is %d\n", i, NumThreads3, check3[i]);
|
||||
}
|
||||
} else if (check3[i] != 0) {
|
||||
printf("invalid: check3[%d] should be 0, is %d\n", i, check3[i]);
|
||||
}
|
||||
|
||||
if (i < NumThreads2) {
|
||||
if (check4[i] != NumThreads2) {
|
||||
printf("invalid: check4[%d] should be %d, is %d\n", i, NumThreads2, check4[i]);
|
||||
}
|
||||
} else if (check4[i] != 0) {
|
||||
printf("invalid: check4[%d] should be 0, is %d\n", i, check4[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// RUN: %compilexx-run-and-check
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
int main(void) {
|
||||
int isHost = -1;
|
||||
int ParallelLevel1 = -1, ParallelLevel2 = -1;
|
||||
int Count = 0;
|
||||
|
||||
#pragma omp target parallel for map(tofrom \
|
||||
: isHost, ParallelLevel1, ParallelLevel2), reduction(+: Count) schedule(static, 1)
|
||||
for (int J = 0; J < 10; ++J) {
|
||||
#pragma omp critical
|
||||
{
|
||||
isHost = (isHost < 0 || isHost == 0) ? omp_is_initial_device() : isHost;
|
||||
ParallelLevel1 = (ParallelLevel1 < 0 || ParallelLevel1 == 1)
|
||||
? omp_get_level()
|
||||
: ParallelLevel1;
|
||||
}
|
||||
if (omp_get_thread_num() > 5) {
|
||||
int L2;
|
||||
#pragma omp parallel for schedule(dynamic) lastprivate(L2) reduction(+: Count)
|
||||
for (int I = 0; I < 10; ++I) {
|
||||
L2 = omp_get_level();
|
||||
Count += omp_get_level(); // (10-6)*10*2 = 80
|
||||
}
|
||||
#pragma omp critical
|
||||
ParallelLevel2 =
|
||||
(ParallelLevel2 < 0 || ParallelLevel2 == 2) ? L2 : ParallelLevel2;
|
||||
} else {
|
||||
Count += omp_get_level(); // 6 * 1 = 6
|
||||
}
|
||||
}
|
||||
|
||||
if (isHost < 0) {
|
||||
printf("Runtime error, isHost=%d\n", isHost);
|
||||
}
|
||||
|
||||
// CHECK: Target region executed on the device
|
||||
printf("Target region executed on the %s\n", isHost ? "host" : "device");
|
||||
// CHECK: Parallel level in SPMD mode: L1 is 1, L2 is 2
|
||||
printf("Parallel level in SPMD mode: L1 is %d, L2 is %d\n", ParallelLevel1,
|
||||
ParallelLevel2);
|
||||
// Final result of Count is (10-6)(num of loops)*10(num of iterations)*2(par
|
||||
// level) + 6(num of iterations) * 1(par level)
|
||||
// CHECK: Expected count = 86
|
||||
printf("Expected count = %d\n", Count);
|
||||
|
||||
return isHost;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
const int WarpSize = 32;
|
||||
const int ThreadLimit = 1 * WarpSize;
|
||||
const int NumThreads2 = 2 * WarpSize;
|
||||
const int NumThreads3 = 3 * WarpSize;
|
||||
const int MaxThreads = 1024;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int check1[MaxThreads];
|
||||
int check2[MaxThreads];
|
||||
int check3[MaxThreads];
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
check1[i] = check2[i] = check3[i] = 0;
|
||||
}
|
||||
|
||||
int threadLimit = -1;
|
||||
|
||||
#pragma omp target teams num_teams(1) thread_limit(ThreadLimit) \
|
||||
map(check1[:], check2[:], check3[:], threadLimit)
|
||||
{
|
||||
threadLimit = omp_get_thread_limit();
|
||||
|
||||
// All parallel regions should get as many threads as specified by the
|
||||
// thread_limit() clause.
|
||||
#pragma omp parallel
|
||||
{
|
||||
check1[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
|
||||
omp_set_num_threads(NumThreads2);
|
||||
#pragma omp parallel
|
||||
{
|
||||
check2[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
|
||||
#pragma omp parallel num_threads(NumThreads3)
|
||||
{
|
||||
check3[omp_get_thread_num()] += omp_get_num_threads();
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: threadLimit = 32
|
||||
printf("threadLimit = %d\n", threadLimit);
|
||||
|
||||
// CHECK-NOT: invalid
|
||||
for (int i = 0; i < MaxThreads; i++) {
|
||||
if (i < ThreadLimit) {
|
||||
if (check1[i] != ThreadLimit) {
|
||||
printf("invalid: check1[%d] should be %d, is %d\n", i, ThreadLimit, check1[i]);
|
||||
}
|
||||
} else if (check1[i] != 0) {
|
||||
printf("invalid: check1[%d] should be 0, is %d\n", i, check1[i]);
|
||||
}
|
||||
|
||||
if (i < ThreadLimit) {
|
||||
if (check2[i] != ThreadLimit) {
|
||||
printf("invalid: check2[%d] should be %d, is %d\n", i, ThreadLimit, check2[i]);
|
||||
}
|
||||
} else if (check2[i] != 0) {
|
||||
printf("invalid: check2[%d] should be 0, is %d\n", i, check2[i]);
|
||||
}
|
||||
|
||||
if (i < ThreadLimit) {
|
||||
if (check3[i] != ThreadLimit) {
|
||||
printf("invalid: check3[%d] should be %d, is %d\n", i, ThreadLimit, check3[i]);
|
||||
}
|
||||
} else if (check3[i] != 0) {
|
||||
printf("invalid: check3[%d] should be 0, is %d\n", i, check3[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// RUN: %compile-run-and-check
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
int res = 0;
|
||||
|
||||
#pragma omp parallel num_threads(2) reduction(+:res)
|
||||
{
|
||||
int tid = omp_get_thread_num();
|
||||
#pragma omp target teams distribute reduction(+:res)
|
||||
for (int i = tid; i < 2; i++)
|
||||
++res;
|
||||
}
|
||||
// The first thread makes 2 iterations, the second - 1. Expected result of the
|
||||
// reduction res is 3.
|
||||
|
||||
// CHECK: res = 3.
|
||||
printf("res = %d.\n", res);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-------- omptarget.h - Target independent OpenMP target RTL -- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -48,6 +47,8 @@ enum tgt_map_type {
|
||||
OMP_TGT_MAPTYPE_LITERAL = 0x100,
|
||||
// mapping is implicit
|
||||
OMP_TGT_MAPTYPE_IMPLICIT = 0x200,
|
||||
// copy data to device
|
||||
OMP_TGT_MAPTYPE_CLOSE = 0x400,
|
||||
// member of struct, member given by [16 MSBs] - 1
|
||||
OMP_TGT_MAPTYPE_MEMBER_OF = 0xffff000000000000
|
||||
};
|
||||
@@ -61,6 +62,21 @@ enum OpenMPOffloadingDeclareTargetFlags {
|
||||
OMP_DECLARE_TARGET_DTOR = 0x04
|
||||
};
|
||||
|
||||
enum OpenMPOffloadingRequiresDirFlags {
|
||||
/// flag undefined.
|
||||
OMP_REQ_UNDEFINED = 0x000,
|
||||
/// no requires directive present.
|
||||
OMP_REQ_NONE = 0x001,
|
||||
/// reverse_offload clause.
|
||||
OMP_REQ_REVERSE_OFFLOAD = 0x002,
|
||||
/// unified_address clause.
|
||||
OMP_REQ_UNIFIED_ADDRESS = 0x004,
|
||||
/// unified_shared_memory clause.
|
||||
OMP_REQ_UNIFIED_SHARED_MEMORY = 0x008,
|
||||
/// dynamic_allocators clause.
|
||||
OMP_REQ_DYNAMIC_ALLOCATORS = 0x010
|
||||
};
|
||||
|
||||
/// This struct is a record of an entry point or global. For a function
|
||||
/// entry point the size is expected to be zero
|
||||
struct __tgt_offload_entry {
|
||||
@@ -114,6 +130,9 @@ int omp_target_associate_ptr(void *host_ptr, void *device_ptr, size_t size,
|
||||
size_t device_offset, int device_num);
|
||||
int omp_target_disassociate_ptr(void *host_ptr, int device_num);
|
||||
|
||||
/// add the clauses of the requires directives in a given file
|
||||
void __tgt_register_requires(int64_t flags);
|
||||
|
||||
/// adds a target shared library to the target execution image
|
||||
void __tgt_register_lib(__tgt_bin_desc *desc);
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-- omptargetplugin.h - Target dependent OpenMP Plugin API --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -32,6 +31,9 @@ int32_t __tgt_rtl_number_of_devices(void);
|
||||
// having to load the library, which can be expensive.
|
||||
int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *Image);
|
||||
|
||||
// Initialize the requires flags for the device.
|
||||
int64_t __tgt_rtl_init_requires(int64_t RequiresFlags);
|
||||
|
||||
// Initialize the specified device. In case of success return 0; otherwise
|
||||
// return an error code.
|
||||
int32_t __tgt_rtl_init_device(int32_t ID);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-- elf_common.c - Common ELF functionality -------------------*- C -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
@@ -29,10 +28,6 @@ libomptarget_say("Building CUDA offloading plugin.")
|
||||
# Define the suffix for the runtime messaging dumps.
|
||||
add_definitions(-DTARGET_NAME=CUDA)
|
||||
|
||||
if(LIBOMPTARGET_CMAKE_BUILD_TYPE MATCHES debug)
|
||||
add_definitions(-DCUDA_ERROR_REPORT)
|
||||
endif()
|
||||
|
||||
include_directories(${LIBOMPTARGET_DEP_CUDA_INCLUDE_DIRS})
|
||||
include_directories(${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS})
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===----RTLs/cuda/src/rtl.cpp - Target RTLs Implementation ------- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -35,25 +34,23 @@ static int DebugLevel = 0;
|
||||
DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// Utility for retrieving and printing CUDA error string.
|
||||
#define CUDA_ERR_STRING(err) \
|
||||
do { \
|
||||
if (DebugLevel > 0) { \
|
||||
const char *errStr; \
|
||||
cuGetErrorString(err, &errStr); \
|
||||
DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", "CUDA error is: %s\n", errStr); \
|
||||
} \
|
||||
} while (false)
|
||||
#else // OMPTARGET_DEBUG
|
||||
#define DP(...) {}
|
||||
#define CUDA_ERR_STRING(err) {}
|
||||
#endif // OMPTARGET_DEBUG
|
||||
|
||||
#include "../../common/elf_common.c"
|
||||
|
||||
// Utility for retrieving and printing CUDA error string.
|
||||
#ifdef CUDA_ERROR_REPORT
|
||||
#define CUDA_ERR_STRING(err) \
|
||||
do { \
|
||||
const char *errStr; \
|
||||
cuGetErrorString(err, &errStr); \
|
||||
DP("CUDA error is: %s\n", errStr); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CUDA_ERR_STRING(err) \
|
||||
{}
|
||||
#endif
|
||||
|
||||
/// Keep entries table per device.
|
||||
struct FuncOrGblEntryTy {
|
||||
__tgt_target_table Table;
|
||||
@@ -112,6 +109,9 @@ public:
|
||||
int EnvNumTeams;
|
||||
int EnvTeamLimit;
|
||||
|
||||
// OpenMP Requires Flags
|
||||
int64_t RequiresFlags;
|
||||
|
||||
//static int EnvNumThreads;
|
||||
static const int HardTeamLimit = 1<<16; // 64k
|
||||
static const int HardThreadLimit = 1024;
|
||||
@@ -228,6 +228,9 @@ public:
|
||||
} else {
|
||||
EnvNumTeams = -1;
|
||||
}
|
||||
|
||||
// Default state.
|
||||
RequiresFlags = OMP_REQ_UNDEFINED;
|
||||
}
|
||||
|
||||
~RTLDeviceInfoTy() {
|
||||
@@ -265,6 +268,12 @@ int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) {
|
||||
|
||||
int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; }
|
||||
|
||||
int64_t __tgt_rtl_init_requires(int64_t RequiresFlags) {
|
||||
DP("Init requires flags to %ld\n", RequiresFlags);
|
||||
DeviceInfo.RequiresFlags = RequiresFlags;
|
||||
return RequiresFlags;
|
||||
}
|
||||
|
||||
int32_t __tgt_rtl_init_device(int32_t device_id) {
|
||||
|
||||
CUdevice cuDevice;
|
||||
@@ -285,43 +294,48 @@ int32_t __tgt_rtl_init_device(int32_t device_id) {
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
// scan properties to determine number of threads/block and blocks/grid.
|
||||
CUdevprop Properties;
|
||||
err = cuDeviceGetProperties(&Properties, cuDevice);
|
||||
// Query attributes to determine number of threads/block and blocks/grid.
|
||||
int maxGridDimX;
|
||||
err = cuDeviceGetAttribute(&maxGridDimX, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X,
|
||||
cuDevice);
|
||||
if (err != CUDA_SUCCESS) {
|
||||
DP("Error getting device Properties, use defaults\n");
|
||||
DP("Error getting max grid dimension, use default\n");
|
||||
DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams;
|
||||
} else if (maxGridDimX <= RTLDeviceInfoTy::HardTeamLimit) {
|
||||
DeviceInfo.BlocksPerGrid[device_id] = maxGridDimX;
|
||||
DP("Using %d CUDA blocks per grid\n", maxGridDimX);
|
||||
} else {
|
||||
DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit;
|
||||
DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping "
|
||||
"at the hard limit\n",
|
||||
maxGridDimX, RTLDeviceInfoTy::HardTeamLimit);
|
||||
}
|
||||
|
||||
// We are only exploiting threads along the x axis.
|
||||
int maxBlockDimX;
|
||||
err = cuDeviceGetAttribute(&maxBlockDimX, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X,
|
||||
cuDevice);
|
||||
if (err != CUDA_SUCCESS) {
|
||||
DP("Error getting max block dimension, use default\n");
|
||||
DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads;
|
||||
} else if (maxBlockDimX <= RTLDeviceInfoTy::HardThreadLimit) {
|
||||
DeviceInfo.ThreadsPerBlock[device_id] = maxBlockDimX;
|
||||
DP("Using %d CUDA threads per block\n", maxBlockDimX);
|
||||
} else {
|
||||
DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit;
|
||||
DP("Max CUDA threads per block %d exceeds the hard thread limit %d, capping"
|
||||
"at the hard limit\n",
|
||||
maxBlockDimX, RTLDeviceInfoTy::HardThreadLimit);
|
||||
}
|
||||
|
||||
int warpSize;
|
||||
err =
|
||||
cuDeviceGetAttribute(&warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, cuDevice);
|
||||
if (err != CUDA_SUCCESS) {
|
||||
DP("Error getting warp size, assume default\n");
|
||||
DeviceInfo.WarpSize[device_id] = 32;
|
||||
} else {
|
||||
// Get blocks per grid
|
||||
if (Properties.maxGridSize[0] <= RTLDeviceInfoTy::HardTeamLimit) {
|
||||
DeviceInfo.BlocksPerGrid[device_id] = Properties.maxGridSize[0];
|
||||
DP("Using %d CUDA blocks per grid\n", Properties.maxGridSize[0]);
|
||||
} else {
|
||||
DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit;
|
||||
DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping "
|
||||
"at the hard limit\n", Properties.maxGridSize[0],
|
||||
RTLDeviceInfoTy::HardTeamLimit);
|
||||
}
|
||||
|
||||
// Get threads per block, exploit threads only along x axis
|
||||
if (Properties.maxThreadsDim[0] <= RTLDeviceInfoTy::HardThreadLimit) {
|
||||
DeviceInfo.ThreadsPerBlock[device_id] = Properties.maxThreadsDim[0];
|
||||
DP("Using %d CUDA threads per block\n", Properties.maxThreadsDim[0]);
|
||||
if (Properties.maxThreadsDim[0] < Properties.maxThreadsPerBlock) {
|
||||
DP("(fewer than max per block along all xyz dims %d)\n",
|
||||
Properties.maxThreadsPerBlock);
|
||||
}
|
||||
} else {
|
||||
DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit;
|
||||
DP("Max CUDA threads per block %d exceeds the hard thread limit %d, "
|
||||
"capping at the hard limit\n", Properties.maxThreadsDim[0],
|
||||
RTLDeviceInfoTy::HardThreadLimit);
|
||||
}
|
||||
|
||||
// According to the documentation, SIMDWidth is "Warp size in threads".
|
||||
DeviceInfo.WarpSize[device_id] = Properties.SIMDWidth;
|
||||
DeviceInfo.WarpSize[device_id] = warpSize;
|
||||
}
|
||||
|
||||
// Adjust teams to the env variables
|
||||
@@ -432,6 +446,26 @@ __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id,
|
||||
DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr));
|
||||
entry.addr = (void *)cuptr;
|
||||
|
||||
// Note: In the current implementation declare target variables
|
||||
// can either be link or to. This means that once unified
|
||||
// memory is activated via the requires directive, the variable
|
||||
// can be used directly from the host in both cases.
|
||||
// TODO: when variables types other than to or link are added,
|
||||
// the below condition should be changed to explicitely
|
||||
// check for to and link variables types:
|
||||
// (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY &&
|
||||
// (e->flags & OMP_DECLARE_TARGET_LINK ||
|
||||
// e->flags == OMP_DECLARE_TARGET_TO))
|
||||
if (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) {
|
||||
// If unified memory is present any target link or to variables
|
||||
// can access host addresses directly. There is no longer a
|
||||
// need for device copies.
|
||||
cuMemcpyHtoD(cuptr, e->addr, sizeof(void *));
|
||||
DP("Copy linked variable host address (" DPxMOD ")"
|
||||
"to device address (" DPxMOD ")\n",
|
||||
DPxPTR(*((void**)e->addr)), DPxPTR(cuptr));
|
||||
}
|
||||
|
||||
DeviceInfo.addOffloadEntry(device_id, entry);
|
||||
|
||||
continue;
|
||||
|
||||
@@ -2,6 +2,7 @@ VERS1.0 {
|
||||
global:
|
||||
__tgt_rtl_is_valid_binary;
|
||||
__tgt_rtl_number_of_devices;
|
||||
__tgt_rtl_init_requires;
|
||||
__tgt_rtl_init_device;
|
||||
__tgt_rtl_load_binary;
|
||||
__tgt_rtl_data_alloc;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===-RTLs/generic-64bit/src/rtl.cpp - Target RTLs Implementation - C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -51,7 +50,7 @@ static int DebugLevel = 0;
|
||||
#include "../../common/elf_common.c"
|
||||
|
||||
#define NUMBER_OF_DEVICES 4
|
||||
#define OFFLOADSECTIONNAME ".omp_offloading.entries"
|
||||
#define OFFLOADSECTIONNAME "omp_offloading_entries"
|
||||
|
||||
/// Array of Dynamic libraries loaded for this target.
|
||||
struct DynLibTy {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.txt for details.
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
@@ -28,4 +27,5 @@ target_link_libraries(omptarget
|
||||
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/exports")
|
||||
|
||||
# Install libomptarget under the lib destination folder.
|
||||
install(TARGETS omptarget LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
|
||||
install(TARGETS omptarget LIBRARY COMPONENT omptarget
|
||||
DESTINATION "${OPENMP_INSTALL_LIBDIR}")
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===----------- api.cpp - Target independent OpenMP target RTL -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -114,7 +113,15 @@ EXTERN int omp_target_is_present(void *ptr, int device_num) {
|
||||
|
||||
DeviceTy& Device = Devices[device_num];
|
||||
bool IsLast; // not used
|
||||
int rc = (Device.getTgtPtrBegin(ptr, 0, IsLast, false) != NULL);
|
||||
bool IsHostPtr;
|
||||
void *TgtPtr = Device.getTgtPtrBegin(ptr, 0, IsLast, false, IsHostPtr);
|
||||
int rc = (TgtPtr != NULL);
|
||||
// Under unified memory the host pointer can be returned by the
|
||||
// getTgtPtrBegin() function which means that there is no device
|
||||
// corresponding point for ptr. This function should return false
|
||||
// in that situation.
|
||||
if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY)
|
||||
rc = !IsHostPtr;
|
||||
DP("Call to omp_target_is_present returns %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+50
-19
@@ -1,9 +1,8 @@
|
||||
//===--------- device.cpp - Target independent OpenMP target RTL ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -153,17 +152,22 @@ LookupResult DeviceTy::lookupMapping(void *HstPtrBegin, int64_t Size) {
|
||||
|
||||
// Used by target_data_begin
|
||||
// Return the target pointer begin (where the data will be moved).
|
||||
// Allocate memory if this is the first occurrence if this mapping.
|
||||
// Allocate memory if this is the first occurrence of this mapping.
|
||||
// Increment the reference counter.
|
||||
// If NULL is returned, then either data allocation failed or the user tried
|
||||
// to do an illegal mapping.
|
||||
void *DeviceTy::getOrAllocTgtPtr(void *HstPtrBegin, void *HstPtrBase,
|
||||
int64_t Size, bool &IsNew, bool IsImplicit, bool UpdateRefCount) {
|
||||
int64_t Size, bool &IsNew, bool &IsHostPtr, bool IsImplicit,
|
||||
bool UpdateRefCount, bool HasCloseModifier) {
|
||||
void *rc = NULL;
|
||||
IsHostPtr = false;
|
||||
DataMapMtx.lock();
|
||||
LookupResult lr = lookupMapping(HstPtrBegin, Size);
|
||||
|
||||
// Check if the pointer is contained.
|
||||
// If a variable is mapped to the device manually by the user - which would
|
||||
// lead to the IsContained flag to be true - then we must ensure that the
|
||||
// device address is returned even under unified memory conditions.
|
||||
if (lr.Flags.IsContained ||
|
||||
((lr.Flags.ExtendsBefore || lr.Flags.ExtendsAfter) && IsImplicit)) {
|
||||
auto &HT = *lr.Entry;
|
||||
@@ -184,15 +188,28 @@ void *DeviceTy::getOrAllocTgtPtr(void *HstPtrBegin, void *HstPtrBase,
|
||||
// Explicit extension of mapped data - not allowed.
|
||||
DP("Explicit extension of mapping is not allowed.\n");
|
||||
} else if (Size) {
|
||||
// If it is not contained and Size > 0 we should create a new entry for it.
|
||||
IsNew = true;
|
||||
uintptr_t tp = (uintptr_t)RTL->data_alloc(RTLDeviceID, Size, HstPtrBegin);
|
||||
DP("Creating new map entry: HstBase=" DPxMOD ", HstBegin=" DPxMOD ", "
|
||||
"HstEnd=" DPxMOD ", TgtBegin=" DPxMOD "\n", DPxPTR(HstPtrBase),
|
||||
DPxPTR(HstPtrBegin), DPxPTR((uintptr_t)HstPtrBegin + Size), DPxPTR(tp));
|
||||
HostDataToTargetMap.push_front(HostDataToTargetTy((uintptr_t)HstPtrBase,
|
||||
(uintptr_t)HstPtrBegin, (uintptr_t)HstPtrBegin + Size, tp));
|
||||
rc = (void *)tp;
|
||||
// If unified shared memory is active, implicitly mapped variables that are not
|
||||
// privatized use host address. Any explicitly mapped variables also use
|
||||
// host address where correctness is not impeded. In all other cases
|
||||
// maps are respected.
|
||||
// In addition to the mapping rules above, the close map
|
||||
// modifier forces the mapping of the variable to the device.
|
||||
if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY && !HasCloseModifier) {
|
||||
DP("Return HstPtrBegin " DPxMOD " Size=%ld RefCount=%s\n",
|
||||
DPxPTR((uintptr_t)HstPtrBegin), Size, (UpdateRefCount ? " updated" : ""));
|
||||
IsHostPtr = true;
|
||||
rc = HstPtrBegin;
|
||||
} else {
|
||||
// If it is not contained and Size > 0 we should create a new entry for it.
|
||||
IsNew = true;
|
||||
uintptr_t tp = (uintptr_t)RTL->data_alloc(RTLDeviceID, Size, HstPtrBegin);
|
||||
DP("Creating new map entry: HstBase=" DPxMOD ", HstBegin=" DPxMOD ", "
|
||||
"HstEnd=" DPxMOD ", TgtBegin=" DPxMOD "\n", DPxPTR(HstPtrBase),
|
||||
DPxPTR(HstPtrBegin), DPxPTR((uintptr_t)HstPtrBegin + Size), DPxPTR(tp));
|
||||
HostDataToTargetMap.push_front(HostDataToTargetTy((uintptr_t)HstPtrBase,
|
||||
(uintptr_t)HstPtrBegin, (uintptr_t)HstPtrBegin + Size, tp));
|
||||
rc = (void *)tp;
|
||||
}
|
||||
}
|
||||
|
||||
DataMapMtx.unlock();
|
||||
@@ -203,8 +220,10 @@ void *DeviceTy::getOrAllocTgtPtr(void *HstPtrBegin, void *HstPtrBase,
|
||||
// Return the target pointer begin (where the data will be moved).
|
||||
// Decrement the reference counter if called from target_data_end.
|
||||
void *DeviceTy::getTgtPtrBegin(void *HstPtrBegin, int64_t Size, bool &IsLast,
|
||||
bool UpdateRefCount) {
|
||||
bool UpdateRefCount, bool &IsHostPtr) {
|
||||
void *rc = NULL;
|
||||
IsHostPtr = false;
|
||||
IsLast = false;
|
||||
DataMapMtx.lock();
|
||||
LookupResult lr = lookupMapping(HstPtrBegin, Size);
|
||||
|
||||
@@ -222,8 +241,14 @@ void *DeviceTy::getTgtPtrBegin(void *HstPtrBegin, int64_t Size, bool &IsLast,
|
||||
(CONSIDERED_INF(HT.RefCount)) ? "INF" :
|
||||
std::to_string(HT.RefCount).c_str());
|
||||
rc = (void *)tp;
|
||||
} else {
|
||||
IsLast = false;
|
||||
} else if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) {
|
||||
// If the value isn't found in the mapping and unified shared memory
|
||||
// is on then it means we have stumbled upon a value which we need to
|
||||
// use directly from the host.
|
||||
DP("Get HstPtrBegin " DPxMOD " Size=%ld RefCount=%s\n",
|
||||
DPxPTR((uintptr_t)HstPtrBegin), Size, (UpdateRefCount ? " updated" : ""));
|
||||
IsHostPtr = true;
|
||||
rc = HstPtrBegin;
|
||||
}
|
||||
|
||||
DataMapMtx.unlock();
|
||||
@@ -244,7 +269,10 @@ void *DeviceTy::getTgtPtrBegin(void *HstPtrBegin, int64_t Size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int DeviceTy::deallocTgtPtr(void *HstPtrBegin, int64_t Size, bool ForceDelete) {
|
||||
int DeviceTy::deallocTgtPtr(void *HstPtrBegin, int64_t Size, bool ForceDelete,
|
||||
bool HasCloseModifier) {
|
||||
if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY && !HasCloseModifier)
|
||||
return OFFLOAD_SUCCESS;
|
||||
// Check if the pointer is contained in any sub-nodes.
|
||||
int rc;
|
||||
DataMapMtx.lock();
|
||||
@@ -276,6 +304,9 @@ int DeviceTy::deallocTgtPtr(void *HstPtrBegin, int64_t Size, bool ForceDelete) {
|
||||
|
||||
/// Init device, should not be called directly.
|
||||
void DeviceTy::init() {
|
||||
// Make call to init_requires if it exists for this plugin.
|
||||
if (RTL->init_requires)
|
||||
RTL->init_requires(RTLs.RequiresFlags);
|
||||
int32_t rc = RTL->init_device(RTLDeviceID);
|
||||
if (rc == OFFLOAD_SUCCESS) {
|
||||
IsInit = true;
|
||||
|
||||
+16
-14
@@ -1,9 +1,8 @@
|
||||
//===----------- device.h - Target independent OpenMP target RTL ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -97,13 +96,14 @@ struct DeviceTy {
|
||||
|
||||
std::mutex DataMapMtx, PendingGlobalsMtx, ShadowMtx;
|
||||
|
||||
uint64_t loopTripCnt;
|
||||
// NOTE: Once libomp gains full target-task support, this state should be
|
||||
// moved into the target task in libomp.
|
||||
std::map<int32_t, uint64_t> LoopTripCnt;
|
||||
|
||||
DeviceTy(RTLInfoTy *RTL)
|
||||
: DeviceID(-1), RTL(RTL), RTLDeviceID(-1), IsInit(false), InitFlag(),
|
||||
HasPendingGlobals(false), HostDataToTargetMap(),
|
||||
PendingCtorsDtors(), ShadowPtrMap(), DataMapMtx(), PendingGlobalsMtx(),
|
||||
ShadowMtx(), loopTripCnt(0) {}
|
||||
HasPendingGlobals(false), HostDataToTargetMap(), PendingCtorsDtors(),
|
||||
ShadowPtrMap(), DataMapMtx(), PendingGlobalsMtx(), ShadowMtx() {}
|
||||
|
||||
// The existence of mutexes makes DeviceTy non-copyable. We need to
|
||||
// provide a copy constructor and an assignment operator explicitly.
|
||||
@@ -112,8 +112,8 @@ struct DeviceTy {
|
||||
IsInit(d.IsInit), InitFlag(), HasPendingGlobals(d.HasPendingGlobals),
|
||||
HostDataToTargetMap(d.HostDataToTargetMap),
|
||||
PendingCtorsDtors(d.PendingCtorsDtors), ShadowPtrMap(d.ShadowPtrMap),
|
||||
DataMapMtx(), PendingGlobalsMtx(),
|
||||
ShadowMtx(), loopTripCnt(d.loopTripCnt) {}
|
||||
DataMapMtx(), PendingGlobalsMtx(), ShadowMtx(),
|
||||
LoopTripCnt(d.LoopTripCnt) {}
|
||||
|
||||
DeviceTy& operator=(const DeviceTy &d) {
|
||||
DeviceID = d.DeviceID;
|
||||
@@ -124,7 +124,7 @@ struct DeviceTy {
|
||||
HostDataToTargetMap = d.HostDataToTargetMap;
|
||||
PendingCtorsDtors = d.PendingCtorsDtors;
|
||||
ShadowPtrMap = d.ShadowPtrMap;
|
||||
loopTripCnt = d.loopTripCnt;
|
||||
LoopTripCnt = d.LoopTripCnt;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -132,11 +132,13 @@ struct DeviceTy {
|
||||
long getMapEntryRefCnt(void *HstPtrBegin);
|
||||
LookupResult lookupMapping(void *HstPtrBegin, int64_t Size);
|
||||
void *getOrAllocTgtPtr(void *HstPtrBegin, void *HstPtrBase, int64_t Size,
|
||||
bool &IsNew, bool IsImplicit, bool UpdateRefCount = true);
|
||||
bool &IsNew, bool &IsHostPtr, bool IsImplicit, bool UpdateRefCount = true,
|
||||
bool HasCloseModifier = false);
|
||||
void *getTgtPtrBegin(void *HstPtrBegin, int64_t Size);
|
||||
void *getTgtPtrBegin(void *HstPtrBegin, int64_t Size, bool &IsLast,
|
||||
bool UpdateRefCount);
|
||||
int deallocTgtPtr(void *TgtPtrBegin, int64_t Size, bool ForceDelete);
|
||||
bool UpdateRefCount, bool &IsHostPtr);
|
||||
int deallocTgtPtr(void *TgtPtrBegin, int64_t Size, bool ForceDelete,
|
||||
bool HasCloseModifier = false);
|
||||
int associatePtr(void *HstPtrBegin, void *TgtPtrBegin, int64_t Size);
|
||||
int disassociatePtr(void *HstPtrBegin);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
VERS1.0 {
|
||||
global:
|
||||
__tgt_register_requires;
|
||||
__tgt_register_lib;
|
||||
__tgt_unregister_lib;
|
||||
__tgt_target_data_begin;
|
||||
@@ -12,6 +13,8 @@ VERS1.0 {
|
||||
__tgt_target_data_update_nowait;
|
||||
__tgt_target_nowait;
|
||||
__tgt_target_teams_nowait;
|
||||
__tgt_mapper_num_components;
|
||||
__tgt_push_mapper_component;
|
||||
omp_get_num_devices;
|
||||
omp_get_initial_device;
|
||||
omp_target_alloc;
|
||||
|
||||
+114
-15
@@ -1,9 +1,8 @@
|
||||
//===-------- interface.cpp - Target independent OpenMP target RTL --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -20,6 +19,60 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
|
||||
// Store target policy (disabled, mandatory, default)
|
||||
kmp_target_offload_kind_t TargetOffloadPolicy = tgt_default;
|
||||
std::mutex TargetOffloadMtx;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// manage the success or failure of a target constuct
|
||||
|
||||
static void HandleDefaultTargetOffload() {
|
||||
TargetOffloadMtx.lock();
|
||||
if (TargetOffloadPolicy == tgt_default) {
|
||||
if (omp_get_num_devices() > 0) {
|
||||
DP("Default TARGET OFFLOAD policy is now mandatory "
|
||||
"(devices were found)\n");
|
||||
TargetOffloadPolicy = tgt_mandatory;
|
||||
} else {
|
||||
DP("Default TARGET OFFLOAD policy is now disabled "
|
||||
"(no devices were found)\n");
|
||||
TargetOffloadPolicy = tgt_disabled;
|
||||
}
|
||||
}
|
||||
TargetOffloadMtx.unlock();
|
||||
}
|
||||
|
||||
static int IsOffloadDisabled() {
|
||||
if (TargetOffloadPolicy == tgt_default) HandleDefaultTargetOffload();
|
||||
return TargetOffloadPolicy == tgt_disabled;
|
||||
}
|
||||
|
||||
static void HandleTargetOutcome(bool success) {
|
||||
switch (TargetOffloadPolicy) {
|
||||
case tgt_disabled:
|
||||
if (success) {
|
||||
FATAL_MESSAGE0(1, "expected no offloading while offloading is disabled");
|
||||
}
|
||||
break;
|
||||
case tgt_default:
|
||||
FATAL_MESSAGE0(1, "default offloading policy must be switched to "
|
||||
"mandatory or disabled");
|
||||
break;
|
||||
case tgt_mandatory:
|
||||
if (!success) {
|
||||
FATAL_MESSAGE0(1, "failure of target construct while offloading is mandatory");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// adds requires flags
|
||||
EXTERN void __tgt_register_requires(int64_t flags) {
|
||||
RTLs.RegisterRequires(flags);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// adds a target shared library to the target execution image
|
||||
@@ -38,6 +91,8 @@ EXTERN void __tgt_unregister_lib(__tgt_bin_desc *desc) {
|
||||
/// and passes the data to the device.
|
||||
EXTERN void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
if (IsOffloadDisabled()) return;
|
||||
|
||||
DP("Entering data begin region for device %" PRId64 " with %d mappings\n",
|
||||
device_id, arg_num);
|
||||
|
||||
@@ -49,6 +104,7 @@ EXTERN void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
|
||||
|
||||
if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
|
||||
DP("Failed to get device %" PRId64 " ready\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,7 +118,9 @@ EXTERN void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
|
||||
}
|
||||
#endif
|
||||
|
||||
target_data_begin(Device, arg_num, args_base, args, arg_sizes, arg_types);
|
||||
int rc = target_data_begin(Device, arg_num, args_base,
|
||||
args, arg_sizes, arg_types);
|
||||
HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
|
||||
}
|
||||
|
||||
EXTERN void __tgt_target_data_begin_nowait(int64_t device_id, int32_t arg_num,
|
||||
@@ -70,7 +128,7 @@ EXTERN void __tgt_target_data_begin_nowait(int64_t device_id, int32_t arg_num,
|
||||
int32_t depNum, void *depList, int32_t noAliasDepNum,
|
||||
void *noAliasDepList) {
|
||||
if (depNum + noAliasDepNum > 0)
|
||||
__kmpc_omp_taskwait(NULL, 0);
|
||||
__kmpc_omp_taskwait(NULL, __kmpc_global_thread_num(NULL));
|
||||
|
||||
__tgt_target_data_begin(device_id, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
@@ -81,6 +139,7 @@ EXTERN void __tgt_target_data_begin_nowait(int64_t device_id, int32_t arg_num,
|
||||
/// created by the last __tgt_target_data_begin.
|
||||
EXTERN void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
if (IsOffloadDisabled()) return;
|
||||
DP("Entering data end region with %d mappings\n", arg_num);
|
||||
|
||||
// No devices available?
|
||||
@@ -93,12 +152,14 @@ EXTERN void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
|
||||
RTLsMtx.unlock();
|
||||
if (Devices_size <= (size_t)device_id) {
|
||||
DP("Device ID %" PRId64 " does not have a matching RTL.\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceTy &Device = Devices[device_id];
|
||||
if (!Device.IsInit) {
|
||||
DP("Uninit device: ignore");
|
||||
HandleTargetOutcome(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,7 +171,9 @@ EXTERN void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
|
||||
}
|
||||
#endif
|
||||
|
||||
target_data_end(Device, arg_num, args_base, args, arg_sizes, arg_types);
|
||||
int rc = target_data_end(Device, arg_num, args_base,
|
||||
args, arg_sizes, arg_types);
|
||||
HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
|
||||
}
|
||||
|
||||
EXTERN void __tgt_target_data_end_nowait(int64_t device_id, int32_t arg_num,
|
||||
@@ -118,7 +181,7 @@ EXTERN void __tgt_target_data_end_nowait(int64_t device_id, int32_t arg_num,
|
||||
int32_t depNum, void *depList, int32_t noAliasDepNum,
|
||||
void *noAliasDepList) {
|
||||
if (depNum + noAliasDepNum > 0)
|
||||
__kmpc_omp_taskwait(NULL, 0);
|
||||
__kmpc_omp_taskwait(NULL, __kmpc_global_thread_num(NULL));
|
||||
|
||||
__tgt_target_data_end(device_id, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
@@ -126,6 +189,7 @@ EXTERN void __tgt_target_data_end_nowait(int64_t device_id, int32_t arg_num,
|
||||
|
||||
EXTERN void __tgt_target_data_update(int64_t device_id, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
if (IsOffloadDisabled()) return;
|
||||
DP("Entering data update with %d mappings\n", arg_num);
|
||||
|
||||
// No devices available?
|
||||
@@ -135,11 +199,14 @@ EXTERN void __tgt_target_data_update(int64_t device_id, int32_t arg_num,
|
||||
|
||||
if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
|
||||
DP("Failed to get device %" PRId64 " ready\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceTy& Device = Devices[device_id];
|
||||
target_data_update(Device, arg_num, args_base, args, arg_sizes, arg_types);
|
||||
int rc = target_data_update(Device, arg_num, args_base,
|
||||
args, arg_sizes, arg_types);
|
||||
HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
|
||||
}
|
||||
|
||||
EXTERN void __tgt_target_data_update_nowait(
|
||||
@@ -147,7 +214,7 @@ EXTERN void __tgt_target_data_update_nowait(
|
||||
int64_t *arg_sizes, int64_t *arg_types, int32_t depNum, void *depList,
|
||||
int32_t noAliasDepNum, void *noAliasDepList) {
|
||||
if (depNum + noAliasDepNum > 0)
|
||||
__kmpc_omp_taskwait(NULL, 0);
|
||||
__kmpc_omp_taskwait(NULL, __kmpc_global_thread_num(NULL));
|
||||
|
||||
__tgt_target_data_update(device_id, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
@@ -155,6 +222,7 @@ EXTERN void __tgt_target_data_update_nowait(
|
||||
|
||||
EXTERN int __tgt_target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
if (IsOffloadDisabled()) return OFFLOAD_FAIL;
|
||||
DP("Entering target region with entry point " DPxMOD " and device Id %"
|
||||
PRId64 "\n", DPxPTR(host_ptr), device_id);
|
||||
|
||||
@@ -164,6 +232,7 @@ EXTERN int __tgt_target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
|
||||
if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
|
||||
DP("Failed to get device %" PRId64 " ready\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
@@ -177,7 +246,7 @@ EXTERN int __tgt_target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
|
||||
int rc = target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
|
||||
arg_types, 0, 0, false /*team*/);
|
||||
|
||||
HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -186,7 +255,7 @@ EXTERN int __tgt_target_nowait(int64_t device_id, void *host_ptr,
|
||||
int64_t *arg_types, int32_t depNum, void *depList, int32_t noAliasDepNum,
|
||||
void *noAliasDepList) {
|
||||
if (depNum + noAliasDepNum > 0)
|
||||
__kmpc_omp_taskwait(NULL, 0);
|
||||
__kmpc_omp_taskwait(NULL, __kmpc_global_thread_num(NULL));
|
||||
|
||||
return __tgt_target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
@@ -195,6 +264,7 @@ EXTERN int __tgt_target_nowait(int64_t device_id, void *host_ptr,
|
||||
EXTERN int __tgt_target_teams(int64_t device_id, void *host_ptr,
|
||||
int32_t arg_num, void **args_base, void **args, int64_t *arg_sizes,
|
||||
int64_t *arg_types, int32_t team_num, int32_t thread_limit) {
|
||||
if (IsOffloadDisabled()) return OFFLOAD_FAIL;
|
||||
DP("Entering target region with entry point " DPxMOD " and device Id %"
|
||||
PRId64 "\n", DPxPTR(host_ptr), device_id);
|
||||
|
||||
@@ -204,6 +274,7 @@ EXTERN int __tgt_target_teams(int64_t device_id, void *host_ptr,
|
||||
|
||||
if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
|
||||
DP("Failed to get device %" PRId64 " ready\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
@@ -217,6 +288,7 @@ EXTERN int __tgt_target_teams(int64_t device_id, void *host_ptr,
|
||||
|
||||
int rc = target(device_id, host_ptr, arg_num, args_base, args, arg_sizes,
|
||||
arg_types, team_num, thread_limit, true /*team*/);
|
||||
HandleTargetOutcome(rc == OFFLOAD_SUCCESS);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -226,26 +298,53 @@ EXTERN int __tgt_target_teams_nowait(int64_t device_id, void *host_ptr,
|
||||
int64_t *arg_types, int32_t team_num, int32_t thread_limit, int32_t depNum,
|
||||
void *depList, int32_t noAliasDepNum, void *noAliasDepList) {
|
||||
if (depNum + noAliasDepNum > 0)
|
||||
__kmpc_omp_taskwait(NULL, 0);
|
||||
__kmpc_omp_taskwait(NULL, __kmpc_global_thread_num(NULL));
|
||||
|
||||
return __tgt_target_teams(device_id, host_ptr, arg_num, args_base, args,
|
||||
arg_sizes, arg_types, team_num, thread_limit);
|
||||
}
|
||||
|
||||
// Get the current number of components for a user-defined mapper.
|
||||
EXTERN int64_t __tgt_mapper_num_components(void *rt_mapper_handle) {
|
||||
auto *MapperComponentsPtr = (struct MapperComponentsTy *)rt_mapper_handle;
|
||||
int64_t size = MapperComponentsPtr->Components.size();
|
||||
DP("__tgt_mapper_num_components(Handle=" DPxMOD ") returns %" PRId64 "\n",
|
||||
DPxPTR(rt_mapper_handle), size);
|
||||
return size;
|
||||
}
|
||||
|
||||
// Push back one component for a user-defined mapper.
|
||||
EXTERN void __tgt_push_mapper_component(void *rt_mapper_handle, void *base,
|
||||
void *begin, int64_t size,
|
||||
int64_t type) {
|
||||
DP("__tgt_push_mapper_component(Handle=" DPxMOD
|
||||
") adds an entry (Base=" DPxMOD ", Begin=" DPxMOD ", Size=%" PRId64
|
||||
", Type=0x%" PRIx64 ").\n",
|
||||
DPxPTR(rt_mapper_handle), DPxPTR(base), DPxPTR(begin), size, type);
|
||||
auto *MapperComponentsPtr = (struct MapperComponentsTy *)rt_mapper_handle;
|
||||
MapperComponentsPtr->Components.push_back(
|
||||
MapComponentInfoTy(base, begin, size, type));
|
||||
}
|
||||
|
||||
// The trip count mechanism will be revised - this scheme is not thread-safe.
|
||||
EXTERN void __kmpc_push_target_tripcount(int64_t device_id,
|
||||
uint64_t loop_tripcount) {
|
||||
if (IsOffloadDisabled())
|
||||
return;
|
||||
|
||||
if (device_id == OFFLOAD_DEVICE_DEFAULT) {
|
||||
device_id = omp_get_default_device();
|
||||
}
|
||||
|
||||
if (CheckDeviceAndCtors(device_id) != OFFLOAD_SUCCESS) {
|
||||
DP("Failed to get device %" PRId64 " ready\n", device_id);
|
||||
HandleTargetOutcome(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DP("__kmpc_push_target_tripcount(%" PRId64 ", %" PRIu64 ")\n", device_id,
|
||||
loop_tripcount);
|
||||
Devices[device_id].loopTripCnt = loop_tripcount;
|
||||
TblMapMtx.lock();
|
||||
Devices[device_id].LoopTripCnt.emplace(__kmpc_global_thread_num(NULL),
|
||||
loop_tripcount);
|
||||
TblMapMtx.unlock();
|
||||
}
|
||||
|
||||
+187
-94
@@ -1,9 +1,8 @@
|
||||
//===------ omptarget.cpp - Target independent OpenMP target RTL -- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -25,6 +24,8 @@
|
||||
int DebugLevel = 0;
|
||||
#endif // OMPTARGET_DEBUG
|
||||
|
||||
|
||||
|
||||
/* All begin addresses for partially mapped structs must be 8-aligned in order
|
||||
* to ensure proper alignment of members. E.g.
|
||||
*
|
||||
@@ -212,7 +213,6 @@ static int32_t member_of(int64_t type) {
|
||||
int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
// process each input.
|
||||
int rc = OFFLOAD_SUCCESS;
|
||||
for (int32_t i = 0; i < arg_num; ++i) {
|
||||
// Ignore private variables and arrays - there is no mapping for them.
|
||||
if ((arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) ||
|
||||
@@ -242,7 +242,11 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
// Address of pointer on the host and device, respectively.
|
||||
void *Pointer_HstPtrBegin, *Pointer_TgtPtrBegin;
|
||||
bool IsNew, Pointer_IsNew;
|
||||
bool IsHostPtr = false;
|
||||
bool IsImplicit = arg_types[i] & OMP_TGT_MAPTYPE_IMPLICIT;
|
||||
// Force the creation of a device side copy of the data when:
|
||||
// a close map modifier was associated with a map that contained a to.
|
||||
bool HasCloseModifier = arg_types[i] & OMP_TGT_MAPTYPE_CLOSE;
|
||||
// UpdateRef is based on MEMBER_OF instead of TARGET_PARAM because if we
|
||||
// have reached this point via __tgt_target_data_begin and not __tgt_target
|
||||
// then no argument is marked as TARGET_PARAM ("omp target data map" is not
|
||||
@@ -253,10 +257,12 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
DP("Has a pointer entry: \n");
|
||||
// base is address of pointer.
|
||||
Pointer_TgtPtrBegin = Device.getOrAllocTgtPtr(HstPtrBase, HstPtrBase,
|
||||
sizeof(void *), Pointer_IsNew, IsImplicit, UpdateRef);
|
||||
sizeof(void *), Pointer_IsNew, IsHostPtr, IsImplicit, UpdateRef,
|
||||
HasCloseModifier);
|
||||
if (!Pointer_TgtPtrBegin) {
|
||||
DP("Call to getOrAllocTgtPtr returned null pointer (device failure or "
|
||||
"illegal mapping).\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
DP("There are %zu bytes allocated at target address " DPxMOD " - is%s new"
|
||||
"\n", sizeof(void *), DPxPTR(Pointer_TgtPtrBegin),
|
||||
@@ -268,7 +274,7 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
}
|
||||
|
||||
void *TgtPtrBegin = Device.getOrAllocTgtPtr(HstPtrBegin, HstPtrBase,
|
||||
data_size, IsNew, IsImplicit, UpdateRef);
|
||||
data_size, IsNew, IsHostPtr, IsImplicit, UpdateRef, HasCloseModifier);
|
||||
if (!TgtPtrBegin && data_size) {
|
||||
// If data_size==0, then the argument could be a zero-length pointer to
|
||||
// NULL, so getOrAlloc() returning NULL is not an error.
|
||||
@@ -288,30 +294,33 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
|
||||
bool copy = false;
|
||||
if (IsNew || (arg_types[i] & OMP_TGT_MAPTYPE_ALWAYS)) {
|
||||
copy = true;
|
||||
} else if (arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) {
|
||||
// Copy data only if the "parent" struct has RefCount==1.
|
||||
int32_t parent_idx = member_of(arg_types[i]);
|
||||
long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
|
||||
assert(parent_rc > 0 && "parent struct not found");
|
||||
if (parent_rc == 1) {
|
||||
if (!(RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) ||
|
||||
HasCloseModifier) {
|
||||
if (IsNew || (arg_types[i] & OMP_TGT_MAPTYPE_ALWAYS)) {
|
||||
copy = true;
|
||||
} else if (arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) {
|
||||
// Copy data only if the "parent" struct has RefCount==1.
|
||||
int32_t parent_idx = member_of(arg_types[i]);
|
||||
long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
|
||||
assert(parent_rc > 0 && "parent struct not found");
|
||||
if (parent_rc == 1) {
|
||||
copy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (copy) {
|
||||
if (copy && !IsHostPtr) {
|
||||
DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n",
|
||||
data_size, DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBegin));
|
||||
int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, data_size);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data to device failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ) {
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ && !IsHostPtr) {
|
||||
DP("Update pointer (" DPxMOD ") -> [" DPxMOD "]\n",
|
||||
DPxPTR(Pointer_TgtPtrBegin), DPxPTR(TgtPtrBegin));
|
||||
uint64_t Delta = (uint64_t)HstPtrBegin - (uint64_t)HstPtrBase;
|
||||
@@ -320,7 +329,7 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
sizeof(void *));
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data to device failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
// create shadow pointers for this entry
|
||||
Device.ShadowMtx.lock();
|
||||
@@ -330,13 +339,12 @@ int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return OFFLOAD_SUCCESS;
|
||||
}
|
||||
|
||||
/// Internal function to undo the mapping and retrieve the data from the device.
|
||||
int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
int rc = OFFLOAD_SUCCESS;
|
||||
// process each input.
|
||||
for (int32_t i = arg_num - 1; i >= 0; --i) {
|
||||
// Ignore private variables and arrays - there is no mapping for them.
|
||||
@@ -363,14 +371,15 @@ int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLast;
|
||||
bool IsLast, IsHostPtr;
|
||||
bool UpdateRef = !(arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) ||
|
||||
(arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ);
|
||||
bool ForceDelete = arg_types[i] & OMP_TGT_MAPTYPE_DELETE;
|
||||
bool HasCloseModifier = arg_types[i] & OMP_TGT_MAPTYPE_CLOSE;
|
||||
|
||||
// If PTR_AND_OBJ, HstPtrBegin is address of pointee
|
||||
void *TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, data_size, IsLast,
|
||||
UpdateRef);
|
||||
UpdateRef, IsHostPtr);
|
||||
DP("There are %" PRId64 " bytes allocated at target address " DPxMOD
|
||||
" - is%s last\n", data_size, DPxPTR(TgtPtrBegin),
|
||||
(IsLast ? "" : " not"));
|
||||
@@ -387,24 +396,29 @@ int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_FROM) {
|
||||
bool Always = arg_types[i] & OMP_TGT_MAPTYPE_ALWAYS;
|
||||
bool CopyMember = false;
|
||||
if ((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
|
||||
!(arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ)) {
|
||||
// Copy data only if the "parent" struct has RefCount==1.
|
||||
int32_t parent_idx = member_of(arg_types[i]);
|
||||
long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
|
||||
assert(parent_rc > 0 && "parent struct not found");
|
||||
if (parent_rc == 1) {
|
||||
CopyMember = true;
|
||||
if (!(RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) ||
|
||||
HasCloseModifier) {
|
||||
if ((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
|
||||
!(arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ)) {
|
||||
// Copy data only if the "parent" struct has RefCount==1.
|
||||
int32_t parent_idx = member_of(arg_types[i]);
|
||||
long parent_rc = Device.getMapEntryRefCnt(args[parent_idx]);
|
||||
assert(parent_rc > 0 && "parent struct not found");
|
||||
if (parent_rc == 1) {
|
||||
CopyMember = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DelEntry || Always || CopyMember) {
|
||||
if ((DelEntry || Always || CopyMember) &&
|
||||
!(RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY &&
|
||||
TgtPtrBegin == HstPtrBegin)) {
|
||||
DP("Moving %" PRId64 " bytes (tgt:" DPxMOD ") -> (hst:" DPxMOD ")\n",
|
||||
data_size, DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBegin));
|
||||
int rt = Device.data_retrieve(HstPtrBegin, TgtPtrBegin, data_size);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data from device failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,13 +431,15 @@ int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
uintptr_t ub = (uintptr_t) HstPtrBegin + data_size;
|
||||
Device.ShadowMtx.lock();
|
||||
for (ShadowPtrListTy::iterator it = Device.ShadowPtrMap.begin();
|
||||
it != Device.ShadowPtrMap.end(); ++it) {
|
||||
it != Device.ShadowPtrMap.end();) {
|
||||
void **ShadowHstPtrAddr = (void**) it->first;
|
||||
|
||||
// An STL map is sorted on its keys; use this property
|
||||
// to quickly determine when to break out of the loop.
|
||||
if ((uintptr_t) ShadowHstPtrAddr < lb)
|
||||
if ((uintptr_t) ShadowHstPtrAddr < lb) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
if ((uintptr_t) ShadowHstPtrAddr >= ub)
|
||||
break;
|
||||
|
||||
@@ -437,27 +453,30 @@ int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
// If the struct is to be deallocated, remove the shadow entry.
|
||||
if (DelEntry) {
|
||||
DP("Removing shadow pointer " DPxMOD "\n", DPxPTR(ShadowHstPtrAddr));
|
||||
Device.ShadowPtrMap.erase(it);
|
||||
it = Device.ShadowPtrMap.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
Device.ShadowMtx.unlock();
|
||||
|
||||
// Deallocate map
|
||||
if (DelEntry) {
|
||||
int rt = Device.deallocTgtPtr(HstPtrBegin, data_size, ForceDelete);
|
||||
int rt = Device.deallocTgtPtr(HstPtrBegin, data_size, ForceDelete,
|
||||
HasCloseModifier);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Deallocating data from device failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return OFFLOAD_SUCCESS;
|
||||
}
|
||||
|
||||
/// Internal function to pass data to/from the target.
|
||||
void target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
int target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types) {
|
||||
// process each input.
|
||||
for (int32_t i = 0; i < arg_num; ++i) {
|
||||
@@ -467,14 +486,29 @@ void target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
|
||||
void *HstPtrBegin = args[i];
|
||||
int64_t MapSize = arg_sizes[i];
|
||||
bool IsLast;
|
||||
bool IsLast, IsHostPtr;
|
||||
void *TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, MapSize, IsLast,
|
||||
false);
|
||||
false, IsHostPtr);
|
||||
if (!TgtPtrBegin) {
|
||||
DP("hst data:" DPxMOD " not found, becomes a noop\n", DPxPTR(HstPtrBegin));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY &&
|
||||
TgtPtrBegin == HstPtrBegin) {
|
||||
DP("hst data:" DPxMOD " unified and shared, becomes a noop\n",
|
||||
DPxPTR(HstPtrBegin));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_FROM) {
|
||||
DP("Moving %" PRId64 " bytes (tgt:" DPxMOD ") -> (hst:" DPxMOD ")\n",
|
||||
arg_sizes[i], DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBegin));
|
||||
Device.data_retrieve(HstPtrBegin, TgtPtrBegin, MapSize);
|
||||
int rt = Device.data_retrieve(HstPtrBegin, TgtPtrBegin, MapSize);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data from device failed.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
uintptr_t lb = (uintptr_t) HstPtrBegin;
|
||||
uintptr_t ub = (uintptr_t) HstPtrBegin + MapSize;
|
||||
@@ -497,7 +531,11 @@ void target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
|
||||
DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n",
|
||||
arg_sizes[i], DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBegin));
|
||||
Device.data_submit(TgtPtrBegin, HstPtrBegin, MapSize);
|
||||
int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, MapSize);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data to device failed.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
uintptr_t lb = (uintptr_t) HstPtrBegin;
|
||||
uintptr_t ub = (uintptr_t) HstPtrBegin + MapSize;
|
||||
@@ -512,12 +550,25 @@ void target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
DP("Restoring original target pointer value " DPxMOD " for target "
|
||||
"pointer " DPxMOD "\n", DPxPTR(it->second.TgtPtrVal),
|
||||
DPxPTR(it->second.TgtPtrAddr));
|
||||
Device.data_submit(it->second.TgtPtrAddr,
|
||||
rt = Device.data_submit(it->second.TgtPtrAddr,
|
||||
&it->second.TgtPtrVal, sizeof(void *));
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data to device failed.\n");
|
||||
Device.ShadowMtx.unlock();
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
Device.ShadowMtx.unlock();
|
||||
}
|
||||
}
|
||||
return OFFLOAD_SUCCESS;
|
||||
}
|
||||
|
||||
static const unsigned LambdaMapping = OMP_TGT_MAPTYPE_PTR_AND_OBJ |
|
||||
OMP_TGT_MAPTYPE_LITERAL |
|
||||
OMP_TGT_MAPTYPE_IMPLICIT;
|
||||
static bool isLambdaMapping(int64_t Mapping) {
|
||||
return (Mapping & LambdaMapping) == LambdaMapping;
|
||||
}
|
||||
|
||||
/// performs the same actions as data_begin in case arg_num is
|
||||
@@ -585,12 +636,8 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
// Move data to device.
|
||||
int rc = target_data_begin(Device, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
|
||||
if (rc != OFFLOAD_SUCCESS) {
|
||||
DP("Call to target_data_begin failed, skipping target execution.\n");
|
||||
// Call target_data_end to dealloc whatever target_data_begin allocated
|
||||
// and return OFFLOAD_FAIL.
|
||||
target_data_end(Device, arg_num, args_base, args, arg_sizes, arg_types);
|
||||
DP("Call to target_data_begin failed, abort target.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
@@ -599,17 +646,59 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
|
||||
// List of (first-)private arrays allocated for this target region
|
||||
std::vector<void *> fpArrays;
|
||||
std::vector<int> tgtArgsPositions(arg_num, -1);
|
||||
|
||||
for (int32_t i = 0; i < arg_num; ++i) {
|
||||
if (!(arg_types[i] & OMP_TGT_MAPTYPE_TARGET_PARAM)) {
|
||||
// This is not a target parameter, do not push it into tgt_args.
|
||||
// Check for lambda mapping.
|
||||
if (isLambdaMapping(arg_types[i])) {
|
||||
assert((arg_types[i] & OMP_TGT_MAPTYPE_MEMBER_OF) &&
|
||||
"PTR_AND_OBJ must be also MEMBER_OF.");
|
||||
unsigned idx = member_of(arg_types[i]);
|
||||
int tgtIdx = tgtArgsPositions[idx];
|
||||
assert(tgtIdx != -1 && "Base address must be translated already.");
|
||||
// The parent lambda must be processed already and it must be the last
|
||||
// in tgt_args and tgt_offsets arrays.
|
||||
void *HstPtrVal = args[i];
|
||||
void *HstPtrBegin = args_base[i];
|
||||
void *HstPtrBase = args[idx];
|
||||
bool IsLast, IsHostPtr; // unused.
|
||||
void *TgtPtrBase =
|
||||
(void *)((intptr_t)tgt_args[tgtIdx] + tgt_offsets[tgtIdx]);
|
||||
DP("Parent lambda base " DPxMOD "\n", DPxPTR(TgtPtrBase));
|
||||
uint64_t Delta = (uint64_t)HstPtrBegin - (uint64_t)HstPtrBase;
|
||||
void *TgtPtrBegin = (void *)((uintptr_t)TgtPtrBase + Delta);
|
||||
void *Pointer_TgtPtrBegin =
|
||||
Device.getTgtPtrBegin(HstPtrVal, arg_sizes[i], IsLast, false,
|
||||
IsHostPtr);
|
||||
if (!Pointer_TgtPtrBegin) {
|
||||
DP("No lambda captured variable mapped (" DPxMOD ") - ignored\n",
|
||||
DPxPTR(HstPtrVal));
|
||||
continue;
|
||||
}
|
||||
if (RTLs.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY &&
|
||||
TgtPtrBegin == HstPtrBegin) {
|
||||
DP("Unified memory is active, no need to map lambda captured"
|
||||
"variable (" DPxMOD ")\n", DPxPTR(HstPtrVal));
|
||||
continue;
|
||||
}
|
||||
DP("Update lambda reference (" DPxMOD ") -> [" DPxMOD "]\n",
|
||||
DPxPTR(Pointer_TgtPtrBegin), DPxPTR(TgtPtrBegin));
|
||||
int rt = Device.data_submit(TgtPtrBegin, &Pointer_TgtPtrBegin,
|
||||
sizeof(void *));
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Copying data to device failed.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
void *HstPtrBegin = args[i];
|
||||
void *HstPtrBase = args_base[i];
|
||||
void *TgtPtrBegin;
|
||||
ptrdiff_t TgtBaseOffset;
|
||||
bool IsLast; // unused.
|
||||
bool IsLast, IsHostPtr; // unused.
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_LITERAL) {
|
||||
DP("Forwarding first-private value " DPxMOD " to the target construct\n",
|
||||
DPxPTR(HstPtrBase));
|
||||
@@ -620,42 +709,40 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
TgtPtrBegin = Device.RTL->data_alloc(Device.RTLDeviceID,
|
||||
arg_sizes[i], HstPtrBegin);
|
||||
if (!TgtPtrBegin) {
|
||||
DP ("Data allocation for %sprivate array " DPxMOD " failed\n",
|
||||
DP ("Data allocation for %sprivate array " DPxMOD " failed, "
|
||||
"abort target.\n",
|
||||
(arg_types[i] & OMP_TGT_MAPTYPE_TO ? "first-" : ""),
|
||||
DPxPTR(HstPtrBegin));
|
||||
rc = OFFLOAD_FAIL;
|
||||
break;
|
||||
} else {
|
||||
fpArrays.push_back(TgtPtrBegin);
|
||||
TgtBaseOffset = (intptr_t)HstPtrBase - (intptr_t)HstPtrBegin;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
fpArrays.push_back(TgtPtrBegin);
|
||||
TgtBaseOffset = (intptr_t)HstPtrBase - (intptr_t)HstPtrBegin;
|
||||
#ifdef OMPTARGET_DEBUG
|
||||
void *TgtPtrBase = (void *)((intptr_t)TgtPtrBegin + TgtBaseOffset);
|
||||
DP("Allocated %" PRId64 " bytes of target memory at " DPxMOD " for "
|
||||
"%sprivate array " DPxMOD " - pushing target argument " DPxMOD "\n",
|
||||
arg_sizes[i], DPxPTR(TgtPtrBegin),
|
||||
(arg_types[i] & OMP_TGT_MAPTYPE_TO ? "first-" : ""),
|
||||
DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBase));
|
||||
void *TgtPtrBase = (void *)((intptr_t)TgtPtrBegin + TgtBaseOffset);
|
||||
DP("Allocated %" PRId64 " bytes of target memory at " DPxMOD " for "
|
||||
"%sprivate array " DPxMOD " - pushing target argument " DPxMOD "\n",
|
||||
arg_sizes[i], DPxPTR(TgtPtrBegin),
|
||||
(arg_types[i] & OMP_TGT_MAPTYPE_TO ? "first-" : ""),
|
||||
DPxPTR(HstPtrBegin), DPxPTR(TgtPtrBase));
|
||||
#endif
|
||||
// If first-private, copy data from host
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
|
||||
int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, arg_sizes[i]);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP ("Copying data to device failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
break;
|
||||
}
|
||||
// If first-private, copy data from host
|
||||
if (arg_types[i] & OMP_TGT_MAPTYPE_TO) {
|
||||
int rt = Device.data_submit(TgtPtrBegin, HstPtrBegin, arg_sizes[i]);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP ("Copying data to device failed, failed.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
} else if (arg_types[i] & OMP_TGT_MAPTYPE_PTR_AND_OBJ) {
|
||||
TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBase, sizeof(void *), IsLast,
|
||||
false);
|
||||
false, IsHostPtr);
|
||||
TgtBaseOffset = 0; // no offset for ptrs.
|
||||
DP("Obtained target argument " DPxMOD " from host pointer " DPxMOD " to "
|
||||
"object " DPxMOD "\n", DPxPTR(TgtPtrBegin), DPxPTR(HstPtrBase),
|
||||
DPxPTR(HstPtrBase));
|
||||
} else {
|
||||
TgtPtrBegin = Device.getTgtPtrBegin(HstPtrBegin, arg_sizes[i], IsLast,
|
||||
false);
|
||||
false, IsHostPtr);
|
||||
TgtBaseOffset = (intptr_t)HstPtrBase - (intptr_t)HstPtrBegin;
|
||||
#ifdef OMPTARGET_DEBUG
|
||||
void *TgtPtrBase = (void *)((intptr_t)TgtPtrBegin + TgtBaseOffset);
|
||||
@@ -663,6 +750,7 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
DPxPTR(TgtPtrBase), DPxPTR(HstPtrBegin));
|
||||
#endif
|
||||
}
|
||||
tgtArgsPositions[i] = tgt_args.size();
|
||||
tgt_args.push_back(TgtPtrBegin);
|
||||
tgt_offsets.push_back(TgtBaseOffset);
|
||||
}
|
||||
@@ -671,25 +759,31 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
"Size mismatch in arguments and offsets");
|
||||
|
||||
// Pop loop trip count
|
||||
uint64_t ltc = Device.loopTripCnt;
|
||||
Device.loopTripCnt = 0;
|
||||
uint64_t ltc = 0;
|
||||
TblMapMtx.lock();
|
||||
auto I = Device.LoopTripCnt.find(__kmpc_global_thread_num(NULL));
|
||||
if (I != Device.LoopTripCnt.end()) {
|
||||
ltc = I->second;
|
||||
Device.LoopTripCnt.erase(I);
|
||||
DP("loop trip count is %lu.\n", ltc);
|
||||
}
|
||||
TblMapMtx.unlock();
|
||||
|
||||
// Launch device execution.
|
||||
if (rc == OFFLOAD_SUCCESS) {
|
||||
DP("Launching target execution %s with pointer " DPxMOD " (index=%d).\n",
|
||||
TargetTable->EntriesBegin[TM->Index].name,
|
||||
DPxPTR(TargetTable->EntriesBegin[TM->Index].addr), TM->Index);
|
||||
if (IsTeamConstruct) {
|
||||
rc = Device.run_team_region(TargetTable->EntriesBegin[TM->Index].addr,
|
||||
&tgt_args[0], &tgt_offsets[0], tgt_args.size(), team_num,
|
||||
thread_limit, ltc);
|
||||
} else {
|
||||
rc = Device.run_region(TargetTable->EntriesBegin[TM->Index].addr,
|
||||
&tgt_args[0], &tgt_offsets[0], tgt_args.size());
|
||||
}
|
||||
DP("Launching target execution %s with pointer " DPxMOD " (index=%d).\n",
|
||||
TargetTable->EntriesBegin[TM->Index].name,
|
||||
DPxPTR(TargetTable->EntriesBegin[TM->Index].addr), TM->Index);
|
||||
if (IsTeamConstruct) {
|
||||
rc = Device.run_team_region(TargetTable->EntriesBegin[TM->Index].addr,
|
||||
&tgt_args[0], &tgt_offsets[0], tgt_args.size(), team_num,
|
||||
thread_limit, ltc);
|
||||
} else {
|
||||
DP("Errors occurred while obtaining target arguments, skipping kernel "
|
||||
"execution\n");
|
||||
rc = Device.run_region(TargetTable->EntriesBegin[TM->Index].addr,
|
||||
&tgt_args[0], &tgt_offsets[0], tgt_args.size());
|
||||
}
|
||||
if (rc != OFFLOAD_SUCCESS) {
|
||||
DP ("Executing target region abort target.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
// Deallocate (first-)private arrays
|
||||
@@ -697,18 +791,17 @@ int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
int rt = Device.RTL->data_delete(Device.RTLDeviceID, it);
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Deallocation of (first-)private arrays failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Move data from device.
|
||||
int rt = target_data_end(Device, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
|
||||
if (rt != OFFLOAD_SUCCESS) {
|
||||
DP("Call to target_data_end failed.\n");
|
||||
rc = OFFLOAD_FAIL;
|
||||
DP("Call to target_data_end failed, abort targe.\n");
|
||||
return OFFLOAD_FAIL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return OFFLOAD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//===---------- private.h - Target independent OpenMP target RTL ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -24,7 +23,7 @@ extern int target_data_begin(DeviceTy &Device, int32_t arg_num,
|
||||
extern int target_data_end(DeviceTy &Device, int32_t arg_num, void **args_base,
|
||||
void **args, int64_t *arg_sizes, int64_t *arg_types);
|
||||
|
||||
extern void target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
extern int target_data_update(DeviceTy &Device, int32_t arg_num,
|
||||
void **args_base, void **args, int64_t *arg_sizes, int64_t *arg_types);
|
||||
|
||||
extern int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
@@ -33,12 +32,59 @@ extern int target(int64_t device_id, void *host_ptr, int32_t arg_num,
|
||||
|
||||
extern int CheckDeviceAndCtors(int64_t device_id);
|
||||
|
||||
// enum for OMP_TARGET_OFFLOAD; keep in sync with kmp.h definition
|
||||
enum kmp_target_offload_kind {
|
||||
tgt_disabled = 0,
|
||||
tgt_default = 1,
|
||||
tgt_mandatory = 2
|
||||
};
|
||||
typedef enum kmp_target_offload_kind kmp_target_offload_kind_t;
|
||||
extern kmp_target_offload_kind_t TargetOffloadPolicy;
|
||||
|
||||
// This structure stores information of a mapped memory region.
|
||||
struct MapComponentInfoTy {
|
||||
void *Base;
|
||||
void *Begin;
|
||||
int64_t Size;
|
||||
int64_t Type;
|
||||
MapComponentInfoTy() = default;
|
||||
MapComponentInfoTy(void *Base, void *Begin, int64_t Size, int64_t Type)
|
||||
: Base(Base), Begin(Begin), Size(Size), Type(Type) {}
|
||||
};
|
||||
|
||||
// This structure stores all components of a user-defined mapper. The number of
|
||||
// components are dynamically decided, so we utilize C++ STL vector
|
||||
// implementation here.
|
||||
struct MapperComponentsTy {
|
||||
std::vector<MapComponentInfoTy> Components;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// implemtation for fatal messages
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define FATAL_MESSAGE0(_num, _str) \
|
||||
do { \
|
||||
fprintf(stderr, "Libomptarget fatal error %d: %s\n", _num, _str); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define FATAL_MESSAGE(_num, _str, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "Libomptarget fatal error %d:" _str "\n", _num, \
|
||||
__VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
// Implemented in libomp, they are called from within __tgt_* functions.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// functions that extract info from libomp; keep in sync
|
||||
int omp_get_default_device(void) __attribute__((weak));
|
||||
int32_t __kmpc_omp_taskwait(void *loc_ref, int32_t gtid) __attribute__((weak));
|
||||
int32_t __kmpc_global_thread_num(void *) __attribute__((weak));
|
||||
int __kmpc_get_target_offload(void) __attribute__((weak));
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+49
-11
@@ -1,9 +1,8 @@
|
||||
//===----------- rtl.cpp - Target independent OpenMP target RTL -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -46,9 +45,8 @@ void RTLsTy::LoadRTLs() {
|
||||
#endif // OMPTARGET_DEBUG
|
||||
|
||||
// Parse environment variable OMP_TARGET_OFFLOAD (if set)
|
||||
char *envStr = getenv("OMP_TARGET_OFFLOAD");
|
||||
if (envStr && !strcmp(envStr, "DISABLED")) {
|
||||
DP("Target offloading disabled by environment\n");
|
||||
TargetOffloadPolicy = (kmp_target_offload_kind_t) __kmpc_get_target_offload();
|
||||
if (TargetOffloadPolicy == tgt_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,6 +107,10 @@ void RTLsTy::LoadRTLs() {
|
||||
dynlib_handle, "__tgt_rtl_run_target_team_region")))
|
||||
continue;
|
||||
|
||||
// Optional functions
|
||||
*((void**) &R.init_requires) = dlsym(
|
||||
dynlib_handle, "__tgt_rtl_init_requires");
|
||||
|
||||
// No devices are supported by this RTL?
|
||||
if (!(R.NumberOfDevices = R.number_of_devices())) {
|
||||
DP("No devices supported in this RTL\n");
|
||||
@@ -188,6 +190,46 @@ static void RegisterGlobalCtorsDtorsForImage(__tgt_bin_desc *desc,
|
||||
}
|
||||
}
|
||||
|
||||
void RTLsTy::RegisterRequires(int64_t flags) {
|
||||
// TODO: add more elaborate check.
|
||||
// Minimal check: only set requires flags if previous value
|
||||
// is undefined. This ensures that only the first call to this
|
||||
// function will set the requires flags. All subsequent calls
|
||||
// will be checked for compatibility.
|
||||
assert(flags != OMP_REQ_UNDEFINED &&
|
||||
"illegal undefined flag for requires directive!");
|
||||
if (RequiresFlags == OMP_REQ_UNDEFINED) {
|
||||
RequiresFlags = flags;
|
||||
return;
|
||||
}
|
||||
|
||||
// If multiple compilation units are present enforce
|
||||
// consistency across all of them for require clauses:
|
||||
// - reverse_offload
|
||||
// - unified_address
|
||||
// - unified_shared_memory
|
||||
if ((RequiresFlags & OMP_REQ_REVERSE_OFFLOAD) !=
|
||||
(flags & OMP_REQ_REVERSE_OFFLOAD)) {
|
||||
FATAL_MESSAGE0(1,
|
||||
"'#pragma omp requires reverse_offload' not used consistently!");
|
||||
}
|
||||
if ((RequiresFlags & OMP_REQ_UNIFIED_ADDRESS) !=
|
||||
(flags & OMP_REQ_UNIFIED_ADDRESS)) {
|
||||
FATAL_MESSAGE0(1,
|
||||
"'#pragma omp requires unified_address' not used consistently!");
|
||||
}
|
||||
if ((RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) !=
|
||||
(flags & OMP_REQ_UNIFIED_SHARED_MEMORY)) {
|
||||
FATAL_MESSAGE0(1,
|
||||
"'#pragma omp requires unified_shared_memory' not used consistently!");
|
||||
}
|
||||
|
||||
// TODO: insert any other missing checks
|
||||
|
||||
DP("New requires flags %ld compatible with existing %ld!\n",
|
||||
flags, RequiresFlags);
|
||||
}
|
||||
|
||||
void RTLsTy::RegisterLib(__tgt_bin_desc *desc) {
|
||||
// Attempt to load all plugins available in the system.
|
||||
std::call_once(initFlag, &RTLsTy::LoadRTLs, this);
|
||||
@@ -216,7 +258,6 @@ void RTLsTy::RegisterLib(__tgt_bin_desc *desc) {
|
||||
if (!R.isUsed) {
|
||||
// Initialize the device information for the RTL we are about to use.
|
||||
DeviceTy device(&R);
|
||||
|
||||
size_t start = Devices.size();
|
||||
Devices.resize(start + R.NumberOfDevices, device);
|
||||
for (int32_t device_id = 0; device_id < R.NumberOfDevices;
|
||||
@@ -225,9 +266,6 @@ void RTLsTy::RegisterLib(__tgt_bin_desc *desc) {
|
||||
Devices[start + device_id].DeviceID = start + device_id;
|
||||
// RTL local device ID
|
||||
Devices[start + device_id].RTLDeviceID = device_id;
|
||||
|
||||
// Save pointer to device in RTL in case we want to unregister the RTL
|
||||
R.Devices.push_back(&Devices[start + device_id]);
|
||||
}
|
||||
|
||||
// Initialize the index of this RTL and save it in the used RTLs.
|
||||
|
||||
+14
-9
@@ -1,9 +1,8 @@
|
||||
//===------------ rtl.h - Target independent OpenMP target RTL ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
@@ -37,13 +36,13 @@ struct RTLInfoTy {
|
||||
int32_t);
|
||||
typedef int32_t(run_team_region_ty)(int32_t, void *, void **, ptrdiff_t *,
|
||||
int32_t, int32_t, int32_t, uint64_t);
|
||||
typedef int64_t(init_requires_ty)(int64_t);
|
||||
|
||||
int32_t Idx; // RTL index, index is the number of devices
|
||||
// of other RTLs that were registered before,
|
||||
// i.e. the OpenMP index of the first device
|
||||
// to be registered with this RTL.
|
||||
int32_t NumberOfDevices; // Number of devices this RTL deals with.
|
||||
std::vector<DeviceTy *> Devices; // one per device (NumberOfDevices in total).
|
||||
|
||||
void *LibraryHandler;
|
||||
|
||||
@@ -62,6 +61,7 @@ struct RTLInfoTy {
|
||||
data_delete_ty *data_delete;
|
||||
run_region_ty *run_region;
|
||||
run_team_region_ty *run_team_region;
|
||||
init_requires_ty *init_requires;
|
||||
|
||||
// Are there images associated with this RTL.
|
||||
bool isUsed;
|
||||
@@ -74,19 +74,18 @@ struct RTLInfoTy {
|
||||
// The existence of the mutex above makes RTLInfoTy non-copyable.
|
||||
// We need to provide a copy constructor explicitly.
|
||||
RTLInfoTy()
|
||||
: Idx(-1), NumberOfDevices(-1), Devices(), LibraryHandler(0),
|
||||
: Idx(-1), NumberOfDevices(-1), LibraryHandler(0),
|
||||
#ifdef OMPTARGET_DEBUG
|
||||
RTLName(),
|
||||
#endif
|
||||
is_valid_binary(0), number_of_devices(0), init_device(0),
|
||||
load_binary(0), data_alloc(0), data_submit(0), data_retrieve(0),
|
||||
data_delete(0), run_region(0), run_team_region(0), isUsed(false),
|
||||
Mtx() {}
|
||||
data_delete(0), run_region(0), run_team_region(0),
|
||||
init_requires(0), isUsed(false), Mtx() {}
|
||||
|
||||
RTLInfoTy(const RTLInfoTy &r) : Mtx() {
|
||||
Idx = r.Idx;
|
||||
NumberOfDevices = r.NumberOfDevices;
|
||||
Devices = r.Devices;
|
||||
LibraryHandler = r.LibraryHandler;
|
||||
#ifdef OMPTARGET_DEBUG
|
||||
RTLName = r.RTLName;
|
||||
@@ -101,6 +100,7 @@ struct RTLInfoTy {
|
||||
data_delete = r.data_delete;
|
||||
run_region = r.run_region;
|
||||
run_team_region = r.run_team_region;
|
||||
init_requires = r.init_requires;
|
||||
isUsed = r.isUsed;
|
||||
}
|
||||
};
|
||||
@@ -121,8 +121,13 @@ public:
|
||||
// binaries.
|
||||
std::vector<RTLInfoTy *> UsedRTLs;
|
||||
|
||||
int64_t RequiresFlags;
|
||||
|
||||
explicit RTLsTy() {}
|
||||
|
||||
// Register the clauses of the requires directive.
|
||||
void RegisterRequires(int64_t flags);
|
||||
|
||||
// Register a shared library with all (compatible) RTLs.
|
||||
void RegisterLib(__tgt_bin_desc *desc);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ if(NOT OPENMP_TEST_COMPILER_ID STREQUAL "Clang" OR
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(LIBOMPTARGET_CMAKE_BUILD_TYPE MATCHES debug)
|
||||
if(LIBOMPTARGET_ENABLE_DEBUG)
|
||||
set(LIBOMPTARGET_DEBUG True)
|
||||
else()
|
||||
set(LIBOMPTARGET_DEBUG False)
|
||||
@@ -14,15 +14,6 @@ endif()
|
||||
|
||||
add_openmp_testsuite(check-libomptarget "Running libomptarget tests" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS omptarget omp)
|
||||
|
||||
if(${OPENMP_STANDALONE_BUILD})
|
||||
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../../runtime/src" CACHE STRING
|
||||
"Path to folder containing omp.h")
|
||||
set(LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../../runtime/src" CACHE STRING
|
||||
"Path to folder containing libomp.so")
|
||||
else()
|
||||
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${LIBOMPTARGET_BINARY_DIR}/../runtime/src")
|
||||
endif()
|
||||
|
||||
# Configure the lit.site.cfg.in file
|
||||
set(AUTO_GEN_COMMENT "## Autogenerated by libomptarget configuration.\n# Do not edit!")
|
||||
configure_file(lit.site.cfg.in lit.site.cfg @ONLY)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
int test_omp_get_num_devices()
|
||||
{
|
||||
/* checks that omp_get_num_devices() > 0 */
|
||||
int num_devices = omp_get_num_devices();
|
||||
printf("num_devices = %d\n", num_devices);
|
||||
|
||||
#pragma omp target
|
||||
{}
|
||||
|
||||
return (num_devices > 0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
int failed=0;
|
||||
|
||||
if (!test_omp_get_num_devices()) {
|
||||
failed++;
|
||||
}
|
||||
if (failed)
|
||||
printf("FAIL\n");
|
||||
else
|
||||
printf("PASS\n");
|
||||
return failed;
|
||||
}
|
||||
|
||||
// CHECK: PASS
|
||||
@@ -41,6 +41,11 @@ if config.omp_host_rtl_directory:
|
||||
|
||||
config.test_flags = config.test_flags + " " + config.test_extra_flags
|
||||
|
||||
# Allow REQUIRES / UNSUPPORTED / XFAIL to work
|
||||
config.target_triple = [ ]
|
||||
for feature in config.test_compiler_features:
|
||||
config.available_features.add(feature)
|
||||
|
||||
if config.libomptarget_debug:
|
||||
config.available_features.add('libomptarget-debug')
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
config.test_c_compiler = "@OPENMP_TEST_C_COMPILER@"
|
||||
config.test_cxx_compiler = "@OPENMP_TEST_CXX_COMPILER@"
|
||||
config.test_compiler_features = @OPENMP_TEST_COMPILER_FEATURES@
|
||||
config.test_openmp_flags = "@OPENMP_TEST_OPENMP_FLAGS@"
|
||||
config.test_extra_flags = "@OPENMP_TEST_FLAGS@"
|
||||
config.libomptarget_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
|
||||
@@ -15,4 +16,4 @@ config.libomptarget_filecheck = "@OPENMP_FILECHECK_EXECUTABLE@"
|
||||
config.libomptarget_debug = @LIBOMPTARGET_DEBUG@
|
||||
|
||||
# Let the main config do the real work.
|
||||
lit_config.load_config(config, "@LIBOMPTARGET_BASE_DIR@/test/lit.cfg")
|
||||
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// RUN: %libomptarget-compilexx-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
// Data structure definitions copied from OpenMP RTL.
|
||||
struct MapComponentInfoTy {
|
||||
void *Base;
|
||||
void *Begin;
|
||||
int64_t Size;
|
||||
int64_t Type;
|
||||
MapComponentInfoTy() = default;
|
||||
MapComponentInfoTy(void *Base, void *Begin, int64_t Size, int64_t Type)
|
||||
: Base(Base), Begin(Begin), Size(Size), Type(Type) {}
|
||||
};
|
||||
|
||||
struct MapperComponentsTy {
|
||||
std::vector<MapComponentInfoTy> Components;
|
||||
};
|
||||
|
||||
// OpenMP RTL interfaces
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int64_t __tgt_mapper_num_components(void *rt_mapper_handle);
|
||||
void __tgt_push_mapper_component(void *rt_mapper_handle, void *base,
|
||||
void *begin, int64_t size, int64_t type);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
MapperComponentsTy MC;
|
||||
void *base, *begin;
|
||||
int64_t size, type;
|
||||
// Push 2 elements into MC.
|
||||
__tgt_push_mapper_component((void *)&MC, base, begin, size, type);
|
||||
__tgt_push_mapper_component((void *)&MC, base, begin, size, type);
|
||||
int64_t num = __tgt_mapper_num_components((void *)&MC);
|
||||
// CHECK: num=2
|
||||
printf("num=%lld\n", num);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
// Clang 6.0 doesn't use the new map interface, undefined behavior when
|
||||
// the compiler emits "old" interface code for structures.
|
||||
// UNSUPPORTED: clang-6
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int *ptr1;
|
||||
int *ptr2;
|
||||
} StructWithPtrs;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
StructWithPtrs s, s2;
|
||||
s.ptr1 = malloc(sizeof(int));
|
||||
s.ptr2 = malloc(2 * sizeof(int));
|
||||
s2.ptr1 = malloc(sizeof(int));
|
||||
s2.ptr2 = malloc(2 * sizeof(int));
|
||||
|
||||
#pragma omp target enter data map(to: s2.ptr2[0:1])
|
||||
#pragma omp target map(s.ptr1[0:1], s.ptr2[0:2])
|
||||
{
|
||||
s.ptr1[0] = 1;
|
||||
s.ptr2[0] = 2;
|
||||
s.ptr2[1] = 3;
|
||||
}
|
||||
#pragma omp target exit data map(from: s2.ptr1[0:1], s2.ptr2[0:1])
|
||||
|
||||
// CHECK: s.ptr1[0] = 1
|
||||
// CHECK: s.ptr2[0] = 2
|
||||
// CHECK: s.ptr2[1] = 3
|
||||
printf("s.ptr1[0] = %d\n", s.ptr1[0]);
|
||||
printf("s.ptr2[0] = %d\n", s.ptr2[0]);
|
||||
printf("s.ptr2[1] = %d\n", s.ptr2[1]);
|
||||
|
||||
free(s.ptr1);
|
||||
free(s.ptr2);
|
||||
free(s2.ptr1);
|
||||
free(s2.ptr2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// RUN: %libomptarget-compile-aarch64-unknown-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-aarch64-unknown-linux-gnu 2>&1 | %fcheck-aarch64-unknown-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-powerpc64-ibm-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-powerpc64-ibm-linux-gnu 2>&1 | %fcheck-powerpc64-ibm-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-powerpc64le-ibm-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-powerpc64le-ibm-linux-gnu 2>&1 | %fcheck-powerpc64le-ibm-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-x86_64-pc-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-x86_64-pc-linux-gnu 2>&1 | %fcheck-x86_64-pc-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// REQUIRES: libomptarget-debug
|
||||
|
||||
/*
|
||||
Test for looptripcount being popped from runtime stack.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
int main()
|
||||
{
|
||||
int N = 128;
|
||||
int NN = 1024;
|
||||
int num_teams[NN];
|
||||
int num_threads[NN];
|
||||
|
||||
printf("#pragma omp target teams distribute parallel for thread_limit(4)\n");
|
||||
#pragma omp target teams distribute parallel for thread_limit(4)
|
||||
for (int j = 0; j< N; j++) {
|
||||
num_threads[j] = omp_get_num_threads();
|
||||
num_teams[j] = omp_get_num_teams();
|
||||
}
|
||||
printf("num_threads %d num_teams %d\n", num_threads[0], num_teams[0]);
|
||||
// DEBUG: loop trip count is 128
|
||||
printf("#pragma omp target teams distribute parallel for\n");
|
||||
#pragma omp target teams distribute parallel for
|
||||
for (int j = 0; j< N; j++) {
|
||||
num_threads[j] = omp_get_num_threads();
|
||||
num_teams[j] = omp_get_num_teams();
|
||||
}
|
||||
printf("num_threads %d num_teams %d\n", num_threads[0], num_teams[0]);
|
||||
// DEBUG: loop trip count is 128
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// RUN: %libomptarget-compile-aarch64-unknown-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-aarch64-unknown-linux-gnu 2>&1 | %fcheck-aarch64-unknown-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-powerpc64-ibm-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-powerpc64-ibm-linux-gnu 2>&1 | %fcheck-powerpc64-ibm-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-powerpc64le-ibm-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-powerpc64le-ibm-linux-gnu 2>&1 | %fcheck-powerpc64le-ibm-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// RUN: %libomptarget-compile-x86_64-pc-linux-gnu && env LIBOMPTARGET_DEBUG=1 %libomptarget-run-x86_64-pc-linux-gnu 2>&1 | %fcheck-x86_64-pc-linux-gnu -allow-empty -check-prefix=DEBUG
|
||||
// REQUIRES: libomptarget-debug
|
||||
|
||||
/*
|
||||
Test for the 'requires' clause check.
|
||||
When a target region is used, the requires flags are set in the
|
||||
runtime for the entire compilation unit. If the flags are set again,
|
||||
(for whatever reason) the set must be consistent with previously
|
||||
set values.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Various definitions copied from OpenMP RTL
|
||||
|
||||
extern void __tgt_register_requires(int64_t);
|
||||
|
||||
// End of definitions copied from OpenMP RTL.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void run_reg_requires() {
|
||||
// Before the target region is registered, the requires registers the status
|
||||
// of the requires clauses. Since there are no requires clauses in this file
|
||||
// the flags state can only be OMP_REQ_NONE i.e. 1.
|
||||
|
||||
// This is the 2nd time this function is called so it should print the debug
|
||||
// info belonging to the check.
|
||||
__tgt_register_requires(1);
|
||||
__tgt_register_requires(1);
|
||||
// DEBUG: New requires flags 1 compatible with existing 1!
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
int main() {
|
||||
run_reg_requires();
|
||||
|
||||
// This also runs reg requires for the first time.
|
||||
#pragma omp target
|
||||
{}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// RUN: %libomptarget-compilexx-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compilexx-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define N 1024
|
||||
|
||||
int A[N];
|
||||
int B[N];
|
||||
int C[N];
|
||||
int main() {
|
||||
for (int i = 0; i < N; i++)
|
||||
A[i] = B[i] = i;
|
||||
|
||||
#pragma omp parallel num_threads(2)
|
||||
{
|
||||
if (omp_get_thread_num() == 1) {
|
||||
// map data A & B and move to
|
||||
#pragma omp target enter data map(to : A, B) depend(out : A[0]) nowait
|
||||
|
||||
// no data move since already mapped
|
||||
#pragma omp target map(A, B) depend(out : A[0]) nowait
|
||||
{
|
||||
for (int i = 0; i < N; i++)
|
||||
++A[i];
|
||||
for (int i = 0; i < N; i++)
|
||||
++B[i];
|
||||
}
|
||||
|
||||
// no data move since already mapped
|
||||
#pragma omp target teams num_teams(1) map(A, B) depend(out : A[0]) nowait
|
||||
{
|
||||
for (int i = 0; i < N; i++)
|
||||
++A[i];
|
||||
for (int i = 0; i < N; i++)
|
||||
++B[i];
|
||||
}
|
||||
|
||||
// A updated via update
|
||||
#pragma omp target update from(A) depend(out : A[0]) nowait
|
||||
|
||||
// B updated via exit, A just released
|
||||
#pragma omp target exit data map(release \
|
||||
: A) map(from \
|
||||
: B) depend(out \
|
||||
: A[0]) nowait
|
||||
} // if
|
||||
} // parallel
|
||||
|
||||
int Sum = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
Sum += A[i] + B[i];
|
||||
// Sum is 2 * N * (2 + N - 1 + 2) / 2
|
||||
// CHECK: Sum = 1051648.
|
||||
printf("Sum = %d.\n", Sum);
|
||||
|
||||
return Sum != 2 * N * (2 + N - 1 + 2) / 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Various definitions copied from OpenMP RTL
|
||||
|
||||
extern void __tgt_register_requires(int64_t);
|
||||
|
||||
// End of definitions copied from OpenMP RTL.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#pragma omp requires unified_shared_memory
|
||||
|
||||
#define N 1024
|
||||
|
||||
void init(int A[], int B[], int C[]) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
A[i] = 0;
|
||||
B[i] = 1;
|
||||
C[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const int device = omp_get_default_device();
|
||||
|
||||
// Manual registration of requires flags for Clang versions
|
||||
// that do not support requires.
|
||||
__tgt_register_requires(8);
|
||||
|
||||
// CHECK: Initial device: -10
|
||||
printf("Initial device: %d\n", omp_get_initial_device());
|
||||
|
||||
//
|
||||
// Target alloc & target memcpy
|
||||
//
|
||||
int A[N], B[N], C[N];
|
||||
|
||||
// Init
|
||||
init(A, B, C);
|
||||
|
||||
int *pA, *pB, *pC;
|
||||
|
||||
// map ptrs
|
||||
pA = &A[0];
|
||||
pB = &B[0];
|
||||
pC = &C[0];
|
||||
|
||||
int *d_A = (int *)omp_target_alloc(N * sizeof(int), device);
|
||||
int *d_B = (int *)omp_target_alloc(N * sizeof(int), device);
|
||||
int *d_C = (int *)omp_target_alloc(N * sizeof(int), device);
|
||||
|
||||
// CHECK: omp_target_alloc succeeded
|
||||
printf("omp_target_alloc %s\n", d_A && d_B && d_C ? "succeeded" : "failed");
|
||||
|
||||
omp_target_memcpy(d_B, pB, N * sizeof(int), 0, 0, device,
|
||||
omp_get_initial_device());
|
||||
omp_target_memcpy(d_C, pC, N * sizeof(int), 0, 0, device,
|
||||
omp_get_initial_device());
|
||||
|
||||
#pragma omp target is_device_ptr(d_A, d_B, d_C) device(device)
|
||||
{
|
||||
#pragma omp parallel for schedule(static, 1)
|
||||
for (int i = 0; i < N; i++) {
|
||||
d_A[i] = d_B[i] + d_C[i] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
omp_target_memcpy(pA, d_A, N * sizeof(int), 0, 0, omp_get_initial_device(),
|
||||
device);
|
||||
|
||||
// CHECK: Test omp_target_memcpy: Succeeded
|
||||
int fail = 0;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (A[i] != i + 2)
|
||||
fail++;
|
||||
}
|
||||
if (fail) {
|
||||
printf("Test omp_target_memcpy: Failed\n");
|
||||
} else {
|
||||
printf("Test omp_target_memcpy: Succeeded\n");
|
||||
}
|
||||
|
||||
//
|
||||
// target_is_present and target_associate/disassociate_ptr
|
||||
//
|
||||
init(A, B, C);
|
||||
|
||||
// CHECK: B is not present, associating it...
|
||||
// CHECK: omp_target_associate_ptr B succeeded
|
||||
if (!omp_target_is_present(B, device)) {
|
||||
printf("B is not present, associating it...\n");
|
||||
int rc = omp_target_associate_ptr(B, d_B, N * sizeof(int), 0, device);
|
||||
printf("omp_target_associate_ptr B %s\n", !rc ? "succeeded" : "failed");
|
||||
}
|
||||
|
||||
// CHECK: C is not present, associating it...
|
||||
// CHECK: omp_target_associate_ptr C succeeded
|
||||
if (!omp_target_is_present(C, device)) {
|
||||
printf("C is not present, associating it...\n");
|
||||
int rc = omp_target_associate_ptr(C, d_C, N * sizeof(int), 0, device);
|
||||
printf("omp_target_associate_ptr C %s\n", !rc ? "succeeded" : "failed");
|
||||
}
|
||||
|
||||
// CHECK: Inside target data: A is not present
|
||||
// CHECK: Inside target data: B is present
|
||||
// CHECK: Inside target data: C is present
|
||||
#pragma omp target data map(from : B, C) device(device)
|
||||
{
|
||||
printf("Inside target data: A is%s present\n",
|
||||
omp_target_is_present(A, device) ? "" : " not");
|
||||
printf("Inside target data: B is%s present\n",
|
||||
omp_target_is_present(B, device) ? "" : " not");
|
||||
printf("Inside target data: C is%s present\n",
|
||||
omp_target_is_present(C, device) ? "" : " not");
|
||||
|
||||
#pragma omp target map(from : A) device(device)
|
||||
{
|
||||
#pragma omp parallel for schedule(static, 1)
|
||||
for (int i = 0; i < N; i++)
|
||||
A[i] = B[i] + C[i] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: B is present, disassociating it...
|
||||
// CHECK: omp_target_disassociate_ptr B succeeded
|
||||
// CHECK: C is present, disassociating it...
|
||||
// CHECK: omp_target_disassociate_ptr C succeeded
|
||||
if (omp_target_is_present(B, device)) {
|
||||
printf("B is present, disassociating it...\n");
|
||||
int rc = omp_target_disassociate_ptr(B, device);
|
||||
printf("omp_target_disassociate_ptr B %s\n", !rc ? "succeeded" : "failed");
|
||||
}
|
||||
if (omp_target_is_present(C, device)) {
|
||||
printf("C is present, disassociating it...\n");
|
||||
int rc = omp_target_disassociate_ptr(C, device);
|
||||
printf("omp_target_disassociate_ptr C %s\n", !rc ? "succeeded" : "failed");
|
||||
}
|
||||
|
||||
// CHECK: Test omp_target_associate_ptr: Succeeded
|
||||
fail = 0;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (A[i] != i + 2)
|
||||
fail++;
|
||||
}
|
||||
if (fail) {
|
||||
printf("Test omp_target_associate_ptr: Failed\n");
|
||||
} else {
|
||||
printf("Test omp_target_associate_ptr: Succeeded\n");
|
||||
}
|
||||
|
||||
omp_target_free(d_A, device);
|
||||
omp_target_free(d_B, device);
|
||||
omp_target_free(d_C, device);
|
||||
|
||||
printf("Done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
// UNSUPPORTED: clang-6, clang-7, clang-8, clang-9
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma omp requires unified_shared_memory
|
||||
|
||||
#define N 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fails;
|
||||
void *host_alloc = 0, *device_alloc = 0;
|
||||
int *a = (int *)malloc(N * sizeof(int));
|
||||
|
||||
// Init
|
||||
for (int i = 0; i < N; ++i) {
|
||||
a[i] = 10;
|
||||
}
|
||||
host_alloc = &a[0];
|
||||
|
||||
//
|
||||
// map + target no close
|
||||
//
|
||||
#pragma omp target data map(tofrom : a[ : N]) map(tofrom : device_alloc)
|
||||
{
|
||||
#pragma omp target map(tofrom : device_alloc)
|
||||
{ device_alloc = &a[0]; }
|
||||
}
|
||||
|
||||
// CHECK: a used from unified memory.
|
||||
if (device_alloc == host_alloc)
|
||||
printf("a used from unified memory.\n");
|
||||
|
||||
//
|
||||
// map + target with close
|
||||
//
|
||||
device_alloc = 0;
|
||||
#pragma omp target data map(close, tofrom : a[ : N]) map(tofrom : device_alloc)
|
||||
{
|
||||
#pragma omp target map(tofrom : device_alloc)
|
||||
{ device_alloc = &a[0]; }
|
||||
}
|
||||
// CHECK: a copied to device.
|
||||
if (device_alloc != host_alloc)
|
||||
printf("a copied to device.\n");
|
||||
|
||||
//
|
||||
// map + use_device_ptr no close
|
||||
//
|
||||
device_alloc = 0;
|
||||
#pragma omp target data map(tofrom : a[ : N]) use_device_ptr(a)
|
||||
{ device_alloc = &a[0]; }
|
||||
|
||||
// CHECK: a used from unified memory with use_device_ptr.
|
||||
if (device_alloc == host_alloc)
|
||||
printf("a used from unified memory with use_device_ptr.\n");
|
||||
|
||||
//
|
||||
// map + use_device_ptr close
|
||||
//
|
||||
device_alloc = 0;
|
||||
#pragma omp target data map(close, tofrom : a[ : N]) use_device_ptr(a)
|
||||
{ device_alloc = &a[0]; }
|
||||
|
||||
// CHECK: a used from device memory with use_device_ptr.
|
||||
if (device_alloc != host_alloc)
|
||||
printf("a used from device memory with use_device_ptr.\n");
|
||||
|
||||
//
|
||||
// map enter/exit + close
|
||||
//
|
||||
device_alloc = 0;
|
||||
#pragma omp target enter data map(close, to : a[ : N])
|
||||
|
||||
#pragma omp target map(from : device_alloc)
|
||||
{ device_alloc = &a[0]; }
|
||||
|
||||
#pragma omp target exit data map(from : a[ : N])
|
||||
|
||||
// CHECK: a has been mapped to the device.
|
||||
if (device_alloc != host_alloc)
|
||||
printf("a has been mapped to the device.\n");
|
||||
|
||||
free(a);
|
||||
|
||||
// CHECK: Done!
|
||||
printf("Done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Various definitions copied from OpenMP RTL
|
||||
|
||||
extern void __tgt_register_requires(int64_t);
|
||||
|
||||
extern void __tgt_target_data_begin(int64_t device_id, int32_t arg_num,
|
||||
void **args_base, void **args,
|
||||
int64_t *arg_sizes, int64_t *arg_types);
|
||||
|
||||
extern void __tgt_target_data_end(int64_t device_id, int32_t arg_num,
|
||||
void **args_base, void **args,
|
||||
int64_t *arg_sizes, int64_t *arg_types);
|
||||
|
||||
// End of definitions copied from OpenMP RTL.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#pragma omp requires unified_shared_memory
|
||||
|
||||
#define N 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fails;
|
||||
void *host_alloc = 0, *device_alloc = 0;
|
||||
int *a = (int *)malloc(N * sizeof(int));
|
||||
|
||||
// Manual registration of requires flags for Clang versions
|
||||
// that do not support requires.
|
||||
__tgt_register_requires(8);
|
||||
|
||||
// Init
|
||||
for (int i = 0; i < N; ++i) {
|
||||
a[i] = 10;
|
||||
}
|
||||
host_alloc = &a[0];
|
||||
|
||||
// Dummy target region that ensures the runtime library is loaded when
|
||||
// the target data begin/end functions are manually called below.
|
||||
#pragma omp target
|
||||
{}
|
||||
|
||||
// Manual calls
|
||||
int device_id = omp_get_default_device();
|
||||
int arg_num = 1;
|
||||
void **args_base = (void **)&a;
|
||||
void **args = (void **)&a;
|
||||
int64_t arg_sizes[arg_num];
|
||||
|
||||
arg_sizes[0] = sizeof(int) * N;
|
||||
|
||||
int64_t arg_types[arg_num];
|
||||
|
||||
// Ox400 enables the CLOSE map type in the runtime:
|
||||
// OMP_TGT_MAPTYPE_CLOSE = 0x400
|
||||
// OMP_TGT_MAPTYPE_TO = 0x001
|
||||
arg_types[0] = 0x400 | 0x001;
|
||||
|
||||
device_alloc = host_alloc;
|
||||
|
||||
__tgt_target_data_begin(device_id, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
|
||||
#pragma omp target data use_device_ptr(a)
|
||||
{ device_alloc = a; }
|
||||
|
||||
__tgt_target_data_end(device_id, arg_num, args_base, args, arg_sizes,
|
||||
arg_types);
|
||||
|
||||
// CHECK: a was copied to the device
|
||||
if (device_alloc != host_alloc)
|
||||
printf("a was copied to the device\n");
|
||||
|
||||
free(a);
|
||||
|
||||
// CHECK: Done!
|
||||
printf("Done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
// UNSUPPORTED: clang-6, clang-7, clang-8, clang-9
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma omp requires unified_shared_memory
|
||||
|
||||
#define N 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fails;
|
||||
void *host_alloc, *device_alloc;
|
||||
void *host_data, *device_data;
|
||||
int *alloc = (int *)malloc(N * sizeof(int));
|
||||
int data[N];
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
alloc[i] = 10;
|
||||
data[i] = 1;
|
||||
}
|
||||
|
||||
host_data = &data[0];
|
||||
host_alloc = &alloc[0];
|
||||
|
||||
//
|
||||
// Test that updates on the device are not visible to host
|
||||
// when only a TO mapping is used.
|
||||
//
|
||||
#pragma omp target map(tofrom \
|
||||
: device_data, device_alloc) map(close, to \
|
||||
: alloc[:N], data \
|
||||
[:N])
|
||||
{
|
||||
device_data = &data[0];
|
||||
device_alloc = &alloc[0];
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
alloc[i] += 1;
|
||||
data[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: Address of alloc on device different from host address.
|
||||
if (device_alloc != host_alloc)
|
||||
printf("Address of alloc on device different from host address.\n");
|
||||
|
||||
// CHECK: Address of data on device different from host address.
|
||||
if (device_data != host_data)
|
||||
printf("Address of data on device different from host address.\n");
|
||||
|
||||
// On the host, check that the arrays have been updated.
|
||||
// CHECK: Alloc host values not updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (alloc[i] != 10)
|
||||
fails++;
|
||||
}
|
||||
printf("Alloc host values not updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
// CHECK: Data host values not updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (data[i] != 1)
|
||||
fails++;
|
||||
}
|
||||
printf("Data host values not updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
//
|
||||
// Test that updates on the device are visible on host
|
||||
// when a from is used.
|
||||
//
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
alloc[i] += 1;
|
||||
data[i] += 1;
|
||||
}
|
||||
|
||||
#pragma omp target map(close, tofrom : alloc[:N], data[:N])
|
||||
{
|
||||
// CHECK: Alloc device values are correct: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (alloc[i] != 11)
|
||||
fails++;
|
||||
}
|
||||
printf("Alloc device values are correct: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
// CHECK: Data device values are correct: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (data[i] != 2)
|
||||
fails++;
|
||||
}
|
||||
printf("Data device values are correct: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
// Update values on the device
|
||||
for (int i = 0; i < N; i++) {
|
||||
alloc[i] += 1;
|
||||
data[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: Alloc host values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (alloc[i] != 12)
|
||||
fails++;
|
||||
}
|
||||
printf("Alloc host values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
// CHECK: Data host values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (data[i] != 3)
|
||||
fails++;
|
||||
}
|
||||
printf("Data host values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
free(alloc);
|
||||
|
||||
// CHECK: Done!
|
||||
printf("Done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
|
||||
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
|
||||
|
||||
#include <stdio.h>
|
||||
#include <omp.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Various definitions copied from OpenMP RTL
|
||||
|
||||
extern void __tgt_register_requires(int64_t);
|
||||
|
||||
// End of definitions copied from OpenMP RTL.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#pragma omp requires unified_shared_memory
|
||||
|
||||
#define N 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fails;
|
||||
void *host_alloc, *device_alloc;
|
||||
void *host_data, *device_data;
|
||||
int *alloc = (int *)malloc(N * sizeof(int));
|
||||
int data[N];
|
||||
|
||||
// Manual registration of requires flags for Clang versions
|
||||
// that do not support requires.
|
||||
__tgt_register_requires(8);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
alloc[i] = 10;
|
||||
data[i] = 1;
|
||||
}
|
||||
|
||||
host_data = &data[0];
|
||||
host_alloc = &alloc[0];
|
||||
|
||||
// implicit mapping of data
|
||||
#pragma omp target map(tofrom : device_data, device_alloc)
|
||||
{
|
||||
device_data = &data[0];
|
||||
device_alloc = &alloc[0];
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
alloc[i] += 1;
|
||||
data[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: Address of alloc on device matches host address.
|
||||
if (device_alloc == host_alloc)
|
||||
printf("Address of alloc on device matches host address.\n");
|
||||
|
||||
// CHECK: Address of data on device matches host address.
|
||||
if (device_data == host_data)
|
||||
printf("Address of data on device matches host address.\n");
|
||||
|
||||
// On the host, check that the arrays have been updated.
|
||||
// CHECK: Alloc device values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (alloc[i] != 11)
|
||||
fails++;
|
||||
}
|
||||
printf("Alloc device values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
// CHECK: Data device values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (data[i] != 2)
|
||||
fails++;
|
||||
}
|
||||
printf("Data device values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
|
||||
//
|
||||
// Test that updates on the host snd on the device are both visible.
|
||||
//
|
||||
|
||||
// Update on the host.
|
||||
for (int i = 0; i < N; ++i) {
|
||||
alloc[i] += 1;
|
||||
data[i] += 1;
|
||||
}
|
||||
|
||||
#pragma omp target
|
||||
{
|
||||
// CHECK: Alloc host values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (alloc[i] != 12)
|
||||
fails++;
|
||||
}
|
||||
printf("Alloc host values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
// CHECK: Data host values updated: Succeeded
|
||||
fails = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (data[i] != 3)
|
||||
fails++;
|
||||
}
|
||||
printf("Data host values updated: %s\n",
|
||||
(fails == 0) ? "Succeeded" : "Failed");
|
||||
}
|
||||
|
||||
free(alloc);
|
||||
|
||||
printf("Done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
+13
-28
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -31,7 +30,7 @@ if(${OPENMP_STANDALONE_BUILD})
|
||||
# If adding a new architecture, take a look at cmake/LibompGetArchitecture.cmake
|
||||
libomp_get_architecture(LIBOMP_DETECTED_ARCH)
|
||||
set(LIBOMP_ARCH ${LIBOMP_DETECTED_ARCH} CACHE STRING
|
||||
"The architecture to build for (x86_64/i386/arm/ppc64/ppc64le/aarch64/mic/mips/mips64).")
|
||||
"The architecture to build for (x86_64/i386/arm/ppc64/ppc64le/aarch64/mic/mips/mips64/riscv64).")
|
||||
# Should assertions be enabled? They are on by default.
|
||||
set(LIBOMP_ENABLE_ASSERTIONS TRUE CACHE BOOL
|
||||
"enable assertions?")
|
||||
@@ -59,32 +58,21 @@ else() # Part of LLVM build
|
||||
set(LIBOMP_ARCH aarch64)
|
||||
elseif(LIBOMP_NATIVE_ARCH MATCHES "arm")
|
||||
set(LIBOMP_ARCH arm)
|
||||
elseif(LIBOMP_NATIVE_ARCH MATCHES "riscv64")
|
||||
set(LIBOMP_ARCH riscv64)
|
||||
else()
|
||||
# last ditch effort
|
||||
libomp_get_architecture(LIBOMP_ARCH)
|
||||
endif ()
|
||||
set(LIBOMP_ENABLE_ASSERTIONS ${LLVM_ENABLE_ASSERTIONS})
|
||||
endif()
|
||||
libomp_check_variable(LIBOMP_ARCH 32e x86_64 32 i386 arm ppc64 ppc64le aarch64 mic mips mips64)
|
||||
libomp_check_variable(LIBOMP_ARCH 32e x86_64 32 i386 arm ppc64 ppc64le aarch64 mic mips mips64 riscv64)
|
||||
|
||||
set(LIBOMP_LIB_TYPE normal CACHE STRING
|
||||
"Performance,Profiling,Stubs library (normal/profile/stubs)")
|
||||
libomp_check_variable(LIBOMP_LIB_TYPE normal profile stubs)
|
||||
set(LIBOMP_OMP_VERSION 50 CACHE STRING
|
||||
"The OpenMP version (50/45/40/30)")
|
||||
libomp_check_variable(LIBOMP_OMP_VERSION 50 45 40 30)
|
||||
# Set the OpenMP Year and Month assiociated with version
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 50 OR ${LIBOMP_OMP_VERSION} EQUAL 50)
|
||||
set(LIBOMP_OMP_YEAR_MONTH 201611)
|
||||
elseif(${LIBOMP_OMP_VERSION} GREATER 45 OR ${LIBOMP_OMP_VERSION} EQUAL 45)
|
||||
set(LIBOMP_OMP_YEAR_MONTH 201511)
|
||||
elseif(${LIBOMP_OMP_VERSION} GREATER 40 OR ${LIBOMP_OMP_VERSION} EQUAL 40)
|
||||
set(LIBOMP_OMP_YEAR_MONTH 201307)
|
||||
elseif(${LIBOMP_OMP_VERSION} GREATER 30 OR ${LIBOMP_OMP_VERSION} EQUAL 30)
|
||||
set(LIBOMP_OMP_YEAR_MONTH 201107)
|
||||
else()
|
||||
set(LIBOMP_OMP_YEAR_MONTH 200505)
|
||||
endif()
|
||||
set(LIBOMP_OMP_YEAR_MONTH 201611)
|
||||
set(LIBOMP_MIC_ARCH knc CACHE STRING
|
||||
"Intel(R) Many Integrated Core Architecture (Intel(R) MIC Architecture) (knf/knc). Ignored if not Intel(R) MIC Architecture build.")
|
||||
if("${LIBOMP_ARCH}" STREQUAL "mic")
|
||||
@@ -109,8 +97,6 @@ if(NOT DEFINED CMAKE_MACOSX_RPATH)
|
||||
endif()
|
||||
|
||||
# User specified flags. These are appended to the configured flags.
|
||||
set(LIBOMP_CFLAGS "" CACHE STRING
|
||||
"Appended user specified C compiler flags.")
|
||||
set(LIBOMP_CXXFLAGS "" CACHE STRING
|
||||
"Appended user specified C++ compiler flags.")
|
||||
set(LIBOMP_CPPFLAGS "" CACHE STRING
|
||||
@@ -156,6 +142,7 @@ set(PPC64 FALSE)
|
||||
set(MIC FALSE)
|
||||
set(MIPS64 FALSE)
|
||||
set(MIPS FALSE)
|
||||
set(RISCV64 FALSE)
|
||||
if("${LIBOMP_ARCH}" STREQUAL "i386" OR "${LIBOMP_ARCH}" STREQUAL "32") # IA-32 architecture
|
||||
set(IA32 TRUE)
|
||||
elseif("${LIBOMP_ARCH}" STREQUAL "x86_64" OR "${LIBOMP_ARCH}" STREQUAL "32e") # Intel(R) 64 architecture
|
||||
@@ -176,6 +163,8 @@ elseif("${LIBOMP_ARCH}" STREQUAL "mips") # MIPS architecture
|
||||
set(MIPS TRUE)
|
||||
elseif("${LIBOMP_ARCH}" STREQUAL "mips64") # MIPS64 architecture
|
||||
set(MIPS64 TRUE)
|
||||
elseif("${LIBOMP_ARCH}" STREQUAL "riscv64") # RISCV64 architecture
|
||||
set(RISCV64 TRUE)
|
||||
endif()
|
||||
|
||||
# Set some flags based on build_type
|
||||
@@ -214,7 +203,7 @@ endif()
|
||||
set(LIBOMP_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LIBOMP_SRC_DIR ${LIBOMP_BASE_DIR}/src)
|
||||
set(LIBOMP_TOOLS_DIR ${LIBOMP_BASE_DIR}/tools)
|
||||
set(LIBOMP_INC_DIR ${LIBOMP_SRC_DIR}/include/${LIBOMP_OMP_VERSION})
|
||||
set(LIBOMP_INC_DIR ${LIBOMP_SRC_DIR}/include)
|
||||
set(LIBOMP_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Enabling Fortran if it is needed
|
||||
@@ -302,7 +291,7 @@ endif()
|
||||
# OMPT-support defaults to ON for OpenMP 5.0+ and if the requirements in
|
||||
# cmake/config-ix.cmake are fulfilled.
|
||||
set(OMPT_DEFAULT FALSE)
|
||||
if ((${LIBOMP_OMP_VERSION} GREATER 49) AND (LIBOMP_HAVE_OMPT_SUPPORT) AND (NOT WIN32))
|
||||
if ((LIBOMP_HAVE_OMPT_SUPPORT) AND (NOT WIN32))
|
||||
set(OMPT_DEFAULT TRUE)
|
||||
endif()
|
||||
set(LIBOMP_OMPT_SUPPORT ${OMPT_DEFAULT} CACHE BOOL
|
||||
@@ -315,9 +304,6 @@ set(LIBOMP_OMPT_OPTIONAL TRUE CACHE BOOL
|
||||
if(LIBOMP_OMPT_SUPPORT AND (NOT LIBOMP_HAVE_OMPT_SUPPORT))
|
||||
libomp_error_say("OpenMP Tools Interface requested but not available in this implementation")
|
||||
endif()
|
||||
if(LIBOMP_OMPT_SUPPORT AND (${LIBOMP_OMP_VERSION} LESS 50))
|
||||
libomp_error_say("OpenMP Tools Interface only available with OpenMP 5.0, LIBOMP_OMP_VERSION is ${LIBOMP_OMP_VERSION}")
|
||||
endif()
|
||||
|
||||
# TSAN-support
|
||||
set(LIBOMP_TSAN_SUPPORT FALSE CACHE BOOL
|
||||
@@ -369,7 +355,6 @@ if(${OPENMP_STANDALONE_BUILD})
|
||||
libomp_say("Intel(R) MIC Architecture -- ${LIBOMP_MIC_ARCH}")
|
||||
endif()
|
||||
libomp_say("Build Type -- ${CMAKE_BUILD_TYPE}")
|
||||
libomp_say("OpenMP Version -- ${LIBOMP_OMP_VERSION}")
|
||||
libomp_say("Library Kind -- ${LIBOMP_LIBRARY_KIND}")
|
||||
libomp_say("Library Type -- ${LIBOMP_LIB_TYPE}")
|
||||
libomp_say("Fortran Modules -- ${LIBOMP_FORTRAN_MODULES}")
|
||||
|
||||
@@ -53,6 +53,7 @@ Architectures Supported
|
||||
* IBM(R) Power architecture (big endian)
|
||||
* IBM(R) Power architecture (little endian)
|
||||
* MIPS and MIPS64 architecture
|
||||
* RISCV64 architecture
|
||||
|
||||
Supported RTL Build Configurations
|
||||
==================================
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -29,4 +28,3 @@ function(libomp_get_definitions_flags cppflags)
|
||||
# CMake doesn't include CPPFLAGS from environment, but we will.
|
||||
set(${cppflags} ${cppflags_local} ${LIBOMP_CPPFLAGS} $ENV{CPPFLAGS} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -14,16 +13,13 @@
|
||||
|
||||
# Create the suffix for the export directory
|
||||
# - Only add to suffix when not a default value
|
||||
# - Example suffix: .deb.30.s1
|
||||
# final export directory: exports/lin_32e.deb.30.s1/lib
|
||||
# - These suffixes imply the build is a Debug, OpenMP 3.0, Stats-Gathering version of the library
|
||||
# - Example suffix: .deb.s1
|
||||
# final export directory: exports/lin_32e.deb.s1/lib
|
||||
# - These suffixes imply the build is a Debug, Stats-Gathering version of the library
|
||||
set(libomp_suffix)
|
||||
libomp_append(libomp_suffix .deb DEBUG_BUILD)
|
||||
libomp_append(libomp_suffix .dia RELWITHDEBINFO_BUILD)
|
||||
libomp_append(libomp_suffix .min MINSIZEREL_BUILD)
|
||||
if(NOT "${LIBOMP_OMP_VERSION}" STREQUAL "45")
|
||||
libomp_append(libomp_suffix .${LIBOMP_OMP_VERSION})
|
||||
endif()
|
||||
libomp_append(libomp_suffix .s1 LIBOMP_STATS)
|
||||
libomp_append(libomp_suffix .ompt LIBOMP_OMPT_SUPPORT)
|
||||
if(${LIBOMP_OMPT_SUPPORT})
|
||||
@@ -57,7 +53,7 @@ add_custom_command(TARGET omp POST_BUILD
|
||||
)
|
||||
if(${LIBOMP_OMPT_SUPPORT})
|
||||
add_custom_command(TARGET omp POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ompt.h ${LIBOMP_EXPORTS_CMN_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy omp-tools.h ${LIBOMP_EXPORTS_CMN_DIR}
|
||||
)
|
||||
endif()
|
||||
if(${LIBOMP_FORTRAN_MODULES})
|
||||
@@ -96,4 +92,3 @@ if(WIN32)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMPIMP_OUTPUT_DIRECTORY}/${LIBOMP_IMP_LIB_FILE} ${LIBOMP_EXPORTS_LIB_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -46,6 +45,8 @@ function(libomp_get_architecture return_arch)
|
||||
#error ARCHITECTURE=mips64
|
||||
#elif defined(__mips__) && !defined(__mips64)
|
||||
#error ARCHITECTURE=mips
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#error ARCHITECTURE=riscv64
|
||||
#else
|
||||
#error ARCHITECTURE=UnknownArchitecture
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -23,31 +22,24 @@ macro(libomp_setup_flags flags)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Gets flags common to both the C and C++ compiler
|
||||
function(libomp_get_c_and_cxxflags_common flags)
|
||||
# C++ compiler flags
|
||||
function(libomp_get_cxxflags cxxflags)
|
||||
set(flags_local)
|
||||
libomp_append(flags_local -fno-exceptions LIBOMP_HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
libomp_append(flags_local -fno-rtti LIBOMP_HAVE_FNO_RTTI_FLAG)
|
||||
libomp_append(flags_local -Wno-sign-compare LIBOMP_HAVE_WNO_SIGN_COMPARE_FLAG)
|
||||
libomp_append(flags_local -Wno-unused-function LIBOMP_HAVE_WNO_UNUSED_FUNCTION_FLAG)
|
||||
libomp_append(flags_local -Wno-unused-local-typedef LIBOMP_HAVE_WNO_UNUSED_LOCAL_TYPEDEF_FLAG)
|
||||
libomp_append(flags_local -Wno-unused-value LIBOMP_HAVE_WNO_UNUSED_VALUE_FLAG)
|
||||
libomp_append(flags_local -Wno-unused-variable LIBOMP_HAVE_WNO_UNUSED_VARIABLE_FLAG)
|
||||
libomp_append(flags_local -Wno-switch LIBOMP_HAVE_WNO_SWITCH_FLAG)
|
||||
libomp_append(flags_local -Wno-class-memaccess LIBOMP_HAVE_WNO_CLASS_MEMACCESS_FLAG)
|
||||
libomp_append(flags_local -Wno-covered-switch-default LIBOMP_HAVE_WNO_COVERED_SWITCH_DEFAULT_FLAG)
|
||||
libomp_append(flags_local -Wno-deprecated-register LIBOMP_HAVE_WNO_DEPRECATED_REGISTER_FLAG)
|
||||
libomp_append(flags_local -Wno-gnu-anonymous-struct LIBOMP_HAVE_WNO_GNU_ANONYMOUS_STRUCT_FLAG)
|
||||
libomp_append(flags_local -Wno-unknown-pragmas LIBOMP_HAVE_WNO_UNKNOWN_PRAGMAS_FLAG)
|
||||
libomp_append(flags_local -Wno-missing-field-initializers LIBOMP_HAVE_WNO_MISSING_FIELD_INITIALIZERS_FLAG)
|
||||
libomp_append(flags_local -Wno-missing-braces LIBOMP_HAVE_WNO_MISSING_BRACES_FLAG)
|
||||
libomp_append(flags_local -Wno-comment LIBOMP_HAVE_WNO_COMMENT_FLAG)
|
||||
libomp_append(flags_local -Wno-self-assign LIBOMP_HAVE_WNO_SELF_ASSIGN_FLAG)
|
||||
libomp_append(flags_local -Wno-vla-extension LIBOMP_HAVE_WNO_VLA_EXTENSION_FLAG)
|
||||
libomp_append(flags_local -Wno-format-pedantic LIBOMP_HAVE_WNO_FORMAT_PEDANTIC_FLAG)
|
||||
libomp_append(flags_local -Wno-frame-address LIBOMP_HAVE_WNO_FRAME_ADDRESS_FLAG)
|
||||
libomp_append(flags_local -Wno-strict-aliasing LIBOMP_HAVE_WNO_STRICT_ALIASING_FLAG)
|
||||
libomp_append(flags_local -Wstringop-overflow=0 LIBOMP_HAVE_WSTRINGOP_OVERFLOW_FLAG)
|
||||
libomp_append(flags_local -Wno-stringop-truncation LIBOMP_HAVE_WNO_STRINGOP_TRUNCATION_FLAG)
|
||||
libomp_append(flags_local -Wno-switch LIBOMP_HAVE_WNO_SWITCH_FLAG)
|
||||
libomp_append(flags_local -Wno-uninitialized LIBOMP_HAVE_WNO_UNINITIALIZED_FLAG)
|
||||
libomp_append(flags_local -Wno-unused-but-set-variable LIBOMP_HAVE_WNO_UNUSED_BUT_SET_VARIABLE_FLAG)
|
||||
libomp_append(flags_local /GS LIBOMP_HAVE_GS_FLAG)
|
||||
libomp_append(flags_local /EHsc LIBOMP_HAVE_EHSC_FLAG)
|
||||
libomp_append(flags_local /Oy- LIBOMP_HAVE_OY__FLAG)
|
||||
libomp_append(flags_local -mrtm LIBOMP_HAVE_MRTM_FLAG)
|
||||
# Intel(R) C Compiler flags
|
||||
libomp_append(flags_local /Qsafeseh LIBOMP_HAVE_QSAFESEH_FLAG)
|
||||
libomp_append(flags_local -Qoption,cpp,--extended_float_types LIBOMP_HAVE_EXTENDED_FLOAT_TYPES_FLAG)
|
||||
@@ -69,26 +61,7 @@ function(libomp_get_c_and_cxxflags_common flags)
|
||||
libomp_append(flags_local -ftls-model=initial-exec LIBOMP_HAVE_FTLS_MODEL_FLAG)
|
||||
libomp_append(flags_local "-opt-streaming-stores never" LIBOMP_HAVE_OPT_STREAMING_STORES_FLAG)
|
||||
endif()
|
||||
set(${flags} ${flags_local} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# C compiler flags
|
||||
function(libomp_get_cflags cflags)
|
||||
set(cflags_local)
|
||||
libomp_get_c_and_cxxflags_common(cflags_local)
|
||||
# flags only for the C Compiler
|
||||
libomp_append(cflags_local /TP LIBOMP_HAVE_TP_FLAG)
|
||||
libomp_append(cflags_local "-x c++" LIBOMP_HAVE_X_CPP_FLAG)
|
||||
set(cflags_local ${cflags_local} ${LIBOMP_CFLAGS})
|
||||
libomp_setup_flags(cflags_local)
|
||||
set(${cflags} ${cflags_local} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# C++ compiler flags
|
||||
function(libomp_get_cxxflags cxxflags)
|
||||
set(cxxflags_local)
|
||||
libomp_get_c_and_cxxflags_common(cxxflags_local)
|
||||
set(cxxflags_local ${cxxflags_local} ${LIBOMP_CXXFLAGS})
|
||||
set(cxxflags_local ${flags_local} ${LIBOMP_CXXFLAGS})
|
||||
libomp_setup_flags(cxxflags_local)
|
||||
set(${cxxflags} ${cxxflags_local} PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -153,9 +126,13 @@ function(libomp_get_libflags libflags)
|
||||
if(${IA32})
|
||||
libomp_append(libflags_local -lirc_pic LIBOMP_HAVE_IRC_PIC_LIBRARY)
|
||||
endif()
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "DragonFly|FreeBSD")
|
||||
libomp_append(libflags_local "-Wl,--no-as-needed" LIBOMP_HAVE_AS_NEEDED_FLAG)
|
||||
libomp_append(libflags_local "-lm")
|
||||
libomp_append(libflags_local "-Wl,--as-needed" LIBOMP_HAVE_AS_NEEDED_FLAG)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
libomp_append(libflags_local -lm)
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
endif()
|
||||
set(libflags_local ${libflags_local} ${LIBOMP_LIBFLAGS})
|
||||
libomp_setup_flags(libflags_local)
|
||||
set(${libflags} ${libflags_local} PARENT_SCOPE)
|
||||
@@ -189,18 +166,6 @@ function(libomp_get_gdflags gdflags)
|
||||
libomp_append(gdflags_local "-D stub" STUBS_LIBRARY)
|
||||
libomp_append(gdflags_local "-D HAVE_QUAD" LIBOMP_USE_QUAD_PRECISION)
|
||||
libomp_append(gdflags_local "-D USE_DEBUGGER" LIBOMP_USE_DEBUGGER)
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 50 OR ${LIBOMP_OMP_VERSION} EQUAL 50)
|
||||
libomp_append(gdflags_local "-D OMP_50")
|
||||
endif()
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 45 OR ${LIBOMP_OMP_VERSION} EQUAL 45)
|
||||
libomp_append(gdflags_local "-D OMP_45")
|
||||
endif()
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 40 OR ${LIBOMP_OMP_VERSION} EQUAL 40)
|
||||
libomp_append(gdflags_local "-D OMP_40")
|
||||
endif()
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 30 OR ${LIBOMP_OMP_VERSION} EQUAL 30)
|
||||
libomp_append(gdflags_local "-D OMP_30")
|
||||
endif()
|
||||
if(${DEBUG_BUILD} OR ${RELWITHDEBINFO_BUILD})
|
||||
libomp_append(gdflags_local "-D KMP_DEBUG")
|
||||
endif()
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -171,11 +170,14 @@ add_custom_command(
|
||||
add_custom_target(libomp-test-deps DEPENDS test-deps/.success)
|
||||
set(libomp_expected_library_deps)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
set(libomp_expected_library_deps libc.so.7 libthr.so.3)
|
||||
set(libomp_expected_library_deps libc.so.7 libthr.so.3 libm.so.5)
|
||||
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
set(libomp_expected_library_deps libc.so.12 libpthread.so.1 libm.so.0)
|
||||
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly")
|
||||
set(libomp_expected_library_deps libc.so.8 libpthread.so.0 libm.so.4)
|
||||
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
|
||||
elseif(APPLE)
|
||||
set(libomp_expected_library_deps /usr/lib/libSystem.B.dylib)
|
||||
elseif(WIN32)
|
||||
@@ -209,6 +211,9 @@ else()
|
||||
elseif(${MIPS} OR ${MIPS64})
|
||||
libomp_append(libomp_expected_library_deps libc.so.6)
|
||||
libomp_append(libomp_expected_library_deps ld.so.1)
|
||||
elseif(${RISCV64})
|
||||
libomp_append(libomp_expected_library_deps libc.so.6)
|
||||
libomp_append(libomp_expected_library_deps ld.so.1)
|
||||
endif()
|
||||
libomp_append(libomp_expected_library_deps libpthread.so.0 IF_FALSE STUBS_LIBRARY)
|
||||
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -106,6 +105,8 @@ function(libomp_get_legal_arch return_arch_string)
|
||||
set(${return_arch_string} "MIPS" PARENT_SCOPE)
|
||||
elseif(${MIPS64})
|
||||
set(${return_arch_string} "MIPS64" PARENT_SCOPE)
|
||||
elseif(${RISCV64})
|
||||
set(${return_arch_string} "RISCV64" PARENT_SCOPE)
|
||||
else()
|
||||
set(${return_arch_string} "${LIBOMP_ARCH}" PARENT_SCOPE)
|
||||
libomp_warning_say("libomp_get_legal_arch(): Warning: Unknown architecture: Using ${LIBOMP_ARCH}")
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
@@ -46,39 +45,32 @@ function(libomp_check_architecture_flag flag retval)
|
||||
set(${retval} ${${retval}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Checking C, CXX, Linker Flags
|
||||
# Checking CXX, Linker Flags
|
||||
check_cxx_compiler_flag(-fno-exceptions LIBOMP_HAVE_FNO_EXCEPTIONS_FLAG)
|
||||
check_cxx_compiler_flag(-fno-rtti LIBOMP_HAVE_FNO_RTTI_FLAG)
|
||||
check_c_compiler_flag("-x c++" LIBOMP_HAVE_X_CPP_FLAG)
|
||||
check_c_compiler_flag(-Wunused-function LIBOMP_HAVE_WNO_UNUSED_FUNCTION_FLAG)
|
||||
check_c_compiler_flag(-Wunused-local-typedef LIBOMP_HAVE_WNO_UNUSED_LOCAL_TYPEDEF_FLAG)
|
||||
check_c_compiler_flag(-Wunused-value LIBOMP_HAVE_WNO_UNUSED_VALUE_FLAG)
|
||||
check_c_compiler_flag(-Wunused-variable LIBOMP_HAVE_WNO_UNUSED_VARIABLE_FLAG)
|
||||
check_c_compiler_flag(-Wswitch LIBOMP_HAVE_WNO_SWITCH_FLAG)
|
||||
check_c_compiler_flag(-Wcovered-switch-default LIBOMP_HAVE_WNO_COVERED_SWITCH_DEFAULT_FLAG)
|
||||
check_c_compiler_flag(-Wdeprecated-register LIBOMP_HAVE_WNO_DEPRECATED_REGISTER_FLAG)
|
||||
check_c_compiler_flag(-Wsign-compare LIBOMP_HAVE_WNO_SIGN_COMPARE_FLAG)
|
||||
check_c_compiler_flag(-Wgnu-anonymous-struct LIBOMP_HAVE_WNO_GNU_ANONYMOUS_STRUCT_FLAG)
|
||||
check_c_compiler_flag(-Wunknown-pragmas LIBOMP_HAVE_WNO_UNKNOWN_PRAGMAS_FLAG)
|
||||
check_c_compiler_flag(-Wmissing-field-initializers LIBOMP_HAVE_WNO_MISSING_FIELD_INITIALIZERS_FLAG)
|
||||
check_c_compiler_flag(-Wmissing-braces LIBOMP_HAVE_WNO_MISSING_BRACES_FLAG)
|
||||
check_c_compiler_flag(-Wcomment LIBOMP_HAVE_WNO_COMMENT_FLAG)
|
||||
check_c_compiler_flag(-Wself-assign LIBOMP_HAVE_WNO_SELF_ASSIGN_FLAG)
|
||||
check_c_compiler_flag(-Wvla-extension LIBOMP_HAVE_WNO_VLA_EXTENSION_FLAG)
|
||||
check_c_compiler_flag(-Wformat-pedantic LIBOMP_HAVE_WNO_FORMAT_PEDANTIC_FLAG)
|
||||
check_c_compiler_flag(-Wstringop-overflow=0 LIBOMP_HAVE_WSTRINGOP_OVERFLOW_FLAG)
|
||||
check_c_compiler_flag(-msse2 LIBOMP_HAVE_MSSE2_FLAG)
|
||||
check_c_compiler_flag(-ftls-model=initial-exec LIBOMP_HAVE_FTLS_MODEL_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-class-memaccess LIBOMP_HAVE_WNO_CLASS_MEMACCESS_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-covered-switch-default LIBOMP_HAVE_WNO_COVERED_SWITCH_DEFAULT_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-frame-address LIBOMP_HAVE_WNO_FRAME_ADDRESS_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-strict-aliasing LIBOMP_HAVE_WNO_STRICT_ALIASING_FLAG)
|
||||
check_cxx_compiler_flag(-Wstringop-overflow=0 LIBOMP_HAVE_WSTRINGOP_OVERFLOW_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-stringop-truncation LIBOMP_HAVE_WNO_STRINGOP_TRUNCATION_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-switch LIBOMP_HAVE_WNO_SWITCH_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-uninitialized LIBOMP_HAVE_WNO_UNINITIALIZED_FLAG)
|
||||
check_cxx_compiler_flag(-Wno-unused-but-set-variable LIBOMP_HAVE_WNO_UNUSED_BUT_SET_VARIABLE_FLAG)
|
||||
check_cxx_compiler_flag(-msse2 LIBOMP_HAVE_MSSE2_FLAG)
|
||||
check_cxx_compiler_flag(-ftls-model=initial-exec LIBOMP_HAVE_FTLS_MODEL_FLAG)
|
||||
libomp_check_architecture_flag(-mmic LIBOMP_HAVE_MMIC_FLAG)
|
||||
libomp_check_architecture_flag(-m32 LIBOMP_HAVE_M32_FLAG)
|
||||
if(WIN32)
|
||||
# Check Windows MSVC style flags.
|
||||
check_c_compiler_flag(/TP LIBOMP_HAVE_TP_FLAG)
|
||||
check_cxx_compiler_flag(/EHsc LIBOMP_HAVE_EHSC_FLAG)
|
||||
check_cxx_compiler_flag(/GS LIBOMP_HAVE_GS_FLAG)
|
||||
check_cxx_compiler_flag(/Oy- LIBOMP_HAVE_Oy__FLAG)
|
||||
check_cxx_compiler_flag(/arch:SSE2 LIBOMP_HAVE_ARCH_SSE2_FLAG)
|
||||
check_cxx_compiler_flag(/Qsafeseh LIBOMP_HAVE_QSAFESEH_FLAG)
|
||||
if(MSVC)
|
||||
# Check Windows MSVC style flags.
|
||||
check_cxx_compiler_flag(/EHsc LIBOMP_HAVE_EHSC_FLAG)
|
||||
check_cxx_compiler_flag(/GS LIBOMP_HAVE_GS_FLAG)
|
||||
check_cxx_compiler_flag(/Oy- LIBOMP_HAVE_Oy__FLAG)
|
||||
check_cxx_compiler_flag(/arch:SSE2 LIBOMP_HAVE_ARCH_SSE2_FLAG)
|
||||
check_cxx_compiler_flag(/Qsafeseh LIBOMP_HAVE_QSAFESEH_FLAG)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-mrtm LIBOMP_HAVE_MRTM_FLAG)
|
||||
# It is difficult to create a dummy masm assembly file
|
||||
# and then check the MASM assembler to see if these flags exist and work,
|
||||
# so we assume they do for Windows.
|
||||
@@ -243,7 +235,8 @@ else()
|
||||
# (LIBOMP_ARCH STREQUAL arm) OR
|
||||
(LIBOMP_ARCH STREQUAL aarch64) OR
|
||||
(LIBOMP_ARCH STREQUAL ppc64le) OR
|
||||
(LIBOMP_ARCH STREQUAL ppc64))
|
||||
(LIBOMP_ARCH STREQUAL ppc64) OR
|
||||
(LIBOMP_ARCH STREQUAL riscv64))
|
||||
AND # OS supported?
|
||||
((WIN32 AND LIBOMP_HAVE_PSAPI) OR APPLE OR (NOT WIN32 AND LIBOMP_HAVE_WEAK_ATTRIBUTE)))
|
||||
set(LIBOMP_HAVE_OMPT_SUPPORT TRUE)
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.txt for details.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
+25
-25
@@ -1,19 +1,18 @@
|
||||
#
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#//
|
||||
#// The LLVM Compiler Infrastructure
|
||||
#//
|
||||
#// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
#// Source Licenses. See LICENSE.txt for details.
|
||||
#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
#// See https://llvm.org/LICENSE.txt for license information.
|
||||
#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#//
|
||||
#//===----------------------------------------------------------------------===//
|
||||
#
|
||||
|
||||
# Configure omp.h, kmp_config.h and ompt.h if necessary
|
||||
# Configure omp.h, kmp_config.h and omp-tools.h if necessary
|
||||
configure_file(${LIBOMP_INC_DIR}/omp.h.var omp.h @ONLY)
|
||||
configure_file(kmp_config.h.cmake kmp_config.h @ONLY)
|
||||
if(${LIBOMP_OMPT_SUPPORT})
|
||||
configure_file(${LIBOMP_INC_DIR}/ompt.h.var ompt.h @ONLY)
|
||||
configure_file(${LIBOMP_INC_DIR}/omp-tools.h.var omp-tools.h @ONLY)
|
||||
endif()
|
||||
|
||||
# Generate message catalog files: kmp_i18n_id.inc and kmp_i18n_default.inc
|
||||
@@ -32,7 +31,7 @@ add_custom_command(
|
||||
|
||||
# Set the -D definitions for all sources
|
||||
# UNICODE and _UNICODE are set in LLVM's CMake system. They affect the
|
||||
# ittnotify code and should only be set when compiling ittnotify_static.c
|
||||
# ittnotify code and should only be set when compiling ittnotify_static.cpp
|
||||
# on Windows (done below).
|
||||
# TODO: Fix the UNICODE usage in ittnotify code for Windows.
|
||||
remove_definitions(-DUNICODE -D_UNICODE)
|
||||
@@ -52,11 +51,10 @@ if(${LIBOMP_USE_HWLOC})
|
||||
endif()
|
||||
|
||||
# Getting correct source files to build library
|
||||
set(LIBOMP_CFILES)
|
||||
set(LIBOMP_CXXFILES)
|
||||
set(LIBOMP_ASMFILES)
|
||||
if(${STUBS_LIBRARY})
|
||||
set(LIBOMP_CFILES kmp_stub.cpp)
|
||||
if(STUBS_LIBRARY)
|
||||
set(LIBOMP_CXXFILES kmp_stub.cpp)
|
||||
else()
|
||||
# Get C++ files
|
||||
set(LIBOMP_CXXFILES
|
||||
@@ -74,7 +72,6 @@ else()
|
||||
kmp_settings.cpp
|
||||
kmp_str.cpp
|
||||
kmp_tasking.cpp
|
||||
kmp_taskq.cpp
|
||||
kmp_threadprivate.cpp
|
||||
kmp_utility.cpp
|
||||
kmp_barrier.cpp
|
||||
@@ -95,14 +92,12 @@ else()
|
||||
libomp_append(LIBOMP_CXXFILES kmp_gsupport.cpp)
|
||||
libomp_append(LIBOMP_ASMFILES z_Linux_asm.S) # Unix assembly file
|
||||
endif()
|
||||
libomp_append(LIBOMP_CFILES thirdparty/ittnotify/ittnotify_static.c LIBOMP_USE_ITT_NOTIFY)
|
||||
libomp_append(LIBOMP_CXXFILES thirdparty/ittnotify/ittnotify_static.cpp LIBOMP_USE_ITT_NOTIFY)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_debugger.cpp LIBOMP_USE_DEBUGGER)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_stats.cpp LIBOMP_STATS)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_stats_timing.cpp LIBOMP_STATS)
|
||||
if(${LIBOMP_OMP_VERSION} GREATER 40 OR ${LIBOMP_OMP_VERSION} EQUAL 40)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_taskdeps.cpp)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_cancel.cpp)
|
||||
endif()
|
||||
libomp_append(LIBOMP_CXXFILES kmp_taskdeps.cpp)
|
||||
libomp_append(LIBOMP_CXXFILES kmp_cancel.cpp)
|
||||
endif()
|
||||
# Files common to stubs and normal library
|
||||
libomp_append(LIBOMP_CXXFILES kmp_ftn_cdecl.cpp)
|
||||
@@ -111,16 +106,14 @@ libomp_append(LIBOMP_CXXFILES kmp_version.cpp)
|
||||
libomp_append(LIBOMP_CXXFILES ompt-general.cpp IF_TRUE LIBOMP_OMPT_SUPPORT)
|
||||
libomp_append(LIBOMP_CXXFILES tsan_annotations.cpp IF_TRUE LIBOMP_TSAN_SUPPORT)
|
||||
|
||||
set(LIBOMP_SOURCE_FILES ${LIBOMP_CFILES} ${LIBOMP_CXXFILES} ${LIBOMP_ASMFILES})
|
||||
set(LIBOMP_SOURCE_FILES ${LIBOMP_CXXFILES} ${LIBOMP_ASMFILES})
|
||||
# For Windows, there is a resource file (.rc -> .res) that is also compiled
|
||||
libomp_append(LIBOMP_SOURCE_FILES libomp.rc WIN32)
|
||||
|
||||
# Get compiler and assembler flags
|
||||
libomp_get_cflags(LIBOMP_CONFIGURED_CFLAGS)
|
||||
libomp_get_cxxflags(LIBOMP_CONFIGURED_CXXFLAGS)
|
||||
libomp_get_asmflags(LIBOMP_CONFIGURED_ASMFLAGS)
|
||||
# Set the compiler flags for each type of source
|
||||
set_source_files_properties(${LIBOMP_CFILES} PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_CFLAGS}")
|
||||
set_source_files_properties(${LIBOMP_CXXFILES} PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_CXXFLAGS}")
|
||||
set_source_files_properties(${LIBOMP_ASMFILES} PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_ASMFLAGS}")
|
||||
# Let the compiler handle the assembly files on Unix-like systems
|
||||
@@ -195,12 +188,12 @@ if(WIN32)
|
||||
libomp_append(LIBOMP_MASM_DEFINITIONS "-DOMPT_SUPPORT" IF_TRUE_1_0 LIBOMP_OMPT_SUPPORT)
|
||||
libomp_list_to_string("${LIBOMP_MASM_DEFINITIONS}" LIBOMP_MASM_DEFINITIONS)
|
||||
set_property(SOURCE z_Windows_NT-586_asm.asm APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBOMP_MASM_DEFINITIONS}")
|
||||
set_source_files_properties(thirdparty/ittnotify/ittnotify_static.c PROPERTIES COMPILE_DEFINITIONS "UNICODE")
|
||||
set_source_files_properties(thirdparty/ittnotify/ittnotify_static.cpp PROPERTIES COMPILE_DEFINITIONS "UNICODE")
|
||||
|
||||
# Create Windows import library
|
||||
# the import library is "re-linked" to include kmp_import.cpp which prevents
|
||||
# linking of both Visual Studio OpenMP and newly built OpenMP
|
||||
set_source_files_properties(kmp_import.cpp PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_CFLAGS}")
|
||||
set_source_files_properties(kmp_import.cpp PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_CXXFLAGS}")
|
||||
set(LIBOMP_IMP_LIB_FILE ${LIBOMP_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(LIBOMP_GENERATED_IMP_LIB_FILENAME ${LIBOMP_LIB_FILE}${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set_target_properties(omp PROPERTIES
|
||||
@@ -241,6 +234,11 @@ if(${LIBOMP_FORTRAN_MODULES})
|
||||
configure_file(${LIBOMP_INC_DIR}/omp_lib.h.var omp_lib.h @ONLY)
|
||||
configure_file(${LIBOMP_INC_DIR}/omp_lib.f.var omp_lib.f @ONLY)
|
||||
configure_file(${LIBOMP_INC_DIR}/omp_lib.f90.var omp_lib.f90 @ONLY)
|
||||
# Workaround for gfortran to build modules with the
|
||||
# omp_sched_monotonic integer parameter
|
||||
if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||
set(ADDITIONAL_Fortran_FLAGS "-fno-range-check")
|
||||
endif()
|
||||
add_custom_target(libomp-mod ALL DEPENDS omp_lib.mod omp_lib_kinds.mod)
|
||||
libomp_get_fflags(LIBOMP_CONFIGURED_FFLAGS)
|
||||
if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
|
||||
@@ -250,7 +248,8 @@ if(${LIBOMP_FORTRAN_MODULES})
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT omp_lib.mod omp_lib_kinds.mod
|
||||
COMMAND ${CMAKE_Fortran_COMPILER} -c ${LIBOMP_CONFIGURED_FFLAGS} ${LIBOMP_FORTRAN_SOURCE_FILE}
|
||||
COMMAND ${CMAKE_Fortran_COMPILER} -c ${ADDITIONAL_Fortran_FLAGS}
|
||||
${LIBOMP_CONFIGURED_FFLAGS} ${LIBOMP_FORTRAN_SOURCE_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${LIBOMP_FORTRAN_SOURCE_FILE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/omp_lib.h
|
||||
)
|
||||
@@ -297,7 +296,7 @@ if(WIN32)
|
||||
install(CODE "execute_process(COMMAND \"\${CMAKE_COMMAND}\" -E copy \"${LIBOMP_LIB_FILE}\"
|
||||
\"${alias}${LIBOMP_LIBRARY_SUFFIX}\" WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/bin)")
|
||||
install(CODE "execute_process(COMMAND \"\${CMAKE_COMMAND}\" -E copy \"${LIBOMP_IMP_LIB_FILE}\"
|
||||
\"${alias}${LIBOMP_LIBRARY_SUFFIX}\" WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${OPENMP_INSTALL_LIBDIR})")
|
||||
\"${alias}${CMAKE_STATIC_LIBRARY_SUFFIX}\" WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${OPENMP_INSTALL_LIBDIR})")
|
||||
endforeach()
|
||||
else()
|
||||
|
||||
@@ -319,7 +318,9 @@ install(
|
||||
DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH}
|
||||
)
|
||||
if(${LIBOMP_OMPT_SUPPORT})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ompt.h DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/omp-tools.h DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH})
|
||||
# install under legacy name ompt.h
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/omp-tools.h DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH} RENAME ompt.h)
|
||||
endif()
|
||||
if(${LIBOMP_FORTRAN_MODULES})
|
||||
install(FILES
|
||||
@@ -329,4 +330,3 @@ if(${LIBOMP_FORTRAN_MODULES})
|
||||
DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user