From e2a73b49cfb726f03252bee4a5979d2b3d2c4e75 Mon Sep 17 00:00:00 2001 From: nicehashdev Date: Fri, 4 Nov 2016 17:01:00 +0100 Subject: [PATCH 01/15] cv=1 default, text bug fix --- nheqminer/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index ce818dae9..8f0c76dde 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -49,7 +49,7 @@ namespace keywords = boost::log::keywords; int use_avx = 0; int use_avx2 = 0; -int use_old_cuda = 0; +int use_old_cuda = 1; int use_old_xmp = 0; // _XMP @@ -96,7 +96,7 @@ void print_help() std::cout << std::endl; std::cout << "NVIDIA CUDA settings" << std::endl; std::cout << "\t-ci\t\tCUDA info" << std::endl; - std::cout << "\t-cv [ver]\tSet CUDA version (0 = default 8.0, 1 = 7.5)" << std::endl; + std::cout << "\t-cv [ver]\tSet CUDA version (0 = 8.0, 1 = 7.5)" << std::endl; std::cout << "\t-cd [devices]\tEnable CUDA mining on spec. devices" << std::endl; std::cout << "\t-cb [blocks]\tNumber of blocks" << std::endl; std::cout << "\t-ct [tpb]\tNumber of threads per block" << std::endl; @@ -105,7 +105,7 @@ void print_help() std::cout << "OpenCL settings" << std::endl; std::cout << "\t-oi\t\tOpenCL info" << std::endl; std::cout << "\t-ov [ver]\tSet OpenCL solver (0 = silentarmy, 1 = xmp)" << std::endl; - std::cout << "\t-op [devices]\tSet OpenCL platform to selecd platform devices (-od)" << std::endl; + std::cout << "\t-op [platf]\tSet OpenCL platform to selecd platform devices (-od)" << std::endl; std::cout << "\t-od [devices]\tEnable OpenCL mining on spec. devices (specify plafrom number first -op)" << std::endl; std::cout << "\t-ot [threads]\tSet number of threads per device" << std::endl; //std::cout << "\t-cb [blocks]\tNumber of blocks" << std::endl; From 519cdf028c6dd9f480931c2cd1ad3a8fcaddeee8 Mon Sep 17 00:00:00 2001 From: kenshirothefist Date: Sun, 6 Nov 2016 23:45:48 +0100 Subject: [PATCH 02/15] README fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b4a9ad79..b86402af9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Working solvers CPU_TROMP, CPU_XENONCAT, CUDA_TROMP, OCL_XMP, OCL_SILENTARMY - `git clone -b Linux https://github.com/nicehash/nheqminer.git` - `cd nheqminer/cpu_xenoncat/Linux/asm/` - `sh assemble.sh` - - `cd ../../../Linux_cmake/nheqminer_cpu` + - `cd ../../../Linux_cmake/nheqminer_cpu_xenoncat` - `cmake .` - `make -j $(nproc)` From 49630074841c87654f14dee3eadaa75a4bef0e79 Mon Sep 17 00:00:00 2001 From: nicehashdev Date: Wed, 11 Jan 2017 18:56:27 +0100 Subject: [PATCH 03/15] added cuda_djezo solver --- cuda_djezo/LICENSE | 675 ++++++++ cuda_djezo/cuda_djezo.cpp | 128 ++ cuda_djezo/cuda_djezo.hpp | 46 + cuda_djezo/cuda_djezo.vcxproj | 117 ++ cuda_djezo/eqcuda.hpp | 99 ++ cuda_djezo/equi_miner.cu | 2159 +++++++++++++++++++++++++ nheqminer/libstratum/ZcashStratum.cpp | 39 +- nheqminer/libstratum/ZcashStratum.h | 10 +- nheqminer/main.cpp | 12 +- nheqminer/nheqminer.sln | 58 +- nheqminer/nheqminer.vcxproj | 3 +- nheqminer/nheqminer.vcxproj.filters | 3 + nheqminer/speed.hpp | 2 +- nheqminer/version.h | 2 +- 14 files changed, 3279 insertions(+), 74 deletions(-) create mode 100644 cuda_djezo/LICENSE create mode 100644 cuda_djezo/cuda_djezo.cpp create mode 100644 cuda_djezo/cuda_djezo.hpp create mode 100644 cuda_djezo/cuda_djezo.vcxproj create mode 100644 cuda_djezo/eqcuda.hpp create mode 100644 cuda_djezo/equi_miner.cu diff --git a/cuda_djezo/LICENSE b/cuda_djezo/LICENSE new file mode 100644 index 000000000..bb7b082bf --- /dev/null +++ b/cuda_djezo/LICENSE @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2016-2017 NiceHash (www.nicehash.com) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cuda_djezo/cuda_djezo.cpp b/cuda_djezo/cuda_djezo.cpp new file mode 100644 index 000000000..30d672e89 --- /dev/null +++ b/cuda_djezo/cuda_djezo.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include + +#include "cuda_djezo.hpp" + +struct proof; +#include "eqcuda.hpp" + + +cuda_djezo::cuda_djezo(int platf_id, int dev_id) +{ + device_id = dev_id; + getinfo(0, dev_id, m_gpu_name, m_sm_count, m_version); + + combo_mode = 1; + + int major, minor; + std::string::size_type n = m_version.find("."); + if (n != std::string::npos) + { + major = atoi(m_version.substr(0, n).c_str()); + minor = atoi(m_version.substr(n + 1, m_version.length() - n - 1).c_str()); + + if (major < 5) + { + throw std::runtime_error("Only CUDA devices with SM 5.0 and higher are supported."); + } + else if (major == 5 && minor == 0) + { + combo_mode = 2; + } + } + else + throw std::runtime_error("Uknown Compute/SM version."); +} + + +std::string cuda_djezo::getdevinfo() +{ + return m_gpu_name + " (#" + std::to_string(device_id) + ") M=" + std::to_string(combo_mode); +} + + +int cuda_djezo::getcount() +{ + int device_count; + checkCudaErrors(cudaGetDeviceCount(&device_count)); + return device_count; +} + +void cuda_djezo::getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version) +{ + //int runtime_version; + //checkCudaErrors(cudaRuntimeGetVersion(&runtime_version)); + + cudaDeviceProp device_props; + + checkCudaErrors(cudaGetDeviceProperties(&device_props, d_id)); + + gpu_name = device_props.name; + sm_count = device_props.multiProcessorCount; + version = std::to_string(device_props.major) + "." + std::to_string(device_props.minor); +} + + +void cuda_djezo::start(cuda_djezo& device_context) +{ + switch (device_context.combo_mode) + { +#ifdef CONFIG_MODE_2 + case 2: + device_context.context = new eq_cuda_context(device_context.device_id); + break; +#endif +#ifdef CONFIG_MODE_3 + case 3: + device_context.context = new eq_cuda_context(device_context.device_id); + break; +#endif + default: + device_context.context = new eq_cuda_context(device_context.device_id); + break; + } +} + +void cuda_djezo::stop(cuda_djezo& device_context) +{ + if (device_context.context) + { + delete device_context.context; + device_context.context = nullptr; + } +} + +void cuda_djezo::solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef, + cuda_djezo& device_context) +{ + device_context.context->solve(tequihash_header, + tequihash_header_len, + nonce, + nonce_len, + cancelf, + solutionf, + hashdonef); +} + + +void eq_cuda_context_interface::solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef) +{ +} + + +eq_cuda_context_interface::~eq_cuda_context_interface() { } \ No newline at end of file diff --git a/cuda_djezo/cuda_djezo.hpp b/cuda_djezo/cuda_djezo.hpp new file mode 100644 index 000000000..1843c462a --- /dev/null +++ b/cuda_djezo/cuda_djezo.hpp @@ -0,0 +1,46 @@ +#pragma once + +#ifdef _LIB +#define DLL_CUDA_DJEZO __declspec(dllexport) +#else +#define DLL_CUDA_DJEZO +#endif + +struct eq_cuda_context_interface; + +struct DLL_CUDA_DJEZO cuda_djezo +{ + int threadsperblock; + int blocks; + int device_id; + int combo_mode; + eq_cuda_context_interface* context; + + cuda_djezo(int platf_id, int dev_id); + + std::string getdevinfo(); + + static int getcount(); + + static void getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version); + + static void start(cuda_djezo& device_context); + + static void stop(cuda_djezo& device_context); + + static void solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef, + cuda_djezo& device_context); + + std::string getname() { return "CUDA-DJEZO"; } + +private: + std::string m_gpu_name; + std::string m_version; + int m_sm_count; +}; \ No newline at end of file diff --git a/cuda_djezo/cuda_djezo.vcxproj b/cuda_djezo/cuda_djezo.vcxproj new file mode 100644 index 000000000..759a7cf20 --- /dev/null +++ b/cuda_djezo/cuda_djezo.vcxproj @@ -0,0 +1,117 @@ + + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + {268B10AD-D845-498B-8663-AB8911CA2039} + cuda_djezo + $(CUDA_PATH_V8_0) + + + + DynamicLibrary + true + MultiByte + v120 + + + DynamicLibrary + false + true + MultiByte + v120 + + + + + + + + + + + + + + true + + + + Level3 + Disabled + WIN32;WIN64;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + 4334;4316;4244;4996;4251; + ..\3rdparty\include;%(AdditionalIncludeDirectories) + + + true + Console + cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)" +copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)" + + + 64 + compute_61,sm_61;compute_52,sm_52;compute_50,sm_50; + true + false + + + + + Level3 + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + 4334;4316;4244;4996;4251; + ..\3rdparty\include;%(AdditionalIncludeDirectories) + + + true + true + true + Console + cudart.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + echo copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)" +copy "$(CudaToolkitBinDir)\cudart*.dll" "$(OutDir)" + + + 64 + compute_50,sm_50;compute_52,sm_52;compute_61,sm_61; + true + –Xptxas –dlcm=ca -Xptxas -dscm=cs %(AdditionalOptions) + + + + + + + \ No newline at end of file diff --git a/cuda_djezo/eqcuda.hpp b/cuda_djezo/eqcuda.hpp new file mode 100644 index 000000000..48d663a45 --- /dev/null +++ b/cuda_djezo/eqcuda.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "cuda.h" +#include "cuda_runtime.h" +#include "device_launch_parameters.h" +#include "device_functions_decls.h" +#include "../cpu_tromp/blake2/blake2.h" +#include "cuda_djezo.hpp" + +#ifdef WIN32 +#define _SNPRINTF _snprintf +#else +#include +#define _SNPRINTF snprintf +#endif + +#define checkCudaErrors(call) \ +do { \ + cudaError_t err = call; \ + if (cudaSuccess != err) { \ + char errorBuff[512]; \ + _SNPRINTF(errorBuff, sizeof(errorBuff) - 1, \ + "CUDA error '%s' in func '%s' line %d", \ + cudaGetErrorString(err), __FUNCTION__, __LINE__); \ + throw std::runtime_error(errorBuff); \ + } \ +} while (0) + +#define checkCudaDriverErrors(call) \ +do { \ + CUresult err = call; \ + if (CUDA_SUCCESS != err) { \ + char errorBuff[512]; \ + _SNPRINTF(errorBuff, sizeof(errorBuff) - 1, \ + "CUDA error DRIVER: '%d' in func '%s' line %d", \ + err, __FUNCTION__, __LINE__); \ + throw std::runtime_error(errorBuff); \ + } \ +} while (0) + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef unsigned char uchar; + +struct packer_default; +struct packer_cantor; + +#define MAXREALSOLS 9 + +struct scontainerreal +{ + u32 sols[MAXREALSOLS][512]; + u32 nsols; +}; + +template +struct equi; + +struct eq_cuda_context_interface +{ + virtual ~eq_cuda_context_interface(); + + virtual void solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef); +}; + + +template +struct eq_cuda_context : public eq_cuda_context_interface +{ + int threadsperblock; + int totalblocks; + int device_id; + equi* device_eq; + scontainerreal* solutions; + CUcontext pctx; + + eq_cuda_context(int id); + ~eq_cuda_context(); + + void solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef); +}; + +#define CONFIG_MODE_1 9, 1248, 12, 640, packer_cantor + +#define CONFIG_MODE_2 8, 640, 12, 512, packer_default \ No newline at end of file diff --git a/cuda_djezo/equi_miner.cu b/cuda_djezo/equi_miner.cu new file mode 100644 index 000000000..b3401b2bb --- /dev/null +++ b/cuda_djezo/equi_miner.cu @@ -0,0 +1,2159 @@ +/* + Equihash solver created by djeZo (l33tsoftw@gmail.com) for NiceHash + + Based on CUDA solver by John Tromp released under MIT license. + + Some helper functions taken out of OpenCL solver by Marc Bevand + released under MIT license. + + cuda_djezo solver is released by NiceHash (www.nicehash.com) under + GPL 3.0 license. If you don't have a copy, you can obtain one from + https://www.gnu.org/licenses/gpl-3.0.txt +*/ + +/* +The MIT License (MIT) + +Copyright (c) 2016 John Tromp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software, and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +/* +The MIT License (MIT) + +Copyright (c) 2016 Marc Bevand + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software, and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifdef WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "eqcuda.hpp" +#include "sm_32_intrinsics.h" + +#define WN 200 +#define WK 9 +#define NDIGITS (WK+1) +#define DIGITBITS (WN/(NDIGITS)) +#define PROOFSIZE (1< +#include +#define __launch_bounds__(max_tpb, min_blocks) +#define __CUDA_ARCH__ 520 +uint32_t __byte_perm(uint32_t x, uint32_t y, uint32_t z); +uint32_t __byte_perm(uint32_t x, uint32_t y, uint32_t z); +uint32_t __shfl(uint32_t x, uint32_t y, uint32_t z); +uint32_t atomicExch(uint32_t *x, uint32_t y); +uint32_t atomicAdd(uint32_t *x, uint32_t y); +void __syncthreads(void); +void __threadfence(void); +void __threadfence_block(void); +uint32_t __ldg(const uint32_t* address); +uint64_t __ldg(const uint64_t* address); +uint4 __ldca(const uint4 *ptr); +u32 __ldca(const u32 *ptr); +u32 umin(const u32, const u32); +u32 umax(const u32, const u32); +#endif + + +typedef u32 proof[PROOFSIZE]; + + +struct __align__(32) slot +{ + u32 hash[8]; +}; + + +struct __align__(16) slotsmall +{ + u32 hash[4]; +}; + + +struct __align__(8) slottiny +{ + u32 hash[2]; +}; + + +template +struct equi +{ + slot round0trees[4096][RB8_NSLOTS]; + slot trees[1][NBUCKETS][NSLOTS]; + struct + { + slotsmall treessmall[NSLOTS]; + slottiny treestiny[NSLOTS]; + } round2trees[NBUCKETS]; + struct + { + slotsmall treessmall[NSLOTS]; + slottiny treestiny[NSLOTS]; + } round3trees[NBUCKETS]; + slotsmall treessmall[4][NBUCKETS][NSLOTS]; + slottiny treestiny[1][4096][RB8_NSLOTS_LD]; + u32 round4bidandsids[NBUCKETS][NSLOTS]; + union + { + u64 blake_h[8]; + u32 blake_h32[16]; + }; + struct + { + u32 nslots8[4096]; + u32 nslots0[4096]; + u32 nslots[9][NBUCKETS]; + scontainerreal srealcont; + } edata; +}; + + +__device__ __constant__ const u64 blake_iv[] = +{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +}; + +__device__ __forceinline__ uint2 operator^ (uint2 a, uint2 b) +{ + return make_uint2(a.x ^ b.x, a.y ^ b.y); +} + +__device__ __forceinline__ uint4 operator^ (uint4 a, uint4 b) +{ + return make_uint4(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); +} + +__device__ __forceinline__ uint2 ROR2(const uint2 a, const int offset) +{ + uint2 result; + { + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.x) : "r"(a.y), "r"(a.x), "r"(offset)); + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.y) : "r"(a.x), "r"(a.y), "r"(offset)); + } + return result; +} + +__device__ __forceinline__ uint2 SWAPUINT2(uint2 value) +{ + return make_uint2(value.y, value.x); +} + +__device__ __forceinline__ uint2 ROR24(const uint2 a) +{ + uint2 result; + result.x = __byte_perm(a.y, a.x, 0x2107); + result.y = __byte_perm(a.y, a.x, 0x6543); + return result; +} + +__device__ __forceinline__ uint2 ROR16(const uint2 a) +{ + uint2 result; + result.x = __byte_perm(a.y, a.x, 0x1076); + result.y = __byte_perm(a.y, a.x, 0x5432); + return result; +} + +__device__ __forceinline__ void G2(u64 & a, u64 & b, u64 & c, u64 & d, u64 x, u64 y) +{ + a = a + b + x; + ((uint2*)&d)[0] = SWAPUINT2(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); + c = c + d; + ((uint2*)&b)[0] = ROR24(((uint2*)&b)[0] ^ ((uint2*)&c)[0]); + a = a + b + y; + ((uint2*)&d)[0] = ROR16(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); + c = c + d; + ((uint2*)&b)[0] = ROR2(((uint2*)&b)[0] ^ ((uint2*)&c)[0], 63U); +} + + +struct packer_default +{ + __device__ __forceinline__ static u32 set_bucketid_and_slots(const u32 bucketid, const u32 s0, const u32 s1, const u32 RB, const u32 SM) + { + return (((bucketid << SLOTBITS) | s0) << SLOTBITS) | s1; + } + + __device__ __forceinline__ static u32 get_bucketid(const u32 bid, const u32 RB, const u32 SM) + { + // BUCKMASK-ed to prevent illegal memory accesses in case of memory errors + return (bid >> (2 * SLOTBITS)) & BUCKMASK; + } + + __device__ __forceinline__ static u32 get_slot0(const u32 bid, const u32 s1, const u32 RB, const u32 SM) + { + return bid & SLOTMASK; + } + + __device__ __forceinline__ static u32 get_slot1(const u32 bid, const u32 RB, const u32 SM) + { + return (bid >> SLOTBITS) & SLOTMASK; + } +}; + + +struct packer_cantor +{ + __device__ __forceinline__ static u32 cantor(const u32 s0, const u32 s1) + { + u32 a = umax(s0, s1); + u32 b = umin(s0, s1); + return a * (a + 1) / 2 + b; + } + + __device__ __forceinline__ static u32 set_bucketid_and_slots(const u32 bucketid, const u32 s0, const u32 s1, const u32 RB, const u32 SM) + { + return (bucketid << CANTORBITS) | cantor(s0, s1); + } + + __device__ __forceinline__ static u32 get_bucketid(const u32 bid, const u32 RB, const u32 SM) + { + return (bid >> CANTORBITS) & BUCKMASK; + } + + __device__ __forceinline__ static u32 get_slot0(const u32 bid, const u32 s1, const u32 RB, const u32 SM) + { + return ((bid & CANTORMASK) - cantor(0, s1)) & SLOTMASK; + } + + __device__ __forceinline__ static u32 get_slot1(const u32 bid, const u32 RB, const u32 SM) + { + u32 k, q, sqr = 8 * (bid & CANTORMASK) + 1; + // this k=sqrt(sqr) computing loop averages 3.4 iterations out of maximum 9 + for (k = CANTORMAXSQRT; (q = sqr / k) < k; k = (k + q) / 2); + return ((k - 1) / 2) & SLOTMASK; + } +}; + + +template +__global__ void digit_first(equi* eq, u32 nonce) +{ + const u32 block = blockIdx.x * blockDim.x + threadIdx.x; + __shared__ u64 hash_h[8]; + u32* hash_h32 = (u32*)hash_h; + + if (threadIdx.x < 16) + hash_h32[threadIdx.x] = __ldca(&eq->blake_h32[threadIdx.x]); + + __syncthreads(); + + u64 m = (u64)block << 32 | (u64)nonce; + + union + { + u64 v[16]; + u32 v32[32]; + uint4 v128[8]; + }; + + v[0] = hash_h[0]; + v[1] = hash_h[1]; + v[2] = hash_h[2]; + v[3] = hash_h[3]; + v[4] = hash_h[4]; + v[5] = hash_h[5]; + v[6] = hash_h[6]; + v[7] = hash_h[7]; + v[8] = blake_iv[0]; + v[9] = blake_iv[1]; + v[10] = blake_iv[2]; + v[11] = blake_iv[3]; + v[12] = blake_iv[4] ^ (128 + 16); + v[13] = blake_iv[5]; + v[14] = blake_iv[6] ^ 0xffffffffffffffff; + v[15] = blake_iv[7]; + + // mix 1 + G2(v[0], v[4], v[8], v[12], 0, m); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 2 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], m, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 3 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, m); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 4 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, m); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 5 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, m); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 6 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], m, 0); + + // mix 7 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], m, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 8 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, m); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 9 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], m, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 10 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], m, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 11 + G2(v[0], v[4], v[8], v[12], 0, m); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 12 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], m, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + v[0] ^= hash_h[0] ^ v[8]; + v[1] ^= hash_h[1] ^ v[9]; + v[2] ^= hash_h[2] ^ v[10]; + v[3] ^= hash_h[3] ^ v[11]; + v[4] ^= hash_h[4] ^ v[12]; + v[5] ^= hash_h[5] ^ v[13]; + v32[12] ^= hash_h32[12] ^ v32[28]; + + u32 bexor = __byte_perm(v32[0], 0, 0x4012); // first 20 bits + u32 bucketid; + asm("bfe.u32 %0, %1, 12, 12;" : "=r"(bucketid) : "r"(bexor)); + u32 slotp = atomicAdd(&eq->edata.nslots0[bucketid], 1); + if (slotp < RB8_NSLOTS) + { + slot* s = &eq->round0trees[bucketid][slotp]; + + uint4 tt; + tt.x = __byte_perm(v32[0], v32[1], 0x1234); + tt.y = __byte_perm(v32[1], v32[2], 0x1234); + tt.z = __byte_perm(v32[2], v32[3], 0x1234); + tt.w = __byte_perm(v32[3], v32[4], 0x1234); + *(uint4*)(&s->hash[0]) = tt; + + tt.x = __byte_perm(v32[4], v32[5], 0x1234); + tt.y = __byte_perm(v32[5], v32[6], 0x1234); + tt.z = 0; + tt.w = block << 1; + *(uint4*)(&s->hash[4]) = tt; + } + + bexor = __byte_perm(v32[6], 0, 0x0123); + asm("bfe.u32 %0, %1, 12, 12;" : "=r"(bucketid) : "r"(bexor)); + slotp = atomicAdd(&eq->edata.nslots0[bucketid], 1); + if (slotp < RB8_NSLOTS) + { + slot* s = &eq->round0trees[bucketid][slotp]; + + uint4 tt; + tt.x = __byte_perm(v32[6], v32[7], 0x2345); + tt.y = __byte_perm(v32[7], v32[8], 0x2345); + tt.z = __byte_perm(v32[8], v32[9], 0x2345); + tt.w = __byte_perm(v32[9], v32[10], 0x2345); + *(uint4*)(&s->hash[0]) = tt; + + tt.x = __byte_perm(v32[10], v32[11], 0x2345); + tt.y = __byte_perm(v32[11], v32[12], 0x2345); + tt.z = 0; + tt.w = (block << 1) + 1; + *(uint4*)(&s->hash[4]) = tt; + } +} + +/* + Functions digit_1 to digit_8 works by the same principle; + Each thread does 2-3 slot loads (loads are coalesced). + Xorwork of slots is loaded into shared memory and is kept in registers (except for digit_1). + At the same time, restbits (8 or 9 bits) in xorwork are used for collisions. + Restbits determine position in ht. + Following next is pair creation. First one (or two) pairs' xorworks are put into global memory + as soon as possible, the rest pairs are saved in shared memory (one u32 per pair - 16 bit indices). + In most cases, all threads have one (or two) pairs so with this trick, we offload memory writes a bit in last step. + In last step we save xorwork of pairs in memory. +*/ +template +__global__ void digit_1(equi* eq) +{ + __shared__ u16 ht[256][SSM - 1]; + __shared__ uint2 lastword1[RB8_NSLOTS]; + __shared__ uint4 lastword2[RB8_NSLOTS]; + __shared__ int ht_len[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + if (threadid < 256) + ht_len[threadid] = 0; + else if (threadid == (THREADS - 1)) + pairs_len = 0; + else if (threadid == (THREADS - 33)) + next_pair = 0; + + u32 bsize = umin(eq->edata.nslots0[bucketid], RB8_NSLOTS); + + u32 hr[2]; + int pos[2]; + pos[0] = pos[1] = SSM; + + uint2 ta[2]; + uint4 tb[2]; + + u32 si[2]; + + // enable this to make fully safe shared mem operations; + // disabled gains some speed, but can rarely cause a crash + //__syncthreads(); + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + si[i] = i * THREADS + threadid; + if (si[i] >= bsize) break; + + const slot* pslot1 = eq->round0trees[bucketid] + si[i]; + + // get xhash + uint4 a1 = *(uint4*)(&pslot1->hash[0]); + uint2 a2 = *(uint2*)(&pslot1->hash[4]); + ta[i].x = a1.x; + ta[i].y = a1.y; + lastword1[si[i]] = ta[i]; + tb[i].x = a1.z; + tb[i].y = a1.w; + tb[i].z = a2.x; + tb[i].w = a2.y; + lastword2[si[i]] = tb[i]; + + asm("bfe.u32 %0, %1, 20, 8;" : "=r"(hr[i]) : "r"(ta[i].x)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + int* pairs = ht_len; + + u32 xors[6]; + u32 xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + *(uint2*)(&xors[0]) = ta[i] ^ lastword1[p]; + + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[1][xorbucketid], 1); + + if (xorslot < NSLOTS) + { + *(uint4*)(&xors[2]) = lastword2[si[i]] ^ lastword2[p]; + + slot &xs = eq->trees[0][xorbucketid][xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[1]); + uint4 ttx; + ttx.x = xors[5]; + ttx.y = xors[0]; + ttx.z = packer_default::set_bucketid_and_slots(bucketid, si[i], p, 8, RB8_NSLOTS); + ttx.w = 0; + *(uint4*)(&xs.hash[4]) = ttx; + } + + for (int k = 1; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + + u32 i, k; + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + i = __byte_perm(pair, 0, 0x4510); + k = __byte_perm(pair, 0, 0x4532); + + *(uint2*)(&xors[0]) = lastword1[i] ^ lastword1[k]; + + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[1][xorbucketid], 1); + + if (xorslot < NSLOTS) + { + *(uint4*)(&xors[2]) = lastword2[i] ^ lastword2[k]; + + slot &xs = eq->trees[0][xorbucketid][xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[1]); + uint4 ttx; + ttx.x = xors[5]; + ttx.y = xors[0]; + ttx.z = packer_default::set_bucketid_and_slots(bucketid, i, k, 8, RB8_NSLOTS); + ttx.w = 0; + *(uint4*)(&xs.hash[4]) = ttx; + } + } +} + + +template +__global__ void digit_2(equi* eq) +{ + __shared__ u16 ht[NRESTS][SSM - 1]; + __shared__ u32 lastword1[NSLOTS]; + __shared__ uint4 lastword2[NSLOTS]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + if (threadid < NRESTS) + ht_len[threadid] = 0; + else if (threadid == (THREADS - 1)) + pairs_len = 0; + else if (threadid == (THREADS - 33)) + next_pair = 0; + + slot* buck = eq->trees[0][bucketid]; + u32 bsize = umin(eq->edata.nslots[1][bucketid], NSLOTS); + + u32 hr[2]; + int pos[2]; + pos[0] = pos[1] = SSM; + + u32 ta[2]; + uint4 tt[2]; + + u32 si[2]; + + // enable this to make fully safe shared mem operations; + // disabled gains some speed, but can rarely cause a crash + //__syncthreads(); + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + si[i] = i * THREADS + threadid; + if (si[i] >= bsize) break; + + // get slot + const slot* pslot1 = buck + si[i]; + + uint4 ttx = *(uint4*)(&pslot1->hash[0]); + lastword1[si[i]] = ta[i] = ttx.x; + uint2 tty = *(uint2*)(&pslot1->hash[4]); + tt[i].x = ttx.y; + tt[i].y = ttx.z; + tt[i].z = ttx.w; + tt[i].w = tty.x; + lastword2[si[i]] = tt[i]; + + hr[i] = tty.y & RESTMASK; + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + + u32 xors[5]; + u32 xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + xors[0] = ta[i] ^ lastword1[p]; + + xorbucketid = xors[0] >> (12 + RB); + xorslot = atomicAdd(&eq->edata.nslots[2][xorbucketid], 1); + if (xorslot < NSLOTS) + { + *(uint4*)(&xors[1]) = tt[i] ^ lastword2[p]; + slotsmall &xs = eq->round2trees[xorbucketid].treessmall[xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[0]); + slottiny &xst = eq->round2trees[xorbucketid].treestiny[xorslot]; + uint2 ttx; + ttx.x = xors[4]; + ttx.y = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint2*)(&xst.hash[0]) = ttx; + } + + for (int k = 1; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + + u32 i, k; + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + i = __byte_perm(pair, 0, 0x4510); + k = __byte_perm(pair, 0, 0x4532); + + xors[0] = lastword1[i] ^ lastword1[k]; + + xorbucketid = xors[0] >> (12 + RB); + xorslot = atomicAdd(&eq->edata.nslots[2][xorbucketid], 1); + if (xorslot < NSLOTS) + { + *(uint4*)(&xors[1]) = lastword2[i] ^ lastword2[k]; + slotsmall &xs = eq->round2trees[xorbucketid].treessmall[xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[0]); + slottiny &xst = eq->round2trees[xorbucketid].treestiny[xorslot]; + uint2 ttx; + ttx.x = xors[4]; + ttx.y = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + *(uint2*)(&xst.hash[0]) = ttx; + } + } +} + + +template +__global__ void digit_3(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ uint4 lastword1[NSLOTS]; + __shared__ u32 lastword2[NSLOTS]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + if (threadid < NRESTS) + ht_len[threadid] = 0; + else if (threadid == (THREADS - 1)) + pairs_len = 0; + else if (threadid == (THREADS - 33)) + next_pair = 0; + + u32 bsize = umin(eq->edata.nslots[2][bucketid], NSLOTS); + + u32 hr[2]; + int pos[2]; + pos[0] = pos[1] = SSM; + + u32 si[2]; + uint4 tt[2]; + u32 ta[2]; + + // enable this to make fully safe shared mem operations; + // disabled gains some speed, but can rarely cause a crash + //__syncthreads(); + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + si[i] = i * THREADS + threadid; + if (si[i] >= bsize) break; + + slotsmall &xs = eq->round2trees[bucketid].treessmall[si[i]]; + slottiny &xst = eq->round2trees[bucketid].treestiny[si[i]]; + + tt[i] = *(uint4*)(&xs.hash[0]); + lastword1[si[i]] = tt[i]; + ta[i] = xst.hash[0]; + lastword2[si[i]] = ta[i]; + asm("bfe.u32 %0, %1, 12, %2;" : "=r"(hr[i]) : "r"(tt[i].x), "r"(RB)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + + u32 xors[5]; + u32 bexor, xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + xors[4] = ta[i] ^ lastword2[p]; + + if (xors[4] != 0) + { + *(uint4*)(&xors[0]) = tt[i] ^ lastword1[p]; + + bexor = __byte_perm(xors[0], xors[1], 0x2107); + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(bexor), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[3][xorbucketid], 1); + + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->round3trees[xorbucketid].treessmall[xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[1]); + slottiny &xst = eq->round3trees[xorbucketid].treestiny[xorslot]; + uint2 ttx; + ttx.x = bexor; + ttx.y = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint2*)(&xst.hash[0]) = ttx; + } + } + + for (int k = 1; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + + u32 i, k; + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + i = __byte_perm(pair, 0, 0x4510); + k = __byte_perm(pair, 0, 0x4532); + + xors[4] = lastword2[i] ^ lastword2[k]; + + if (xors[4] != 0) + { + *(uint4*)(&xors[0]) = lastword1[i] ^ lastword1[k]; + + bexor = __byte_perm(xors[0], xors[1], 0x2107); + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(bexor), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[3][xorbucketid], 1); + + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->round3trees[xorbucketid].treessmall[xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[1]); + slottiny &xst = eq->round3trees[xorbucketid].treestiny[xorslot]; + uint2 ttx; + ttx.x = bexor; + ttx.y = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + *(uint2*)(&xst.hash[0]) = ttx; + } + } + } +} + + +template +__global__ void digit_4(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ uint4 lastword[NSLOTS]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + if (threadid < NRESTS) + ht_len[threadid] = 0; + else if (threadid == (THREADS - 1)) + pairs_len = 0; + else if (threadid == (THREADS - 33)) + next_pair = 0; + + u32 bsize = umin(eq->edata.nslots[3][bucketid], NSLOTS); + + u32 hr[2]; + int pos[2]; + pos[0] = pos[1] = SSM; + + u32 si[2]; + uint4 tt[2]; + + // enable this to make fully safe shared mem operations; + // disabled gains some speed, but can rarely cause a crash + //__syncthreads(); + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + si[i] = i * THREADS + threadid; + if (si[i] >= bsize) break; + + slotsmall &xs = eq->round3trees[bucketid].treessmall[si[i]]; + slottiny &xst = eq->round3trees[bucketid].treestiny[si[i]]; + + // get xhash + tt[i] = *(uint4*)(&xs.hash[0]); + lastword[si[i]] = tt[i]; + hr[i] = xst.hash[0] & RESTMASK; + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + u32 xors[4]; + u32 xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + *(uint4*)(&xors[0]) = tt[i] ^ lastword[p]; + + if (xors[3] != 0) + { + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(4 + RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[4][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[3][xorbucketid][xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[0]); + + eq->round4bidandsids[xorbucketid][xorslot] = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + } + } + + for (int k = 1; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + u32 i, k; + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + i = __byte_perm(pair, 0, 0x4510); + k = __byte_perm(pair, 0, 0x4532); + + *(uint4*)(&xors[0]) = lastword[i] ^ lastword[k]; + if (xors[3] != 0) + { + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(4 + RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[4][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[3][xorbucketid][xorslot]; + *(uint4*)(&xs.hash[0]) = *(uint4*)(&xors[0]); + eq->round4bidandsids[xorbucketid][xorslot] = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + } + } + } +} + + +template +__global__ void digit_5(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ uint4 lastword[NSLOTS]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + if (threadid < NRESTS) + ht_len[threadid] = 0; + else if (threadid == (THREADS - 1)) + pairs_len = 0; + else if (threadid == (THREADS - 33)) + next_pair = 0; + + slotsmall* buck = eq->treessmall[3][bucketid]; + u32 bsize = umin(eq->edata.nslots[4][bucketid], NSLOTS); + + u32 hr[2]; + int pos[2]; + pos[0] = pos[1] = SSM; + + u32 si[2]; + uint4 tt[2]; + + // enable this to make fully safe shared mem operations; + // disabled gains some speed, but can rarely cause a crash + //__syncthreads(); + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + si[i] = i * THREADS + threadid; + if (si[i] >= bsize) break; + + const slotsmall* pslot1 = buck + si[i]; + + tt[i] = *(uint4*)(&pslot1->hash[0]); + lastword[si[i]] = tt[i]; + asm("bfe.u32 %0, %1, 4, %2;" : "=r"(hr[i]) : "r"(tt[i].x), "r"(RB)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + u32 xors[4]; + u32 bexor, xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 2; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + *(uint4*)(&xors[0]) = tt[i] ^ lastword[p]; + + if (xors[3] != 0) + { + bexor = __byte_perm(xors[0], xors[1], 0x1076); + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(bexor), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[5][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[2][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[1]; + ttx.y = xors[2]; + ttx.z = xors[3]; + ttx.w = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint4*)(&xs.hash[0]) = ttx; + } + } + + for (int k = 1; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + u32 i, k; + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + i = __byte_perm(pair, 0, 0x4510); + k = __byte_perm(pair, 0, 0x4532); + + *(uint4*)(&xors[0]) = lastword[i] ^ lastword[k]; + + if (xors[3] != 0) + { + bexor = __byte_perm(xors[0], xors[1], 0x1076); + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(bexor), "r"(RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[5][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[2][xorbucketid][xorslot]; + uint4 tt; + tt.x = xors[1]; + tt.y = xors[2]; + tt.z = xors[3]; + tt.w = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + *(uint4*)(&xs.hash[0]) = tt; + } + } + } +} + + +template +__global__ void digit_6(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ uint2 lastword1[NSLOTS]; + __shared__ u32 lastword2[NSLOTS]; + __shared__ int ht_len[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 bsize_sh; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + ht_len[threadid] = 0; + if (threadid == (NRESTS - 1)) + { + pairs_len = 0; + next_pair = 0; + } + else if (threadid == (NRESTS - 33)) + bsize_sh = umin(eq->edata.nslots[5][bucketid], NSLOTS); + + slotsmall* buck = eq->treessmall[2][bucketid]; + + u32 hr[3]; + int pos[3]; + pos[0] = pos[1] = pos[2] = SSM; + + u32 si[3]; + uint4 tt[3]; + + __syncthreads(); + + u32 bsize = bsize_sh; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + si[i] = i * NRESTS + threadid; + if (si[i] >= bsize) break; + + const slotsmall* pslot1 = buck + si[i]; + + tt[i] = *(uint4*)(&pslot1->hash[0]); + lastword1[si[i]] = *(uint2*)(&tt[i].x); + lastword2[si[i]] = tt[i].z; + asm("bfe.u32 %0, %1, 16, %2;" : "=r"(hr[i]) : "r"(tt[i].x), "r"(RB)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + // doing this to save shared memory + int* pairs = ht_len; + __syncthreads(); + + u32 xors[3]; + u32 bexor, xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + xors[2] = tt[i].z ^ lastword2[p]; + + if (xors[2] != 0) + { + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ lastword1[p]; + + bexor = __byte_perm(xors[0], xors[1], 0x1076); + xorbucketid = bexor >> (12 + RB); + xorslot = atomicAdd(&eq->edata.nslots[6][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[0][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[1]; + ttx.y = xors[2]; + ttx.z = bexor; + ttx.w = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint4*)(&xs.hash[0]) = ttx; + } + } + + if (pos[i] > 1) + { + p = ht[hr[i]][1]; + + xors[2] = tt[i].z ^ lastword2[p]; + + if (xors[2] != 0) + { + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ lastword1[p]; + + bexor = __byte_perm(xors[0], xors[1], 0x1076); + xorbucketid = bexor >> (12 + RB); + xorslot = atomicAdd(&eq->edata.nslots[6][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[0][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[1]; + ttx.y = xors[2]; + ttx.z = bexor; + ttx.w = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint4*)(&xs.hash[0]) = ttx; + } + } + + for (int k = 2; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + u32 pair = pairs[s]; + u32 i = __byte_perm(pair, 0, 0x4510); + u32 k = __byte_perm(pair, 0, 0x4532); + + xors[2] = lastword2[i] ^ lastword2[k]; + if (xors[2] == 0) + continue; + + *(uint2*)(&xors[0]) = lastword1[i] ^ lastword1[k]; + + bexor = __byte_perm(xors[0], xors[1], 0x1076); + xorbucketid = bexor >> (12 + RB); + xorslot = atomicAdd(&eq->edata.nslots[6][xorbucketid], 1); + if (xorslot >= NSLOTS) continue; + slotsmall &xs = eq->treessmall[0][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[1]; + ttx.y = xors[2]; + ttx.z = bexor; + ttx.w = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + *(uint4*)(&xs.hash[0]) = ttx; + } +} + + +template +__global__ void digit_7(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ u32 lastword[NSLOTS][2]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 bsize_sh; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + ht_len[threadid] = 0; + if (threadid == (NRESTS - 1)) + { + pairs_len = 0; + next_pair = 0; + } + else if (threadid == (NRESTS - 33)) + bsize_sh = umin(eq->edata.nslots[6][bucketid], NSLOTS); + + slotsmall* buck = eq->treessmall[0][bucketid]; + + u32 hr[3]; + int pos[3]; + pos[0] = pos[1] = pos[2] = SSM; + + u32 si[3]; + uint4 tt[3]; + + __syncthreads(); + + u32 bsize = bsize_sh; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + si[i] = i * NRESTS + threadid; + if (si[i] >= bsize) break; + + const slotsmall* pslot1 = buck + si[i]; + + // get xhash + tt[i] = *(uint4*)(&pslot1->hash[0]); + *(uint2*)(&lastword[si[i]][0]) = *(uint2*)(&tt[i].x); + asm("bfe.u32 %0, %1, 12, %2;" : "=r"(hr[i]) : "r"(tt[i].z), "r"(RB)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + + u32 xors[2]; + u32 xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ *(uint2*)(&lastword[p][0]); + + if (xors[1] != 0) + { + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(8 + RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[7][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[1][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[0]; + ttx.y = xors[1]; + ttx.z = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + ttx.w = 0; + *(uint4*)(&xs.hash[0]) = ttx; + } + } + + if (pos[i] > 1) + { + p = ht[hr[i]][1]; + + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ *(uint2*)(&lastword[p][0]); + + if (xors[1] != 0) + { + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(8 + RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[7][xorbucketid], 1); + if (xorslot < NSLOTS) + { + slotsmall &xs = eq->treessmall[1][xorbucketid][xorslot]; + uint4 ttx; + ttx.x = xors[0]; + ttx.y = xors[1]; + ttx.z = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + ttx.w = 0; + *(uint4*)(&xs.hash[0]) = ttx; + } + } + + for (int k = 2; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + u32 i = __byte_perm(pair, 0, 0x4510); + u32 k = __byte_perm(pair, 0, 0x4532); + + *(uint2*)(&xors[0]) = *(uint2*)(&lastword[i][0]) ^ *(uint2*)(&lastword[k][0]); + + if (xors[1] == 0) + continue; + + asm("bfe.u32 %0, %1, %2, %3;" : "=r"(xorbucketid) : "r"(xors[0]), "r"(8 + RB), "r"(BUCKBITS)); + xorslot = atomicAdd(&eq->edata.nslots[7][xorbucketid], 1); + if (xorslot >= NSLOTS) continue; + slotsmall &xs = eq->treessmall[1][xorbucketid][xorslot]; + uint4 tt; + tt.x = xors[0]; + tt.y = xors[1]; + tt.z = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + tt.w = 0; + *(uint4*)(&xs.hash[0]) = tt; + } +} + + +template +__global__ void digit_8(equi* eq) +{ + __shared__ u16 ht[NRESTS][(SSM - 1)]; + __shared__ u32 lastword[NSLOTS][2]; + __shared__ int ht_len[NRESTS]; + __shared__ int pairs[MAXPAIRS]; + __shared__ u32 pairs_len; + __shared__ u32 bsize_sh; + __shared__ u32 next_pair; + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len + ht_len[threadid] = 0; + if (threadid == (NRESTS - 1)) + { + next_pair = 0; + pairs_len = 0; + } + else if (threadid == (NRESTS - 33)) + bsize_sh = umin(eq->edata.nslots[7][bucketid], NSLOTS); + + slotsmall* buck = eq->treessmall[1][bucketid]; + + u32 hr[3]; + int pos[3]; + pos[0] = pos[1] = pos[2] = SSM; + + u32 si[3]; + uint2 tt[3]; + + __syncthreads(); + + u32 bsize = bsize_sh; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + si[i] = i * NRESTS + threadid; + if (si[i] >= bsize) break; + + const slotsmall* pslot1 = buck + si[i]; + + // get xhash + tt[i] = *(uint2*)(&pslot1->hash[0]); + *(uint2*)(&lastword[si[i]][0]) = *(uint2*)(&tt[i].x); + asm("bfe.u32 %0, %1, 8, %2;" : "=r"(hr[i]) : "r"(tt[i].x), "r"(RB)); + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) ht[hr[i]][pos[i]] = si[i]; + } + + __syncthreads(); + + u32 xors[2]; + u32 bexor, xorbucketid, xorslot; + +#pragma unroll + for (u32 i = 0; i != 3; ++i) + { + if (pos[i] >= SSM) continue; + + if (pos[i] > 0) + { + u16 p = ht[hr[i]][0]; + + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ *(uint2*)(&lastword[p][0]); + + if (xors[1] != 0) + { + bexor = __byte_perm(xors[0], xors[1], 0x0765); + xorbucketid = bexor >> (12 + 8); + xorslot = atomicAdd(&eq->edata.nslots8[xorbucketid], 1); + if (xorslot < RB8_NSLOTS_LD) + { + slottiny &xs = eq->treestiny[0][xorbucketid][xorslot]; + uint2 tt; + tt.x = xors[1]; + tt.y = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint2*)(&xs.hash[0]) = tt; + } + } + + if (pos[i] > 1) + { + p = ht[hr[i]][1]; + + *(uint2*)(&xors[0]) = *(uint2*)(&tt[i].x) ^ *(uint2*)(&lastword[p][0]); + + if (xors[1] != 0) + { + bexor = __byte_perm(xors[0], xors[1], 0x0765); + xorbucketid = bexor >> (12 + 8); + xorslot = atomicAdd(&eq->edata.nslots8[xorbucketid], 1); + if (xorslot < RB8_NSLOTS_LD) + { + slottiny &xs = eq->treestiny[0][xorbucketid][xorslot]; + uint2 tt; + tt.x = xors[1]; + tt.y = PACKER::set_bucketid_and_slots(bucketid, si[i], p, RB, SM); + *(uint2*)(&xs.hash[0]) = tt; + } + } + + for (int k = 2; k != pos[i]; ++k) + { + u32 pindex = atomicAdd(&pairs_len, 1); + if (pindex >= MAXPAIRS) break; + u16 prev = ht[hr[i]][k]; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + } + } + + __syncthreads(); + + // process pairs + u32 plen = umin(pairs_len, MAXPAIRS); + for (u32 s = atomicAdd(&next_pair, 1); s < plen; s = atomicAdd(&next_pair, 1)) + { + int pair = pairs[s]; + u32 i = __byte_perm(pair, 0, 0x4510); + u32 k = __byte_perm(pair, 0, 0x4532); + + *(uint2*)(&xors[0]) = *(uint2*)(&lastword[i][0]) ^ *(uint2*)(&lastword[k][0]); + + if (xors[1] == 0) + continue; + + bexor = __byte_perm(xors[0], xors[1], 0x0765); + xorbucketid = bexor >> (12 + 8); + xorslot = atomicAdd(&eq->edata.nslots8[xorbucketid], 1); + if (xorslot >= RB8_NSLOTS_LD) continue; + slottiny &xs = eq->treestiny[0][xorbucketid][xorslot]; + uint2 tt; + tt.x = xors[1]; + tt.y = PACKER::set_bucketid_and_slots(bucketid, i, k, RB, SM); + *(uint2*)(&xs.hash[0]) = tt; + } +} + +/* + Last round function is similar to previous ones but has different ending. + We use warps to process final candidates. Each warp process one candidate. + First two bidandsids (u32 of stored bucketid and two slotids) are retreived by + lane 0 and lane 16, next four bidandsids by lane 0, 8, 16 and 24, ... until + all lanes in warp have bidandsids from round 4. Next, each thread retreives + 16 indices. While doing so, indices are put into comparison using atomicExch + to determine if there are duplicates (tromp's method). At the end, if no + duplicates are found, candidate solution is saved (all indices). Note that this + dup check method is not exact so CPU dup checking is needed after. +*/ +template +__global__ void digit_last_wdc(equi* eq) +{ + __shared__ u8 shared_data[8192]; + int* ht_len = (int*)(&shared_data[0]); + int* pairs = ht_len; + u32* lastword = (u32*)(&shared_data[256 * 4]); + u16* ht = (u16*)(&shared_data[256 * 4 + RB8_NSLOTS_LD * 4]); + u32* pairs_len = (u32*)(&shared_data[8188]); + + const u32 threadid = threadIdx.x; + const u32 bucketid = blockIdx.x; + + // reset hashtable len +#pragma unroll + for (u32 i = 0; i != FCT; ++i) + ht_len[(i * (256 / FCT)) + threadid] = 0; + + if (threadid == ((256 / FCT) - 1)) + *pairs_len = 0; + + slottiny* buck = eq->treestiny[0][bucketid]; + u32 bsize = umin(eq->edata.nslots8[bucketid], RB8_NSLOTS_LD); + + u32 si[3 * FCT]; + u32 hr[3 * FCT]; + int pos[3 * FCT]; + u32 lw[3 * FCT]; +#pragma unroll + for (u32 i = 0; i != (3 * FCT); ++i) + pos[i] = SSM; + + __syncthreads(); + +#pragma unroll + for (u32 i = 0; i != (3 * FCT); ++i) + { + si[i] = i * (256 / FCT) + threadid; + if (si[i] >= bsize) break; + + const slottiny* pslot1 = buck + si[i]; + + // get xhash + uint2 tt = *(uint2*)(&pslot1->hash[0]); + lw[i] = tt.x; + lastword[si[i]] = lw[i]; + + u32 a; + asm("bfe.u32 %0, %1, 20, 8;" : "=r"(a) : "r"(lw[i])); + hr[i] = a; + + pos[i] = atomicAdd(&ht_len[hr[i]], 1); + if (pos[i] < (SSM - 1)) + ht[hr[i] * (SSM - 1) + pos[i]] = si[i]; + } + + __syncthreads(); + +#pragma unroll + for (u32 i = 0; i != (3 * FCT); ++i) + { + if (pos[i] >= SSM) continue; + + for (int k = 0; k != pos[i]; ++k) + { + u16 prev = ht[hr[i] * (SSM - 1) + k]; + if (lw[i] != lastword[prev]) continue; + u32 pindex = atomicAdd(pairs_len, 1); + if (pindex >= MAXPAIRS) break; + pairs[pindex] = __byte_perm(si[i], prev, 0x1054); + } + } + + __syncthreads(); + u32 plen = umin(*pairs_len, 64); + +#define CALC_LEVEL(a, b, c, d) { \ + u32 plvl = levels[b]; \ + u32* bucks = eq->round4bidandsids[PACKER::get_bucketid(plvl, RB, SM)]; \ + u32 slot1 = PACKER::get_slot1(plvl, RB, SM); \ + u32 slot0 = PACKER::get_slot0(plvl, slot1, RB, SM); \ + levels[b] = bucks[slot1]; \ + levels[c] = bucks[slot0]; \ + } + +#define CALC_LEVEL_SMALL(a, b, c, d) { \ + u32 plvl = levels[b]; \ + slotsmall* bucks = eq->treessmall[a][PACKER::get_bucketid(plvl, RB, SM)]; \ + u32 slot1 = PACKER::get_slot1(plvl, RB, SM); \ + u32 slot0 = PACKER::get_slot0(plvl, slot1, RB, SM); \ + levels[b] = bucks[slot1].hash[d]; \ + levels[c] = bucks[slot0].hash[d]; \ + } + + u32 lane = threadIdx.x & 0x1f; + u32 par = threadIdx.x >> 5; + + u32* levels = (u32*)&pairs[MAXPAIRS + (par << DUPBITS)]; + u32* susp = levels; + + while (par < plen) + { + int pair = pairs[par]; + par += W; + + if (lane % 16 == 0) + { + u32 plvl; + if (lane == 0) plvl = buck[__byte_perm(pair, 0, 0x4510)].hash[1]; + else plvl = buck[__byte_perm(pair, 0, 0x4532)].hash[1]; + slotsmall* bucks = eq->treessmall[1][PACKER::get_bucketid(plvl, RB, SM)]; + u32 slot1 = PACKER::get_slot1(plvl, RB, SM); + u32 slot0 = PACKER::get_slot0(plvl, slot1, RB, SM); + levels[lane] = bucks[slot1].hash[2]; + levels[lane + 8] = bucks[slot0].hash[2]; + } + + if (lane % 8 == 0) + CALC_LEVEL_SMALL(0, lane, lane + 4, 3); + + if (lane % 4 == 0) + CALC_LEVEL_SMALL(2, lane, lane + 2, 3); + + if (lane % 2 == 0) + CALC_LEVEL(0, lane, lane + 1, 4); + + u32 ind[16]; + + u32 f1 = levels[lane]; + const slottiny* buck_v4 = &eq->round3trees[PACKER::get_bucketid(f1, RB, SM)].treestiny[0]; + const u32 slot1_v4 = PACKER::get_slot1(f1, RB, SM); + const u32 slot0_v4 = PACKER::get_slot0(f1, slot1_v4, RB, SM); + + susp[lane] = 0xffffffff; + susp[32 + lane] = 0xffffffff; + +#define CHECK_DUP(a) \ + __any(atomicExch(&susp[(ind[a] & ((1 << DUPBITS) - 1))], (ind[a] >> DUPBITS)) == (ind[a] >> DUPBITS)) + + u32 f2 = buck_v4[slot1_v4].hash[1]; + const slottiny* buck_v3_1 = &eq->round2trees[PACKER::get_bucketid(f2, RB, SM)].treestiny[0]; + const u32 slot1_v3_1 = PACKER::get_slot1(f2, RB, SM); + const u32 slot0_v3_1 = PACKER::get_slot0(f2, slot1_v3_1, RB, SM); + + susp[64 + lane] = 0xffffffff; + susp[96 + lane] = 0xffffffff; + + u32 f0 = buck_v3_1[slot1_v3_1].hash[1]; + const slot* buck_v2_1 = eq->trees[0][PACKER::get_bucketid(f0, RB, SM)]; + const u32 slot1_v2_1 = PACKER::get_slot1(f0, RB, SM); + const u32 slot0_v2_1 = PACKER::get_slot0(f0, slot1_v2_1, RB, SM); + + susp[128 + lane] = 0xffffffff; + susp[160 + lane] = 0xffffffff; + + u32 f3 = buck_v2_1[slot1_v2_1].hash[6]; + const slot* buck_fin_1 = eq->round0trees[packer_default::get_bucketid(f3, 8, RB8_NSLOTS)]; + const u32 slot1_fin_1 = packer_default::get_slot1(f3, 8, RB8_NSLOTS); + const u32 slot0_fin_1 = packer_default::get_slot0(f3, slot1_fin_1, 8, RB8_NSLOTS); + + susp[192 + lane] = 0xffffffff; + susp[224 + lane] = 0xffffffff; + + ind[0] = buck_fin_1[slot1_fin_1].hash[7]; + if (CHECK_DUP(0)) continue; + ind[1] = buck_fin_1[slot0_fin_1].hash[7]; + if (CHECK_DUP(1)) continue; + + u32 f4 = buck_v2_1[slot0_v2_1].hash[6]; + const slot* buck_fin_2 = eq->round0trees[packer_default::get_bucketid(f4, 8, RB8_NSLOTS)]; + const u32 slot1_fin_2 = packer_default::get_slot1(f4, 8, RB8_NSLOTS); + const u32 slot0_fin_2 = packer_default::get_slot0(f4, slot1_fin_2, 8, RB8_NSLOTS); + + ind[2] = buck_fin_2[slot1_fin_2].hash[7]; + if (CHECK_DUP(2)) continue; + ind[3] = buck_fin_2[slot0_fin_2].hash[7]; + if (CHECK_DUP(3)) continue; + + u32 f5 = buck_v3_1[slot0_v3_1].hash[1]; + const slot* buck_v2_2 = eq->trees[0][PACKER::get_bucketid(f5, RB, SM)]; + const u32 slot1_v2_2 = PACKER::get_slot1(f5, RB, SM); + const u32 slot0_v2_2 = PACKER::get_slot0(f5, slot1_v2_2, RB, SM); + + u32 f6 = buck_v2_2[slot1_v2_2].hash[6]; + const slot* buck_fin_3 = eq->round0trees[packer_default::get_bucketid(f6, 8, RB8_NSLOTS)]; + const u32 slot1_fin_3 = packer_default::get_slot1(f6, 8, RB8_NSLOTS); + const u32 slot0_fin_3 = packer_default::get_slot0(f6, slot1_fin_3, 8, RB8_NSLOTS); + + ind[4] = buck_fin_3[slot1_fin_3].hash[7]; + if (CHECK_DUP(4)) continue; + ind[5] = buck_fin_3[slot0_fin_3].hash[7]; + if (CHECK_DUP(5)) continue; + + u32 f7 = buck_v2_2[slot0_v2_2].hash[6]; + const slot* buck_fin_4 = eq->round0trees[packer_default::get_bucketid(f7, 8, RB8_NSLOTS)]; + const u32 slot1_fin_4 = packer_default::get_slot1(f7, 8, RB8_NSLOTS); + const u32 slot0_fin_4 = packer_default::get_slot0(f7, slot1_fin_4, 8, RB8_NSLOTS); + + ind[6] = buck_fin_4[slot1_fin_4].hash[7]; + if (CHECK_DUP(6)) continue; + ind[7] = buck_fin_4[slot0_fin_4].hash[7]; + if (CHECK_DUP(7)) continue; + + u32 f8 = buck_v4[slot0_v4].hash[1]; + const slottiny* buck_v3_2 = &eq->round2trees[PACKER::get_bucketid(f8, RB, SM)].treestiny[0]; + const u32 slot1_v3_2 = PACKER::get_slot1(f8, RB, SM); + const u32 slot0_v3_2 = PACKER::get_slot0(f8, slot1_v3_2, RB, SM); + + u32 f9 = buck_v3_2[slot1_v3_2].hash[1]; + const slot* buck_v2_3 = eq->trees[0][PACKER::get_bucketid(f9, RB, SM)]; + const u32 slot1_v2_3 = PACKER::get_slot1(f9, RB, SM); + const u32 slot0_v2_3 = PACKER::get_slot0(f9, slot1_v2_3, RB, SM); + + u32 f10 = buck_v2_3[slot1_v2_3].hash[6]; + const slot* buck_fin_5 = eq->round0trees[packer_default::get_bucketid(f10, 8, RB8_NSLOTS)]; + const u32 slot1_fin_5 = packer_default::get_slot1(f10, 8, RB8_NSLOTS); + const u32 slot0_fin_5 = packer_default::get_slot0(f10, slot1_fin_5, 8, RB8_NSLOTS); + + ind[8] = buck_fin_5[slot1_fin_5].hash[7]; + if (CHECK_DUP(8)) continue; + ind[9] = buck_fin_5[slot0_fin_5].hash[7]; + if (CHECK_DUP(9)) continue; + + u32 f11 = buck_v2_3[slot0_v2_3].hash[6]; + const slot* buck_fin_6 = eq->round0trees[packer_default::get_bucketid(f11, 8, RB8_NSLOTS)]; + const u32 slot1_fin_6 = packer_default::get_slot1(f11, 8, RB8_NSLOTS); + const u32 slot0_fin_6 = packer_default::get_slot0(f11, slot1_fin_6, 8, RB8_NSLOTS); + + ind[10] = buck_fin_6[slot1_fin_6].hash[7]; + if (CHECK_DUP(10)) continue; + ind[11] = buck_fin_6[slot0_fin_6].hash[7]; + if (CHECK_DUP(11)) continue; + + u32 f12 = buck_v3_2[slot0_v3_2].hash[1]; + const slot* buck_v2_4 = eq->trees[0][PACKER::get_bucketid(f12, RB, SM)]; + const u32 slot1_v2_4 = PACKER::get_slot1(f12, RB, SM); + const u32 slot0_v2_4 = PACKER::get_slot0(f12, slot1_v2_4, RB, SM); + + u32 f13 = buck_v2_4[slot1_v2_4].hash[6]; + const slot* buck_fin_7 = eq->round0trees[packer_default::get_bucketid(f13, 8, RB8_NSLOTS)]; + const u32 slot1_fin_7 = packer_default::get_slot1(f13, 8, RB8_NSLOTS); + const u32 slot0_fin_7 = packer_default::get_slot0(f13, slot1_fin_7, 8, RB8_NSLOTS); + + ind[12] = buck_fin_7[slot1_fin_7].hash[7]; + if (CHECK_DUP(12)) continue; + ind[13] = buck_fin_7[slot0_fin_7].hash[7]; + if (CHECK_DUP(13)) continue; + + u32 f14 = buck_v2_4[slot0_v2_4].hash[6]; + const slot* buck_fin_8 = eq->round0trees[packer_default::get_bucketid(f14, 8, RB8_NSLOTS)]; + const u32 slot1_fin_8 = packer_default::get_slot1(f14, 8, RB8_NSLOTS); + const u32 slot0_fin_8 = packer_default::get_slot0(f14, slot1_fin_8, 8, RB8_NSLOTS); + + ind[14] = buck_fin_8[slot1_fin_8].hash[7]; + if (CHECK_DUP(14)) continue; + ind[15] = buck_fin_8[slot0_fin_8].hash[7]; + if (CHECK_DUP(15)) continue; + + u32 soli; + if (lane == 0) + { + soli = atomicAdd(&eq->edata.srealcont.nsols, 1); + } + soli = __shfl(soli, 0); + + if (soli < MAXREALSOLS) + { + u32 pos = lane << 4; + *(uint4*)(&eq->edata.srealcont.sols[soli][pos]) = *(uint4*)(&ind[0]); + *(uint4*)(&eq->edata.srealcont.sols[soli][pos + 4]) = *(uint4*)(&ind[4]); + *(uint4*)(&eq->edata.srealcont.sols[soli][pos + 8]) = *(uint4*)(&ind[8]); + *(uint4*)(&eq->edata.srealcont.sols[soli][pos + 12]) = *(uint4*)(&ind[12]); + } + } +} + + +std::mutex dev_init; +int dev_init_done[8] = { 0 }; + + +__host__ int compu32(const void *pa, const void *pb) +{ + uint32_t a = *(uint32_t *)pa, b = *(uint32_t *)pb; + return a b[i]) + { + need_sorting = 1; + tmp = a[i]; + a[i] = b[i]; + b[i] = tmp; + } + else if (a[i] < b[i]) + return; +} + + +__host__ void setheader(blake2b_state *ctx, const char *header, const u32 headerLen, const char* nce, const u32 nonceLen) +{ + uint32_t le_N = WN; + uint32_t le_K = WK; + uchar personal[] = "ZcashPoW01230123"; + memcpy(personal + 8, &le_N, 4); + memcpy(personal + 12, &le_K, 4); + blake2b_param P[1]; + P->digest_length = HASHOUT; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + P->leaf_length = 0; + P->node_offset = 0; + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + memset(P->salt, 0, sizeof(P->salt)); + memcpy(P->personal, (const uint8_t *)personal, 16); + blake2b_init_param(ctx, P); + blake2b_update(ctx, (const uchar *)header, headerLen); + blake2b_update(ctx, (const uchar *)nce, nonceLen); +} + + +#ifdef WIN32 +typedef CUresult(CUDAAPI *dec_cuDeviceGet)(CUdevice*, int); +typedef CUresult(CUDAAPI *dec_cuCtxCreate)(CUcontext*, unsigned int, CUdevice); +typedef CUresult(CUDAAPI *dec_cuCtxPushCurrent)(CUcontext); +typedef CUresult(CUDAAPI *dec_cuCtxDestroy)(CUcontext); + +dec_cuDeviceGet _cuDeviceGet = nullptr; +dec_cuCtxCreate _cuCtxCreate = nullptr; +dec_cuCtxPushCurrent _cuCtxPushCurrent = nullptr; +dec_cuCtxDestroy _cuCtxDestroy = nullptr; +#endif + + +template +__host__ eq_cuda_context::eq_cuda_context(int id) + : device_id(id) +{ + solutions = nullptr; + + dev_init.lock(); + if (!dev_init_done[device_id]) + { + // only first thread shall init device + checkCudaErrors(cudaSetDevice(device_id)); + checkCudaErrors(cudaDeviceReset()); + checkCudaErrors(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync)); + + pctx = nullptr; + } + else + { + // create new context + CUdevice dev; + +#ifdef WIN32 + if (_cuDeviceGet == nullptr) + { + HMODULE hmod = LoadLibraryA("nvcuda.dll"); + if (hmod == NULL) + throw std::runtime_error("Failed to load nvcuda.dll"); + _cuDeviceGet = (dec_cuDeviceGet)GetProcAddress(hmod, "cuDeviceGet"); + if (_cuDeviceGet == nullptr) + throw std::runtime_error("Failed to get cuDeviceGet address"); + _cuCtxCreate = (dec_cuCtxCreate)GetProcAddress(hmod, "cuCtxCreate_v2"); + if (_cuCtxCreate == nullptr) + throw std::runtime_error("Failed to get cuCtxCreate address"); + _cuCtxPushCurrent = (dec_cuCtxPushCurrent)GetProcAddress(hmod, "cuCtxPushCurrent_v2"); + if (_cuCtxPushCurrent == nullptr) + throw std::runtime_error("Failed to get cuCtxPushCurrent address"); + _cuCtxDestroy = (dec_cuCtxDestroy)GetProcAddress(hmod, "cuCtxDestroy_v2"); + if (_cuCtxDestroy == nullptr) + throw std::runtime_error("Failed to get cuCtxDestroy address"); + } + + + checkCudaDriverErrors(_cuDeviceGet(&dev, device_id)); + checkCudaDriverErrors(_cuCtxCreate(&pctx, CU_CTX_SCHED_BLOCKING_SYNC, dev)); + checkCudaDriverErrors(_cuCtxPushCurrent(pctx)); +#else + checkCudaDriverErrors(cuDeviceGet(&dev, device_id)); + checkCudaDriverErrors(cuCtxCreate(&pctx, CU_CTX_SCHED_BLOCKING_SYNC, dev)); + checkCudaDriverErrors(cuCtxPushCurrent(pctx)); +#endif + } + ++dev_init_done[device_id]; + dev_init.unlock(); + + if (cudaMalloc((void**)&device_eq, sizeof(equi)) != cudaSuccess) + throw std::runtime_error("CUDA: failed to alloc memory"); + + solutions = (scontainerreal*)malloc(sizeof(scontainerreal)); +} + + +template +__host__ void eq_cuda_context::solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef) +{ + blake2b_state blake_ctx; + + int blocks = NBUCKETS; + + setheader(&blake_ctx, tequihash_header, tequihash_header_len, nonce, nonce_len); + + // todo: improve + // djezo solver allows last 4 bytes of nonce to be iterrated + // this can be used to create internal loop - calc initial blake hash only once, then load 8*8 bytes on device (blake state h) + // then just iterate nn++ + // less CPU load, 1 cudaMemcpy less -> faster + //u32 nn = *(u32*)&nonce[28]; + u32 nn = 0; + + checkCudaErrors(cudaMemcpy(&device_eq->blake_h, &blake_ctx.h, sizeof(u64) * 8, cudaMemcpyHostToDevice)); + + checkCudaErrors(cudaMemset(&device_eq->edata, 0, sizeof(device_eq->edata))); + + digit_first << > >(device_eq, nn); + + digit_1 << <4096, 512 >> >(device_eq); + + digit_2 << > >(device_eq); + + digit_3 << > >(device_eq); + + if (cancelf()) return; + + digit_4 << > >(device_eq); + + digit_5 << > >(device_eq); + + digit_6 << > >(device_eq); + + digit_7 << > >(device_eq); + + digit_8 << > >(device_eq); + + digit_last_wdc << <4096, 256 / 2 >> >(device_eq); + + checkCudaErrors(cudaMemcpy(solutions, &device_eq->edata.srealcont, (MAXREALSOLS * (512 * 4)) + 4, cudaMemcpyDeviceToHost)); + + //printf("nsols: %u\n", solutions->nsols); + //if (solutions->nsols > 9) + // printf("missing sol, total: %u\n", solutions->nsols); + + for (u32 s = 0; (s < solutions->nsols) && (s < MAXREALSOLS); s++) + { + // remove dups on CPU (dup removal on GPU is not fully exact and can pass on some invalid solutions) + if (duped(solutions->sols[s])) continue; + + // perform sort of pairs + for (uint32_t level = 0; level < 9; level++) + for (uint32_t i = 0; i < (1 << 9); i += (2 << level)) + sort_pair(&solutions->sols[s][i], 1 << level); + + std::vector index_vector(PROOFSIZE); + for (u32 i = 0; i < PROOFSIZE; i++) { + index_vector[i] = solutions->sols[s][i]; + } + + solutionf(index_vector, DIGITBITS, nullptr); + } + + hashdonef(); +} + + +template +__host__ eq_cuda_context::~eq_cuda_context() +{ + if (solutions) + free(solutions); + + cudaFree(device_eq); + + if (pctx) + { + // non primary thread, destroy context +#ifdef WIN32 + checkCudaDriverErrors(_cuCtxDestroy(pctx)); +#else + checkCudaDriverErrors(cuCtxDestroy(pctx)); +#endif + } + else + { + checkCudaErrors(cudaDeviceReset()); + + dev_init_done[device_id] = 0; + } +} + + +#ifdef CONFIG_MODE_1 +template class eq_cuda_context; +#endif + +#ifdef CONFIG_MODE_2 +template class eq_cuda_context; +#endif + +#ifdef CONFIG_MODE_3 +template class eq_cuda_context; +#endif \ No newline at end of file diff --git a/nheqminer/libstratum/ZcashStratum.cpp b/nheqminer/libstratum/ZcashStratum.cpp index 6c7758c20..7188466e3 100644 --- a/nheqminer/libstratum/ZcashStratum.cpp +++ b/nheqminer/libstratum/ZcashStratum.cpp @@ -6,7 +6,6 @@ #include "ZcashStratum.h" #include "utilstrencodings.h" -//#include "trompequihash/equi_miner.h" #include "streams.h" #include @@ -278,6 +277,7 @@ void static ZcashMinerThread(ZcashMiner* mi catch (const std::runtime_error &e) { BOOST_LOG_CUSTOM(error, pos) << e.what(); + exit(0); } try @@ -404,7 +404,7 @@ ZcashMiner::~ZcashMiner() template std::string ZcashMiner::userAgent() { - return "equihashminer/" STANDALONE_MINER_VERSION; + return "nheqminer/" STANDALONE_MINER_VERSION; } template @@ -608,13 +608,13 @@ void ZcashMiner::failedSolution() } // XMP -template class ZcashMiner; -template class ZcashMiner; +template class ZcashMiner; +template class ZcashMiner; template class ZcashMiner; template class ZcashMiner; // Silentarmy -template class ZcashMiner; -template class ZcashMiner; +template class ZcashMiner; +template class ZcashMiner; template class ZcashMiner; template class ZcashMiner; @@ -687,7 +687,11 @@ int benchmark_thread(int tid, Solver& extra) const char *tequihash_header = (char *)&ss[0]; unsigned int tequihash_header_len = ss.size(); + Solver::start(extra); + while (benchmark_solve_equihash(pblock, tequihash_header, tequihash_header_len, extra)) {} + + Solver::stop(extra); } catch (const std::runtime_error &e) { @@ -733,7 +737,7 @@ void ZcashMiner::doBenchmark(int hashes, in BOOST_LOG_TRIVIAL(info) << "Benchmarking CUDA worker (" << context->getname() << ") " << context->getdevinfo(); - CUDASolver::start(*context); // init CUDA before to get more accurate benchmark + //CUDASolver::start(*context); // init CUDA before to get more accurate benchmark cuda_contexts.push_back(context); } @@ -750,7 +754,7 @@ void ZcashMiner::doBenchmark(int hashes, in BOOST_LOG_TRIVIAL(info) << "Benchmarking OPENCL worker (" << context->getname() << ") " << context->getdevinfo(); - OPENCLSolver::start(*context); // init OPENCL before to get more accurate benchmark + //OPENCLSolver::start(*context); // init OPENCL before to get more accurate benchmark opencl_contexts.push_back(context); } @@ -768,7 +772,7 @@ void ZcashMiner::doBenchmark(int hashes, in CPUSolver* context = new CPUSolver(); context->use_opt = use_avx2; BOOST_LOG_TRIVIAL(info) << "Benchmarking CPU worker (" << context->getname() << ") " << context->getdevinfo(); - CPUSolver::start(*context); + //CPUSolver::start(*context); cpu_contexts.push_back(context); } @@ -776,9 +780,7 @@ void ZcashMiner::doBenchmark(int hashes, in std::thread* bthreads = new std::thread[nThreads]; - BOOST_LOG_TRIVIAL(info) << "Benchmark starting... this may take several minutes, please wait..."; - - auto start = std::chrono::high_resolution_clock::now(); + benchmark_work.lock(); int i = 0; for ( ; i < cpu_contexts.size(); ++i) @@ -790,6 +792,13 @@ void ZcashMiner::doBenchmark(int hashes, in for (; i < (opencl_contexts.size() + cuda_contexts.size() + cpu_contexts.size()); ++i) bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, *opencl_contexts.at(i - cpu_contexts.size() - cuda_contexts.size()))); + Sleep(1000); + + BOOST_LOG_TRIVIAL(info) << "Benchmark starting... this may take several minutes, please wait..."; + + benchmark_work.unlock(); + auto start = std::chrono::high_resolution_clock::now(); + for (int i = 0; i < nThreads; ++i) bthreads[i].join(); @@ -801,17 +810,17 @@ void ZcashMiner::doBenchmark(int hashes, in for (auto it = cpu_contexts.begin(); it != cpu_contexts.end(); ++it) { - CPUSolver::stop(**it); + //CPUSolver::stop(**it); delete (*it); } for (auto it = cuda_contexts.begin(); it != cuda_contexts.end(); ++it) { - CUDASolver::stop(**it); + //CUDASolver::stop(**it); delete (*it); } for (auto it = opencl_contexts.begin(); it != opencl_contexts.end(); ++it) { - OPENCLSolver::stop(**it); + //OPENCLSolver::stop(**it); delete (*it); } cpu_contexts.clear(); diff --git a/nheqminer/libstratum/ZcashStratum.h b/nheqminer/libstratum/ZcashStratum.h index 7b8940fbb..514cd8903 100644 --- a/nheqminer/libstratum/ZcashStratum.h +++ b/nheqminer/libstratum/ZcashStratum.h @@ -30,7 +30,7 @@ CREATE_SOLVER_STUB(cpu_xenoncat, "cpu_xenoncat_STUB") #endif #ifdef USE_CUDA_TROMP #include "../cuda_tromp/cuda_tromp.hpp" - +#include "../cuda_djezo/cuda_djezo.hpp" // TODO fix this #ifndef WIN32 CREATE_SOLVER_STUB(cuda_tromp_75, "cuda_tromp_75_STUB") @@ -154,13 +154,13 @@ class ZcashMiner // 8 combos make sure not to go beyond this // ocl_xmp -typedef ZcashMiner ZMinerAVXCUDA80_XMP; -typedef ZcashMiner ZMinerSSE2CUDA80_XMP; +typedef ZcashMiner ZMinerAVXCUDA80_XMP; +typedef ZcashMiner ZMinerSSE2CUDA80_XMP; typedef ZcashMiner ZMinerAVXCUDA75_XMP; typedef ZcashMiner ZMinerSSE2CUDA75_XMP; // ocl_silentarmy -typedef ZcashMiner ZMinerAVXCUDA80_SA; -typedef ZcashMiner ZMinerSSE2CUDA80_SA; +typedef ZcashMiner ZMinerAVXCUDA80_SA; +typedef ZcashMiner ZMinerSSE2CUDA80_SA; typedef ZcashMiner ZMinerAVXCUDA75_SA; typedef ZcashMiner ZMinerSSE2CUDA75_SA; diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index 8f0c76dde..2d503f8d1 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -43,13 +43,13 @@ namespace keywords = boost::log::keywords; #endif // TODO: -// fix compiler issues with standard vs2013 compiler // file logging // mingw compilation for windows (faster?) +// benchmark accuracy fix: first wait for solvers to init and then measure speed int use_avx = 0; int use_avx2 = 0; -int use_old_cuda = 1; +int use_old_cuda = 0; int use_old_xmp = 0; // _XMP @@ -96,7 +96,7 @@ void print_help() std::cout << std::endl; std::cout << "NVIDIA CUDA settings" << std::endl; std::cout << "\t-ci\t\tCUDA info" << std::endl; - std::cout << "\t-cv [ver]\tSet CUDA version (0 = 8.0, 1 = 7.5)" << std::endl; + std::cout << "\t-cv [ver]\tSet CUDA solver (0 = djeZo, 1 = tromp)" << std::endl; std::cout << "\t-cd [devices]\tEnable CUDA mining on spec. devices" << std::endl; std::cout << "\t-cb [blocks]\tNumber of blocks" << std::endl; std::cout << "\t-ct [tpb]\tNumber of threads per block" << std::endl; @@ -241,16 +241,16 @@ int main(int argc, char* argv[]) std::cout << "\t==================== www.nicehash.com ====================" << std::endl; std::cout << "\t\tEquihash CPU&GPU Miner for NiceHash v" STANDALONE_MINER_VERSION << std::endl; std::cout << "\tThanks to Zcash developers for providing base of the code." << std::endl; - std::cout << "\t Special thanks to tromp, xenoncat, mbevand "<< std::endl; + std::cout << "\t Special thanks to tromp, xenoncat, mbevand, djeZo, "<< std::endl; std::cout << "\t and eXtremal-ik7 for providing " << std::endl; std::cout << "\t optimized CPU, CUDA and AMD equihash solvers." << std::endl; std::cout << "\t==================== www.nicehash.com ====================" << std::endl; std::cout << std::endl; std::string location = "equihash.eu.nicehash.com:3357"; - std::string user = ""; + std::string user = "34HKWdzLxWBduUfJE9JxaFhoXnfC6gmePG"; std::string password = "x"; - int num_threads = -1; + int num_threads = 0; bool benchmark = false; int log_level = 2; int num_hashes = 200; diff --git a/nheqminer/nheqminer.sln b/nheqminer/nheqminer.sln index 0359f7bac..11eece2c6 100644 --- a/nheqminer/nheqminer.sln +++ b/nheqminer/nheqminer.sln @@ -5,9 +5,11 @@ VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nheqminer", "nheqminer.vcxproj", "{6FF7D209-05A3-4550-93CC-211D33503719}" ProjectSection(ProjectDependencies) = postProject + {AB01E715-795A-4089-8DF0-AE6EBDC1AB48} = {AB01E715-795A-4089-8DF0-AE6EBDC1AB48} {299E011B-5242-4EDA-B2F2-73C9B48F12FD} = {299E011B-5242-4EDA-B2F2-73C9B48F12FD} {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B} = {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B} {33C2B469-F025-4223-B9B6-E69D42FEA7D6} = {33C2B469-F025-4223-B9B6-E69D42FEA7D6} + {5DBCE38A-C8D2-4498-A92A-9AF8D5196135} = {5DBCE38A-C8D2-4498-A92A-9AF8D5196135} {5EC9EDEB-8E49-4126-9161-1560683CBC71} = {5EC9EDEB-8E49-4126-9161-1560683CBC71} EndProjectSection EndProject @@ -23,124 +25,90 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ocl_device_utils", "..\ocl_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ocl_silentarmy", "..\ocl_silentarmy\ocl_silentarmy.vcxproj", "{AB01E715-795A-4089-8DF0-AE6EBDC1AB48}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cuda_djezo", "..\cuda_djezo\cuda_djezo.vcxproj", "{268B10AD-D845-498B-8663-AB8911CA2039}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 - Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 Release|x64 = Release|x64 - ReleaseSlow|Mixed Platforms = ReleaseSlow|Mixed Platforms ReleaseSlow|Win32 = ReleaseSlow|Win32 ReleaseSlow|x64 = ReleaseSlow|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6FF7D209-05A3-4550-93CC-211D33503719}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {6FF7D209-05A3-4550-93CC-211D33503719}.Debug|Mixed Platforms.Build.0 = Debug|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Debug|Win32.ActiveCfg = Debug|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Debug|x64.ActiveCfg = Debug|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Debug|x64.Build.0 = Debug|x64 - {6FF7D209-05A3-4550-93CC-211D33503719}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {6FF7D209-05A3-4550-93CC-211D33503719}.Release|Mixed Platforms.Build.0 = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Release|Win32.ActiveCfg = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Release|x64.ActiveCfg = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.Release|x64.Build.0 = Release|x64 - {6FF7D209-05A3-4550-93CC-211D33503719}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release|x64 - {6FF7D209-05A3-4550-93CC-211D33503719}.ReleaseSlow|Mixed Platforms.Build.0 = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.ReleaseSlow|Win32.ActiveCfg = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.ReleaseSlow|x64.ActiveCfg = Release|x64 {6FF7D209-05A3-4550-93CC-211D33503719}.ReleaseSlow|x64.Build.0 = Release|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Debug|Mixed Platforms.Build.0 = Debug|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Debug|Win32.ActiveCfg = Debug|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Debug|x64.ActiveCfg = Debug|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Debug|x64.Build.0 = Debug|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Release|Mixed Platforms.Build.0 = Release|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Release|Win32.ActiveCfg = Release|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Release|x64.ActiveCfg = Release|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.Release|x64.Build.0 = Release|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release7.5|x64 - {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.ReleaseSlow|Mixed Platforms.Build.0 = Release7.5|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.ReleaseSlow|Win32.ActiveCfg = Release7.5|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.ReleaseSlow|x64.ActiveCfg = Release7.5|x64 {33C2B469-F025-4223-B9B6-E69D42FEA7D6}.ReleaseSlow|x64.Build.0 = Release7.5|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Debug|Mixed Platforms.Build.0 = Debug|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Debug|Win32.ActiveCfg = Debug|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Debug|x64.ActiveCfg = Debug|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Debug|x64.Build.0 = Debug|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Release|Mixed Platforms.Build.0 = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Release|Win32.ActiveCfg = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Release|x64.ActiveCfg = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.Release|x64.Build.0 = Release|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release|x64 - {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.ReleaseSlow|Mixed Platforms.Build.0 = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.ReleaseSlow|Win32.ActiveCfg = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.ReleaseSlow|x64.ActiveCfg = Release|x64 {299E011B-5242-4EDA-B2F2-73C9B48F12FD}.ReleaseSlow|x64.Build.0 = Release|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Debug|Mixed Platforms.Build.0 = Debug|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Debug|Win32.ActiveCfg = Debug|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Debug|x64.ActiveCfg = Debug|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Debug|x64.Build.0 = Debug|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Release|Mixed Platforms.Build.0 = Release|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Release|Win32.ActiveCfg = Release|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Release|x64.ActiveCfg = Release|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.Release|x64.Build.0 = Release|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|Mixed Platforms.ActiveCfg = ReleaseSSE2|x64 - {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|Mixed Platforms.Build.0 = ReleaseSSE2|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|Win32.ActiveCfg = ReleaseSSE2|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|x64.ActiveCfg = ReleaseSSE2|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|x64.Build.0 = ReleaseSSE2|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|Mixed Platforms.Build.0 = Debug|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|Win32.ActiveCfg = Debug|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|x64.ActiveCfg = Debug|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|x64.Build.0 = Debug|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|Mixed Platforms.Build.0 = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|Win32.ActiveCfg = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|x64.ActiveCfg = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|x64.Build.0 = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|Mixed Platforms.Build.0 = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|Win32.ActiveCfg = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|x64.ActiveCfg = Release|x64 {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|x64.Build.0 = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|Mixed Platforms.Build.0 = Debug|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|Win32.ActiveCfg = Debug|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|x64.ActiveCfg = Debug|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|x64.Build.0 = Debug|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|Mixed Platforms.Build.0 = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|Win32.ActiveCfg = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|x64.ActiveCfg = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|x64.Build.0 = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|Mixed Platforms.Build.0 = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|Win32.ActiveCfg = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|x64.ActiveCfg = Release|x64 {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|x64.Build.0 = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|Mixed Platforms.Build.0 = Debug|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|Win32.ActiveCfg = Debug|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|x64.ActiveCfg = Debug|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|x64.Build.0 = Debug|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|Mixed Platforms.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|Mixed Platforms.Build.0 = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|Win32.ActiveCfg = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|x64.ActiveCfg = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|x64.Build.0 = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|Mixed Platforms.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|Mixed Platforms.Build.0 = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|Win32.ActiveCfg = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|x64.ActiveCfg = Release|x64 {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|x64.Build.0 = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|Win32.ActiveCfg = Debug|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|x64.ActiveCfg = Debug|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|x64.Build.0 = Debug|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Release|Win32.ActiveCfg = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Release|x64.ActiveCfg = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.Release|x64.Build.0 = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.ReleaseSlow|Win32.ActiveCfg = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.ReleaseSlow|x64.ActiveCfg = Release|x64 + {268B10AD-D845-498B-8663-AB8911CA2039}.ReleaseSlow|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/nheqminer/nheqminer.vcxproj b/nheqminer/nheqminer.vcxproj index 032382760..a2439178f 100644 --- a/nheqminer/nheqminer.vcxproj +++ b/nheqminer/nheqminer.vcxproj @@ -96,7 +96,7 @@ true true true - cuda_tromp.lib;cuda_tromp_75.lib;cpu_xenoncat.lib;cpu_tromp_SSE2.lib;cpu_tromp_AVX.lib;ocl_device_utils.lib;ocl_xpm.lib;ocl_silentarmy.lib;OpenCL.lib + cuda_djezo.lib;cuda_tromp.lib;cuda_tromp_75.lib;cpu_xenoncat.lib;cpu_tromp_SSE2.lib;cpu_tromp_AVX.lib;ocl_device_utils.lib;ocl_xpm.lib;ocl_silentarmy.lib;OpenCL.lib .\trompequihash\pthreads\x64;..\3rdparty\libs\win64;$(AMDAPPSDKROOT)\lib\x86_64\;%(AdditionalLibraryDirectories) @@ -105,6 +105,7 @@ + diff --git a/nheqminer/nheqminer.vcxproj.filters b/nheqminer/nheqminer.vcxproj.filters index 80dca38c7..d951b0e86 100644 --- a/nheqminer/nheqminer.vcxproj.filters +++ b/nheqminer/nheqminer.vcxproj.filters @@ -167,6 +167,9 @@ Header Files + + Header Files\solvers + diff --git a/nheqminer/speed.hpp b/nheqminer/speed.hpp index b758a1a2e..beeea05fd 100644 --- a/nheqminer/speed.hpp +++ b/nheqminer/speed.hpp @@ -1,6 +1,6 @@ #pragma once -#define INTERVAL_SECONDS 300 // 5 minutes +#define INTERVAL_SECONDS 15 // 15 seconds class Speed { diff --git a/nheqminer/version.h b/nheqminer/version.h index 716eb2bae..21ecceb84 100644 --- a/nheqminer/version.h +++ b/nheqminer/version.h @@ -34,7 +34,7 @@ static const int BIP0031_VERSION = 60000; //! "mempool" command, enhanced "getdata" behavior starts with this version static const int MEMPOOL_GD_VERSION = 60002; -#define STANDALONE_MINER_VERSION "0.4b" +#define STANDALONE_MINER_VERSION "0.5a" // uncomment to use with ZCash address //#define ZCASH_POOL From 2a6eb0516c213149b4a028e7b82a32b8737886bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 04:57:37 +0100 Subject: [PATCH 04/15] remove templated code, code cleanup --- nheqminer/AvailableSolvers.cpp | 2 + nheqminer/AvailableSolvers.h | 93 ++++++ nheqminer/ISolver.h | 34 +++ nheqminer/MinerFactory.cpp | 80 +++++ nheqminer/MinerFactory.h | 31 ++ nheqminer/Solver.h | 57 ++++ nheqminer/libstratum/StratumClient.cpp | 12 +- nheqminer/libstratum/StratumClient.h | 12 +- nheqminer/libstratum/ZcashStratum.cpp | 399 +++++++------------------ nheqminer/libstratum/ZcashStratum.h | 82 +---- nheqminer/main.cpp | 135 ++------- nheqminer/nheqminer.vcxproj | 6 + nheqminer/nheqminer.vcxproj.filters | 18 ++ 13 files changed, 465 insertions(+), 496 deletions(-) create mode 100644 nheqminer/AvailableSolvers.cpp create mode 100644 nheqminer/AvailableSolvers.h create mode 100644 nheqminer/ISolver.h create mode 100644 nheqminer/MinerFactory.cpp create mode 100644 nheqminer/MinerFactory.h create mode 100644 nheqminer/Solver.h diff --git a/nheqminer/AvailableSolvers.cpp b/nheqminer/AvailableSolvers.cpp new file mode 100644 index 000000000..cd6d6f3e6 --- /dev/null +++ b/nheqminer/AvailableSolvers.cpp @@ -0,0 +1,2 @@ +#include "AvailableSolvers.h" + diff --git a/nheqminer/AvailableSolvers.h b/nheqminer/AvailableSolvers.h new file mode 100644 index 000000000..3adfd9840 --- /dev/null +++ b/nheqminer/AvailableSolvers.h @@ -0,0 +1,93 @@ +#pragma once + +#include "Solver.h" +#include "SolverStub.h" + + +#ifdef USE_CPU_TROMP +#include "../cpu_tromp/cpu_tromp.hpp" +#else +CREATE_SOLVER_STUB(cpu_tromp, "cpu_tromp_STUB") +#endif +#ifdef USE_CPU_XENONCAT +#include "../cpu_xenoncat/cpu_xenoncat.hpp" +#else +CREATE_SOLVER_STUB(cpu_xenoncat, "cpu_xenoncat_STUB") +#endif +#ifdef USE_CUDA_TROMP +#include "../cuda_tromp/cuda_tromp.hpp" +#include "../cuda_djezo/cuda_djezo.hpp" +#else +CREATE_SOLVER_STUB(cuda_tromp, "cuda_tromp_STUB") +CREATE_SOLVER_STUB(cuda_djezo, "cuda_djezo_STUB") +#endif +#ifdef USE_OCL_XMP +#include "../ocl_xpm/ocl_xmp.hpp" +#else +CREATE_SOLVER_STUB(ocl_xmp, "ocl_xmp_STUB") +#endif +#ifdef USE_OCL_SILENTARMY +#include "../ocl_silentarmy/ocl_silentarmy.hpp" +#else +CREATE_SOLVER_STUB(ocl_silentarmy, "ocl_silentarmy_STUB") +#endif + +//namespace AvailableSolvers +//{ +//} // AvailableSolvers + +// CPU solvers +class CPUSolverTromp : public Solver { +public: + CPUSolverTromp(int use_opt) : Solver(new cpu_tromp(), SolverType::CPU) { + _context->use_opt = use_opt; + } + virtual ~CPUSolverTromp() {} +}; +class CPUSolverXenoncat : public Solver { +public: + CPUSolverXenoncat(int use_opt) : Solver(new cpu_xenoncat(), SolverType::CPU) { + _context->use_opt = use_opt; + } + virtual ~CPUSolverXenoncat() {} +}; +// TODO remove platform id for cuda solvers +// CUDA solvers +class CUDASolverDjezo : public Solver { +public: + CUDASolverDjezo(int dev_id, int blocks, int threadsperblock) : Solver(new cuda_djezo(0, dev_id), SolverType::CUDA) { + if (blocks > 0) { + _context->blocks = blocks; + } + if (threadsperblock > 0) { + _context->threadsperblock = threadsperblock; + } + } + virtual ~CUDASolverDjezo() {} +}; +class CUDASolverTromp : public Solver { +public: + CUDASolverTromp(int dev_id, int blocks, int threadsperblock) : Solver(new cuda_tromp(0, dev_id), SolverType::CUDA) { + if (blocks > 0) { + _context->blocks = blocks; + } + if (threadsperblock > 0) { + _context->threadsperblock = threadsperblock; + } + } + virtual ~CUDASolverTromp() {} +}; +// OpenCL solvers +class OPENCLSolverSilentarmy : public Solver { +public: + OPENCLSolverSilentarmy(int platf_id, int dev_id) : Solver(new ocl_silentarmy(platf_id, dev_id), SolverType::OPENCL) { + } + virtual ~OPENCLSolverSilentarmy() {} +}; +class OPENCLSolverXMP : public Solver { +public: + OPENCLSolverXMP(int platf_id, int dev_id) : Solver(new ocl_xmp(platf_id, dev_id), SolverType::OPENCL) { + } + virtual ~OPENCLSolverXMP() {} +}; + diff --git a/nheqminer/ISolver.h b/nheqminer/ISolver.h new file mode 100644 index 000000000..bad815f66 --- /dev/null +++ b/nheqminer/ISolver.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include + +enum class SolverType { + CPU = 0, + CUDA, + OPENCL +}; + +class ISolver +{ +public: + //ISolver() { } + //virtual ~ISolver() { } + virtual void start() = 0; + virtual void stop() = 0; + + virtual void solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef) = 0; + + virtual std::string getdevinfo() = 0; + virtual std::string getname() = 0; + virtual SolverType GetType() const = 0; +}; + diff --git a/nheqminer/MinerFactory.cpp b/nheqminer/MinerFactory.cpp new file mode 100644 index 000000000..dd6a06bee --- /dev/null +++ b/nheqminer/MinerFactory.cpp @@ -0,0 +1,80 @@ +#include "MinerFactory.h" + +#include + +extern int use_avx; +extern int use_avx2; + +MinerFactory::~MinerFactory() +{ +} + +std::vector MinerFactory::GenerateSolvers(int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, + int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { + std::vector solversPointers; + + for (int i = 0; i < cuda_count; ++i) { + solversPointers.push_back(GenCUDASolver(cuda_en[i], cuda_b[i], cuda_t[i])); + } + + for (int i = 0; i < opencl_count; ++i) + { + if (opencl_t[i] < 1) opencl_t[i] = 1; + + // add multiple threads if wanted + for (int k = 0; k < opencl_t[i]; ++k) { + // todo: save local&global work size, new solvers + solversPointers.push_back(GenOPENCLSolver(opencl_platf, opencl_en[i])); + } + } + + bool hasGpus = solversPointers.size() > 0; + if (cpu_threads < 0) { + cpu_threads = std::thread::hardware_concurrency(); + if (cpu_threads < 1) cpu_threads = 1; + else if (hasGpus) --cpu_threads; // decrease number of threads if there are GPU workers + } + + for (int i = 0; i < cpu_threads; ++i) + { + solversPointers.push_back(GenCPUSolver(use_avx2)); + } + + return solversPointers; +} + +void MinerFactory::ClearAllSolvers() { + _solvers.clear(); +} + +ISolver * MinerFactory::GenCPUSolver(int use_opt) { + if (_use_xenoncat) { + _solvers.push_back(std::make_unique(use_opt)); + return _solvers.back().get(); + } else { + _solvers.push_back(std::make_unique(use_opt)); + return _solvers.back().get(); + } +} + +ISolver * MinerFactory::GenCUDASolver(int dev_id, int blocks, int threadsperblock) { + if (_use_cuda_djezo) { + _solvers.push_back(std::make_unique(dev_id, blocks, threadsperblock)); + return _solvers.back().get(); + } + else { + _solvers.push_back(std::make_unique(dev_id, blocks, threadsperblock)); + return _solvers.back().get(); + } +} + +ISolver * MinerFactory::GenOPENCLSolver(int platf_id, int dev_id) { + if (_use_silentarmy) { + _solvers.push_back(std::make_unique(platf_id, dev_id)); + return _solvers.back().get(); + } + else { + _solvers.push_back(std::make_unique(platf_id, dev_id)); + return _solvers.back().get(); + } +} \ No newline at end of file diff --git a/nheqminer/MinerFactory.h b/nheqminer/MinerFactory.h new file mode 100644 index 000000000..4a72e8075 --- /dev/null +++ b/nheqminer/MinerFactory.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +class MinerFactory +{ +public: + MinerFactory(bool use_xenoncat, bool use_cuda_djezo, bool use_silentarmy) + : _use_xenoncat(use_xenoncat), _use_cuda_djezo(use_cuda_djezo), _use_silentarmy(use_silentarmy) { + } + + ~MinerFactory(); + + std::vector GenerateSolvers(int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, + int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); + void ClearAllSolvers(); + +private: + std::vector> _solvers; + + bool _use_xenoncat = true; + bool _use_cuda_djezo = true; + bool _use_silentarmy = true; + + ISolver * GenCPUSolver(int use_opt); + ISolver * GenCUDASolver(int dev_id, int blocks, int threadsperblock); + ISolver * GenOPENCLSolver(int platf_id, int dev_id); + +}; + diff --git a/nheqminer/Solver.h b/nheqminer/Solver.h new file mode 100644 index 000000000..7ebb8c100 --- /dev/null +++ b/nheqminer/Solver.h @@ -0,0 +1,57 @@ +#pragma once + +#include "ISolver.h" + +template +class Solver : public ISolver +{ +protected: + const SolverType _type; + StaticInterface * const _context = nullptr; +public: + Solver(StaticInterface *contex, SolverType type) : _context(contex), _type(type){} + virtual ~Solver() { + // the solver owns the context should delete it + if (_context != nullptr) { + delete _context; + } + } + + virtual void start() override { + StaticInterface::start(*_context); + } + + virtual void stop() override { + StaticInterface::stop(*_context); + } + + virtual void solve(const char *tequihash_header, + unsigned int tequihash_header_len, + const char* nonce, + unsigned int nonce_len, + std::function cancelf, + std::function&, size_t, const unsigned char*)> solutionf, + std::function hashdonef) override { + StaticInterface::solve( + tequihash_header, + tequihash_header_len, + nonce, + nonce_len, + cancelf, + solutionf, + hashdonef, + *_context); + } + + virtual std::string getdevinfo() override { + return _context->getdevinfo(); + } + + virtual std::string getname() override { + return _context->getname(); + } + + virtual SolverType GetType() const override { + return _type; + } +}; \ No newline at end of file diff --git a/nheqminer/libstratum/StratumClient.cpp b/nheqminer/libstratum/StratumClient.cpp index 50dbb6f1f..165f1a007 100644 --- a/nheqminer/libstratum/StratumClient.cpp +++ b/nheqminer/libstratum/StratumClient.cpp @@ -421,13 +421,5 @@ bool StratumClient::submit(const Solution* solution, const return true; } -// XMP -template class StratumClient; -template class StratumClient; -template class StratumClient; -template class StratumClient; -// Silentarmy -template class StratumClient; -template class StratumClient; -template class StratumClient; -template class StratumClient; \ No newline at end of file +// create StratumClient class +template class StratumClient; \ No newline at end of file diff --git a/nheqminer/libstratum/StratumClient.h b/nheqminer/libstratum/StratumClient.h index 373baf183..eff327812 100644 --- a/nheqminer/libstratum/StratumClient.h +++ b/nheqminer/libstratum/StratumClient.h @@ -162,13 +162,5 @@ class StratumClient }; -// XMP -typedef StratumClient ZcashStratumClientAVXCUDA80_XMP; -typedef StratumClient ZcashStratumClientSSE2CUDA80_XMP; -typedef StratumClient ZcashStratumClientAVXCUDA75_XMP; -typedef StratumClient ZcashStratumClientSSE2CUDA75_XMP; -// Silentarmy -typedef StratumClient ZcashStratumClientAVXCUDA80_SA; -typedef StratumClient ZcashStratumClientSSE2CUDA80_SA; -typedef StratumClient ZcashStratumClientAVXCUDA75_SA; -typedef StratumClient ZcashStratumClientSSE2CUDA75_SA; \ No newline at end of file +// ZcashStratumClient +typedef StratumClient ZcashStratumClient; \ No newline at end of file diff --git a/nheqminer/libstratum/ZcashStratum.cpp b/nheqminer/libstratum/ZcashStratum.cpp index 7188466e3..1106d02b5 100644 --- a/nheqminer/libstratum/ZcashStratum.cpp +++ b/nheqminer/libstratum/ZcashStratum.cpp @@ -95,10 +95,10 @@ std::vector GetMinimalFromIndices(std::vector indices, return ret; } -template -void static ZcashMinerThread(ZcashMiner* miner, int size, int pos, Solver& extra) + +void static ZcashMinerThread(ZcashMiner* miner, int size, int pos, ISolver *solver) { - BOOST_LOG_CUSTOM(info, pos) << "Starting thread #" << pos << " (" << extra.getname() << ") " << extra.getdevinfo(); + BOOST_LOG_CUSTOM(info, pos) << "Starting thread #" << pos << " (" << solver->getname() << ") " << solver->getdevinfo(); std::shared_ptr m_zmt(new std::mutex); CBlockHeader header; @@ -140,7 +140,7 @@ void static ZcashMinerThread(ZcashMiner* mi try { - Solver::start(extra); + solver->start(); while (true) { // Wait for work @@ -235,14 +235,13 @@ void static ZcashMinerThread(ZcashMiner* mi speed.AddHash(); }; - Solver::solve(tequihash_header, + solver->solve(tequihash_header, tequihash_header_len, (const char*)bNonce.begin(), bNonce.size(), cancelFun, solutionFound, - hashDone, - extra); + hashDone); // Check for stop if (!miner->minerThreadActive[pos]) @@ -282,14 +281,14 @@ void static ZcashMinerThread(ZcashMiner* mi try { - Solver::stop(extra); + solver->stop(); } catch (const std::runtime_error &e) { BOOST_LOG_CUSTOM(error, pos) << e.what(); } - BOOST_LOG_CUSTOM(info, pos) << "Thread #" << pos << " ended (" << extra.getname() << ")"; + BOOST_LOG_CUSTOM(info, pos) << "Thread #" << pos << " ended (" << solver->getname() << ")"; } ZcashJob* ZcashJob::clone() const @@ -333,82 +332,29 @@ std::string ZcashJob::getSubmission(const EquihashSolution* solution) return stream.str(); } -template -ZcashMiner::ZcashMiner(int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) - : minerThreads{nullptr} + +ZcashMiner::ZcashMiner(const std::vector &i_solvers) + : minerThreads{ nullptr } { m_isActive = false; - nThreads = 0; - - for (int i = 0; i < cuda_count; ++i) - { - CUDASolver* context = new CUDASolver(0, cuda_en[i]); - if (cuda_b[i] > 0) - context->blocks = cuda_b[i]; - if (cuda_t[i] > 0) - context->threadsperblock = cuda_t[i]; - - cuda_contexts.push_back(context); - } - nThreads += cuda_contexts.size(); - - - for (int i = 0; i < opencl_count; ++i) - { - if (opencl_t[i] < 1) opencl_t[i] = 1; - - // add multiple threads if wanted - for (int k = 0; k < opencl_t[i]; ++k) - { - OPENCLSolver* context = new OPENCLSolver(opencl_platf, opencl_en[i]); - // todo: save local&global work size - opencl_contexts.push_back(context); - } - } - nThreads += opencl_contexts.size(); - - - - if (cpu_threads < 0) { - cpu_threads = std::thread::hardware_concurrency(); - if (cpu_threads < 1) cpu_threads = 1; - else if (cuda_contexts.size() + opencl_contexts.size() > 0) --cpu_threads; // decrease number of threads if there are GPU workers - } - - - for (int i = 0; i < cpu_threads; ++i) - { - CPUSolver* context = new CPUSolver(); - context->use_opt = use_avx2; - cpu_contexts.push_back(context); - } - nThreads += cpu_contexts.size(); - - -// nThreads = cpu_contexts.size() + cuda_contexts.size() + opencl_contexts.size(); + solvers = i_solvers; + nThreads = solvers.size(); } -template -ZcashMiner::~ZcashMiner() + +ZcashMiner::~ZcashMiner() { stop(); - for (auto it = cpu_contexts.begin(); it != cpu_contexts.end(); ++it) - delete (*it); - for (auto it = cuda_contexts.begin(); it != cuda_contexts.end(); ++it) - delete (*it); - cpu_contexts.clear(); - cuda_contexts.clear(); } -template -std::string ZcashMiner::userAgent() + +std::string ZcashMiner::userAgent() { return "nheqminer/" STANDALONE_MINER_VERSION; } -template -void ZcashMiner::start() + +void ZcashMiner::start() { if (minerThreads) { stop(); @@ -419,60 +365,71 @@ void ZcashMiner::start() minerThreads = new std::thread[nThreads]; minerThreadActive = new bool[nThreads]; - - // start cpu threads - int i = 0; - for ( ; i < cpu_contexts.size(); ++i) - { - minerThreadActive[i] = true; - minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, - this, nThreads, i, *cpu_contexts.at(i))); + // sort solvers CPU, CUDA, OPENCL + std::sort(solvers.begin(), solvers.end(), [](const ISolver* a, const ISolver* b) { return a->GetType() < b->GetType(); }); + + // start solvers + // #1 start cpu threads + // #2 start CUDA threads + // #3 start OPENCL threads + for (int i = 0; i < solvers.size(); ++i) { + minerThreadActive[i] = true; + minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, this, nThreads, i, solvers[i])); + if (solvers[i]->GetType() == SolverType::CPU) { #ifdef WIN32 - HANDLE hThread = minerThreads[i].native_handle(); - if (!SetThreadPriority(hThread, THREAD_PRIORITY_LOWEST)) - { - BOOST_LOG_CUSTOM(warning, i) << "Failed to set low priority"; - } - else - { - BOOST_LOG_CUSTOM(debug, i) << "Priority set to " << GetThreadPriority(hThread); - } + HANDLE hThread = minerThreads[i].native_handle(); + if (!SetThreadPriority(hThread, THREAD_PRIORITY_LOWEST)) + { + BOOST_LOG_CUSTOM(warning, i) << "Failed to set low priority"; + } + else + { + BOOST_LOG_CUSTOM(debug, i) << "Priority set to " << GetThreadPriority(hThread); + } #else - // todo: linux set low priority + // todo: linux set low priority #endif - } + } + } + + + //for ( ; ) + //{ + // + //} - // start CUDA threads - for (; i < (cpu_contexts.size() + cuda_contexts.size()); ++i) - { - minerThreadActive[i] = true; - minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, - this, nThreads, i, *cuda_contexts.at(i - cpu_contexts.size()))); - } + // + //for (; i < (cpu_contexts.size() + cuda_contexts.size()); ++i) + //{ + // minerThreadActive[i] = true; + // minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, + // this, nThreads, i, *cuda_contexts.at(i - cpu_contexts.size()))); + //} - // start OPENCL threads - for (; i < (cpu_contexts.size() + cuda_contexts.size() + opencl_contexts.size()); ++i) - { - minerThreadActive[i] = true; - minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, - this, nThreads, i, *opencl_contexts.at(i - cpu_contexts.size() - cuda_contexts.size()))); - } + // + //for (; i < (cpu_contexts.size() + cuda_contexts.size() + opencl_contexts.size()); ++i) + //{ + // minerThreadActive[i] = true; + // minerThreads[i] = std::thread(boost::bind(&ZcashMinerThread, + // this, nThreads, i, *opencl_contexts.at(i - cpu_contexts.size() - cuda_contexts.size()))); + //} - /*minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) { - minerThreads->create_thread(boost::bind(&ZcashMinerThread, this, nThreads, i)); - }*/ + + ///*minerThreads = new boost::thread_group(); + //for (int i = 0; i < nThreads; i++) { + // minerThreads->create_thread(boost::bind(&ZcashMinerThread, this, nThreads, i)); + //}*/ speed.Reset(); } -template -void ZcashMiner::stop() + +void ZcashMiner::stop() { m_isActive = false; if (minerThreads) @@ -492,8 +449,8 @@ void ZcashMiner::stop() }*/ } -template -void ZcashMiner::setServerNonce(const std::string& n1str) + +void ZcashMiner::setServerNonce(const std::string& n1str) { //auto n1str = params[1].get_str(); BOOST_LOG_TRIVIAL(info) << "miner | Extranonce is " << n1str; @@ -518,8 +475,8 @@ void ZcashMiner::setServerNonce(const std:: nonce2Inc <<= nonce1Bits; } -template -ZcashJob* ZcashMiner::parseJob(const Array& params) + +ZcashJob* ZcashMiner::parseJob(const Array& params) { if (params.size() < 2) { throw std::logic_error("Invalid job params"); @@ -571,59 +528,47 @@ ZcashJob* ZcashMiner::parseJob(const Array& return ret; } -template -void ZcashMiner::setJob(ZcashJob* job) + +void ZcashMiner::setJob(ZcashJob* job) { NewJob(job); } -template -void ZcashMiner::onSolutionFound( + +void ZcashMiner::onSolutionFound( const std::function callback) { solutionFoundCallback = callback; } -template -void ZcashMiner::submitSolution(const EquihashSolution& solution, const std::string& jobid) + +void ZcashMiner::submitSolution(const EquihashSolution& solution, const std::string& jobid) { solutionFoundCallback(solution, jobid); speed.AddShare(); } -template -void ZcashMiner::acceptedSolution(bool stale) + +void ZcashMiner::acceptedSolution(bool stale) { speed.AddShareOK(); } -template -void ZcashMiner::rejectedSolution(bool stale) + +void ZcashMiner::rejectedSolution(bool stale) { } -template -void ZcashMiner::failedSolution() + +void ZcashMiner::failedSolution() { } -// XMP -template class ZcashMiner; -template class ZcashMiner; -template class ZcashMiner; -template class ZcashMiner; -// Silentarmy -template class ZcashMiner; -template class ZcashMiner; -template class ZcashMiner; -template class ZcashMiner; - std::mutex benchmark_work; std::vector benchmark_nonces; std::atomic_int benchmark_solutions; -template -bool benchmark_solve_equihash(const CBlock& pblock, const char *tequihash_header, unsigned int tequihash_header_len, Solver& extra) +bool benchmark_solve_equihash(const CBlock& pblock, const char *tequihash_header, unsigned int tequihash_header_len, ISolver *solver) { benchmark_work.lock(); if (benchmark_nonces.empty()) @@ -658,24 +603,23 @@ bool benchmark_solve_equihash(const CBlock& pblock, const char *tequihash_header ++benchmark_solutions; }; - Solver::solve(tequihash_header, + solver->solve(tequihash_header, tequihash_header_len, (const char*)nonce->begin(), nonce->size(), []() { return false; }, solutionFound, - []() {}, - extra); + []() {} + ); delete nonce; return true; } -template -int benchmark_thread(int tid, Solver& extra) +int benchmark_thread(int tid, ISolver *solver) { - BOOST_LOG_TRIVIAL(debug) << "Thread #" << tid << " started (" << extra.getname() << ")"; + BOOST_LOG_TRIVIAL(debug) << "Thread #" << tid << " started (" << solver->getname() << ")"; try { @@ -687,11 +631,11 @@ int benchmark_thread(int tid, Solver& extra) const char *tequihash_header = (char *)&ss[0]; unsigned int tequihash_header_len = ss.size(); - Solver::start(extra); + solver->start(); - while (benchmark_solve_equihash(pblock, tequihash_header, tequihash_header_len, extra)) {} + while (benchmark_solve_equihash(pblock, tequihash_header, tequihash_header_len, solver)) {} - Solver::stop(extra); + solver->stop(); } catch (const std::runtime_error &e) { @@ -700,15 +644,12 @@ int benchmark_thread(int tid, Solver& extra) return 0; } - BOOST_LOG_TRIVIAL(debug) << "Thread #" << tid << " ended (" << extra.getname() << ")"; + BOOST_LOG_TRIVIAL(debug) << "Thread #" << tid << " ended (" << solver->getname() << ")"; return 0; } -template -void ZcashMiner::doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) -{ +void Solvers_doBenchmark(int hashes, const std::vector &solvers) { // generate array of various nonces std::srand(std::time(0)); benchmark_nonces.push_back(new uint256()); @@ -723,75 +664,28 @@ void ZcashMiner::doBenchmark(int hashes, in size_t total_hashes = benchmark_nonces.size(); - std::vector cpu_contexts; - std::vector cuda_contexts; - std::vector opencl_contexts; - - for (int i = 0; i < cuda_count; ++i) - { - CUDASolver* context = new CUDASolver(0, cuda_en[i]); - if (cuda_b[i] > 0) - context->blocks = cuda_b[i]; - if (cuda_t[i] > 0) - context->threadsperblock = cuda_t[i]; - - BOOST_LOG_TRIVIAL(info) << "Benchmarking CUDA worker (" << context->getname() << ") " << context->getdevinfo(); - - //CUDASolver::start(*context); // init CUDA before to get more accurate benchmark - - cuda_contexts.push_back(context); - } - - for (int i = 0; i < opencl_count; ++i) - { - if (opencl_t[i] < 1) opencl_t[i] = 1; - - for (int k = 0; k < opencl_t[i]; ++k) - { - OPENCLSolver* context = new OPENCLSolver(opencl_platf, opencl_en[i]); - - // todo: save local&global work size - - BOOST_LOG_TRIVIAL(info) << "Benchmarking OPENCL worker (" << context->getname() << ") " << context->getdevinfo(); - - //OPENCLSolver::start(*context); // init OPENCL before to get more accurate benchmark - - opencl_contexts.push_back(context); + // log what is benchmarking + for (ISolver* solver : solvers) { + if (solver->GetType() == SolverType::CPU) { + BOOST_LOG_TRIVIAL(info) << "Benchmarking CPU worker (" << solver->getname() << ") " << solver->getdevinfo(); + } + else if (solver->GetType() == SolverType::CUDA) { + BOOST_LOG_TRIVIAL(info) << "Benchmarking CUDA worker (" << solver->getname() << ") " << solver->getdevinfo(); + } + else if (solver->GetType() == SolverType::OPENCL) { + BOOST_LOG_TRIVIAL(info) << "Benchmarking OPENCL worker (" << solver->getname() << ") " << solver->getdevinfo(); } } - if (cpu_threads < 0) - { - cpu_threads = std::thread::hardware_concurrency(); - if (cpu_threads < 1) cpu_threads = 1; - else if (cuda_contexts.size() + opencl_contexts.size() > 0) --cpu_threads; // decrease number of threads if there are GPU workers - } - - for (int i = 0; i < cpu_threads; ++i) - { - CPUSolver* context = new CPUSolver(); - context->use_opt = use_avx2; - BOOST_LOG_TRIVIAL(info) << "Benchmarking CPU worker (" << context->getname() << ") " << context->getdevinfo(); - //CPUSolver::start(*context); - cpu_contexts.push_back(context); - } - - int nThreads = cpu_contexts.size() + cuda_contexts.size() + opencl_contexts.size(); - + int nThreads = solvers.size(); std::thread* bthreads = new std::thread[nThreads]; benchmark_work.lock(); - - int i = 0; - for ( ; i < cpu_contexts.size(); ++i) - bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, *cpu_contexts.at(i))); - - for (; i < (cuda_contexts.size() + cpu_contexts.size()); ++i) - bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, *cuda_contexts.at(i - cpu_contexts.size()))); - - for (; i < (opencl_contexts.size() + cuda_contexts.size() + cpu_contexts.size()); ++i) - bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, *opencl_contexts.at(i - cpu_contexts.size() - cuda_contexts.size()))); - + // bind benchmark threads + for (int i = 0; i < solvers.size(); ++i) { + bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, solvers[i])); + } + // TODO get back to this sleep Sleep(1000); BOOST_LOG_TRIVIAL(info) << "Benchmark starting... this may take several minutes, please wait..."; @@ -808,25 +702,6 @@ void ZcashMiner::doBenchmark(int hashes, in size_t hashes_done = total_hashes - benchmark_nonces.size(); - for (auto it = cpu_contexts.begin(); it != cpu_contexts.end(); ++it) - { - //CPUSolver::stop(**it); - delete (*it); - } - for (auto it = cuda_contexts.begin(); it != cuda_contexts.end(); ++it) - { - //CUDASolver::stop(**it); - delete (*it); - } - for (auto it = opencl_contexts.begin(); it != opencl_contexts.end(); ++it) - { - //OPENCLSolver::stop(**it); - delete (*it); - } - cpu_contexts.clear(); - cuda_contexts.clear(); - opencl_contexts.clear(); - BOOST_LOG_TRIVIAL(info) << "Benchmark done!"; BOOST_LOG_TRIVIAL(info) << "Total time : " << msec << " ms"; BOOST_LOG_TRIVIAL(info) << "Total iterations: " << hashes_done; @@ -834,53 +709,3 @@ void ZcashMiner::doBenchmark(int hashes, in BOOST_LOG_TRIVIAL(info) << "Speed: " << ((double)hashes_done * 1000 / (double)msec) << " I/s"; BOOST_LOG_TRIVIAL(info) << "Speed: " << ((double)benchmark_solutions * 1000 / (double)msec) << " Sols/s"; } - - -//void ZMinerAVX_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, -// int opencl_count, int opencl_platf, int* opencl_en) { -// ZMinerAVX::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en); -//} -// -//void ZMinerSSE2_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, -// int opencl_count, int opencl_platf, int* opencl_en) { -// ZMinerSSE2::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en); -//} - - - -// ocl_xmp -// gcc static undefined reference workaround -void ZMinerAVXCUDA80_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerAVXCUDA80_XMP::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerSSE2CUDA80_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerSSE2CUDA80_XMP::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerAVXCUDA75_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerAVXCUDA75_XMP::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerSSE2CUDA75_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerSSE2CUDA75_XMP::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -// ocl_silentarmy -void ZMinerAVXCUDA80_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerAVXCUDA80_SA::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerSSE2CUDA80_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerSSE2CUDA80_SA::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerAVXCUDA75_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerAVXCUDA75_SA::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} -void ZMinerSSE2CUDA75_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t) { - ZMinerSSE2CUDA75_SA::doBenchmark(hashes, cpu_threads, cuda_count, cuda_en, cuda_b, cuda_t, opencl_count, opencl_platf, opencl_en, opencl_t); -} - diff --git a/nheqminer/libstratum/ZcashStratum.h b/nheqminer/libstratum/ZcashStratum.h index 514cd8903..ad659962a 100644 --- a/nheqminer/libstratum/ZcashStratum.h +++ b/nheqminer/libstratum/ZcashStratum.h @@ -16,40 +16,7 @@ #include "json/json_spirit_value.h" -#include "SolverStub.h" - -#ifdef USE_CPU_TROMP -#include "../cpu_tromp/cpu_tromp.hpp" -#else -CREATE_SOLVER_STUB(cpu_tromp, "cpu_tromp_STUB") -#endif -#ifdef USE_CPU_XENONCAT -#include "../cpu_xenoncat/cpu_xenoncat.hpp" -#else -CREATE_SOLVER_STUB(cpu_xenoncat, "cpu_xenoncat_STUB") -#endif -#ifdef USE_CUDA_TROMP -#include "../cuda_tromp/cuda_tromp.hpp" -#include "../cuda_djezo/cuda_djezo.hpp" -// TODO fix this -#ifndef WIN32 -CREATE_SOLVER_STUB(cuda_tromp_75, "cuda_tromp_75_STUB") -#endif - -#else -CREATE_SOLVER_STUB(cuda_tromp, "cuda_tromp_STUB") -CREATE_SOLVER_STUB(cuda_tromp_75, "cuda_tromp_75_STUB") -#endif -#ifdef USE_OCL_XMP -#include "../ocl_xpm/ocl_xmp.hpp" -#else -CREATE_SOLVER_STUB(ocl_xmp, "ocl_xmp_STUB") -#endif -#ifdef USE_OCL_SILENTARMY -#include "../ocl_silentarmy/ocl_silentarmy.hpp" -#else -CREATE_SOLVER_STUB(ocl_silentarmy, "ocl_silentarmy_STUB") -#endif +#include "ISolver.h" using namespace json_spirit; @@ -108,7 +75,7 @@ inline bool operator==(const ZcashJob& a, const ZcashJob& b) typedef boost::signals2::signal NewJob_t; -template + class ZcashMiner { int nThreads; @@ -121,18 +88,13 @@ class ZcashMiner std::function solutionFoundCallback; bool m_isActive; - - std::vector cpu_contexts; - std::vector cuda_contexts; - std::vector opencl_contexts; - + std::vector solvers; public: NewJob_t NewJob; bool* minerThreadActive; - ZcashMiner(int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); + ZcashMiner(const std::vector &i_solvers); ~ZcashMiner(); std::string userAgent(); @@ -147,39 +109,7 @@ class ZcashMiner void acceptedSolution(bool stale); void rejectedSolution(bool stale); void failedSolution(); - - static void doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); }; -// 8 combos make sure not to go beyond this -// ocl_xmp -typedef ZcashMiner ZMinerAVXCUDA80_XMP; -typedef ZcashMiner ZMinerSSE2CUDA80_XMP; -typedef ZcashMiner ZMinerAVXCUDA75_XMP; -typedef ZcashMiner ZMinerSSE2CUDA75_XMP; -// ocl_silentarmy -typedef ZcashMiner ZMinerAVXCUDA80_SA; -typedef ZcashMiner ZMinerSSE2CUDA80_SA; -typedef ZcashMiner ZMinerAVXCUDA75_SA; -typedef ZcashMiner ZMinerSSE2CUDA75_SA; - -// ocl_xmp -// gcc static undefined reference workaround -void ZMinerAVXCUDA80_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerSSE2CUDA80_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerAVXCUDA75_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerSSE2CUDA75_XMP_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -// ocl_silentarmy -void ZMinerAVXCUDA80_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerSSE2CUDA80_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerAVXCUDA75_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); -void ZMinerSSE2CUDA75_SA_doBenchmark(int hashes, int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, - int opencl_count, int opencl_platf, int* opencl_en, int* opencl_t); +void Solvers_doBenchmark(int hashes, const std::vector &solvers); + diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index 2d503f8d1..49f572d8f 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -5,6 +5,8 @@ #include "primitives/block.h" #include "streams.h" +#include "MinerFactory.h" + #include "libstratum/StratumClient.h" #if defined(USE_OCL_XMP) || defined(USE_OCL_SILENTARMY) @@ -52,27 +54,16 @@ int use_avx2 = 0; int use_old_cuda = 0; int use_old_xmp = 0; -// _XMP -static ZcashStratumClientAVXCUDA80_XMP* scSigAVXC80_XMP = nullptr; -static ZcashStratumClientSSE2CUDA80_XMP* scSigSSE2C80_XMP = nullptr; -static ZcashStratumClientAVXCUDA75_XMP* scSigAVXC75_XMP = nullptr; -static ZcashStratumClientSSE2CUDA75_XMP* scSigSSE2C75_XMP = nullptr; -// _SA -static ZcashStratumClientAVXCUDA80_SA* scSigAVXC80_SA = nullptr; -static ZcashStratumClientSSE2CUDA80_SA* scSigSSE2C80_SA = nullptr; -static ZcashStratumClientAVXCUDA75_SA* scSigAVXC75_SA = nullptr; -static ZcashStratumClientSSE2CUDA75_SA* scSigSSE2C75_SA = nullptr; +// TODO move somwhere else +MinerFactory *_MinerFactory = nullptr; + +// stratum client sig +static ZcashStratumClient* scSig = nullptr; extern "C" void stratum_sigint_handler(int signum) { - if (scSigAVXC80_XMP) scSigAVXC80_XMP->disconnect(); - if (scSigSSE2C80_XMP) scSigSSE2C80_XMP->disconnect(); - if (scSigAVXC75_XMP) scSigAVXC75_XMP->disconnect(); - if (scSigSSE2C75_XMP) scSigSSE2C75_XMP->disconnect(); - if (scSigAVXC80_SA) scSigAVXC80_SA->disconnect(); - if (scSigSSE2C80_SA) scSigSSE2C80_SA->disconnect(); - if (scSigAVXC75_SA) scSigAVXC75_SA->disconnect(); - if (scSigSSE2C75_SA) scSigSSE2C75_SA->disconnect(); + if (scSig) scSig->disconnect(); + if (_MinerFactory) _MinerFactory->ClearAllSolvers(); } void print_help() @@ -180,10 +171,10 @@ void detect_AVX_and_AVX2() } } -template -void start_mining(int api_port, int cpu_threads, int cuda_device_count, int opencl_device_count, int opencl_platform, - const std::string& host, const std::string& port, const std::string& user, const std::string& password, - StratumType* handler) + +void start_mining(int api_port, const std::string& host, const std::string& port, + const std::string& user, const std::string& password, + ZcashStratumClient* handler, const std::vector &i_solvers) { std::shared_ptr io_service(new boost::asio::io_service); @@ -197,9 +188,9 @@ void start_mining(int api_port, int cpu_threads, int cuda_device_count, int open api = nullptr; } } - - MinerType miner(cpu_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - StratumType sc{ + + ZcashMiner miner(i_solvers); + ZcashStratumClient sc{ io_service, &miner, host, port, user, password, 0, 0 }; @@ -445,6 +436,7 @@ int main(int argc, char* argv[]) try { + _MinerFactory = new MinerFactory(use_avx == 1, use_old_cuda == 0, use_old_xmp == 0); if (!benchmark) { if (user.length() == 0) @@ -457,97 +449,14 @@ int main(int argc, char* argv[]) std::string host = delim != std::string::npos ? location.substr(0, delim) : location; std::string port = delim != std::string::npos ? location.substr(delim + 1) : "2142"; - if (use_old_xmp) { - if (use_avx) - { - if (use_old_cuda) - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigAVXC75_XMP); - } - else - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigAVXC80_XMP); - } - } - else - { - if (use_old_cuda) - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigSSE2C75_XMP); - } - else - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigSSE2C80_XMP); - } - } - } - else { // sarmy - if (use_avx) - { - if (use_old_cuda) - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigAVXC75_SA); - } - else - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigAVXC80_SA); - } - } - else - { - if (use_old_cuda) - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigSSE2C75_SA); - } - else - { - start_mining(api_port, num_threads, cuda_device_count, opencl_device_count, opencl_platform, - host, port, user, password, scSigSSE2C80_SA); - } - } - } + start_mining(api_port, host, port, user, password, + scSig, + _MinerFactory->GenerateSolvers(num_threads, cuda_device_count, cuda_enabled, cuda_blocks, + cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads)); } else { - if (use_old_xmp) { - if (use_avx) - { - if (use_old_cuda) - ZMinerAVXCUDA75_XMP_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - else - ZMinerAVXCUDA80_XMP_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - } - else - { - if (use_old_cuda) - ZMinerSSE2CUDA75_XMP_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - else - ZMinerSSE2CUDA80_XMP_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - } - } - else { // sarmy - if (use_avx) - { - if (use_old_cuda) - ZMinerAVXCUDA75_SA_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - else - ZMinerAVXCUDA80_SA_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - } - else - { - if (use_old_cuda) - ZMinerSSE2CUDA75_SA_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - else - ZMinerSSE2CUDA80_SA_doBenchmark(num_hashes, num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads); - } - } + Solvers_doBenchmark(num_hashes, _MinerFactory->GenerateSolvers(num_threads, cuda_device_count, cuda_enabled, cuda_blocks, cuda_tpb, opencl_device_count, opencl_platform, opencl_enabled, opencl_threads)); } } catch (std::runtime_error& er) diff --git a/nheqminer/nheqminer.vcxproj b/nheqminer/nheqminer.vcxproj index a2439178f..07a56f8cc 100644 --- a/nheqminer/nheqminer.vcxproj +++ b/nheqminer/nheqminer.vcxproj @@ -111,6 +111,7 @@ + @@ -127,10 +128,13 @@ + + + @@ -149,6 +153,7 @@ + /bigobj %(AdditionalOptions) @@ -159,6 +164,7 @@ + diff --git a/nheqminer/nheqminer.vcxproj.filters b/nheqminer/nheqminer.vcxproj.filters index d951b0e86..737fb0d7f 100644 --- a/nheqminer/nheqminer.vcxproj.filters +++ b/nheqminer/nheqminer.vcxproj.filters @@ -170,6 +170,18 @@ Header Files\solvers + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -214,5 +226,11 @@ Source Files\stuff + + Source Files + + + Source Files + \ No newline at end of file From 340064b9c69e3c5b0cef38d0a7cd016ad79ac15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 10:52:17 +0100 Subject: [PATCH 05/15] drop OpenCL solvers --- 3rdparty/amd_bins_linux/equiw200k9.bin | Bin 434628 -> 0 bytes 3rdparty/amd_bins_linux/zcash/gpu/blake2bcl.h | 150 - 3rdparty/amd_bins_linux/zcash/gpu/common.h | 156 - 3rdparty/amd_bins_linux/zcash/gpu/equihash.cl | 1038 -- 3rdparty/amd_bins_windows/equiw200k9.bin | Bin 889324 -> 0 bytes .../amd_bins_windows/zcash/gpu/blake2bcl.h | 150 - 3rdparty/amd_bins_windows/zcash/gpu/common.h | 156 - .../amd_bins_windows/zcash/gpu/equihash.cl | 1038 -- .../zcash/gpu/kernel.cl | 555 - .../kernel_R92xx_linux_14.4/equiw200k9.bin | Bin 434628 -> 0 bytes .../kernel_RX4xx_windows_16.7/equiw200k9.bin | Bin 889324 -> 0 bytes 3rdparty/silentarmy/16_kernel.cl | 526 - 3rdparty/silentarmy/19_kernel.cl | 531 - 3rdparty/silentarmy/kernel.cl | 526 - nheqminer/AvailableSolvers.cpp | 2 - nheqminer/AvailableSolvers.h | 1 + nheqminer/nheqminer.sln | 36 - nheqminer/nheqminer.vcxproj | 3 +- nheqminer/nheqminer.vcxproj.filters | 3 - ocl_device_utils/OpenCLDevice.h | 15 - ocl_device_utils/cl_ext.hpp | 12355 ---------------- ocl_device_utils/ocl_device_utils.cpp | 146 - ocl_device_utils/ocl_device_utils.h | 34 - ocl_device_utils/ocl_device_utils.vcxproj | 95 - .../ocl_device_utils.vcxproj.filters | 13 - ocl_device_utils/opencl.cpp | 174 - ocl_device_utils/opencl.h | 131 - ocl_silentarmy/ocl_silentarmy.cpp | 536 - ocl_silentarmy/ocl_silentarmy.hpp | 58 - ocl_silentarmy/ocl_silentarmy.vcxproj | 98 - ocl_silentarmy/ocl_silentarmy.vcxproj.filters | 28 - ocl_silentarmy/param.h | 66 - ocl_silentarmy/sa_blake.cpp | 104 - ocl_silentarmy/sa_blake.h | 11 - ocl_silentarmy/zcash/gpu/input.cl | 704 - ocl_silentarmy/zcash/gpu/kernel.cl | 555 - ocl_xpm/ocl_xmp.cpp | 305 - ocl_xpm/ocl_xmp.hpp | 56 - ocl_xpm/ocl_xpm.vcxproj | 100 - ocl_xpm/ocl_xpm.vcxproj.filters | 26 - ocl_xpm/zcash/gpu/blake2bcl.h | 150 - ocl_xpm/zcash/gpu/common.h | 159 - ocl_xpm/zcash/gpu/equihash.cl | 1038 -- 43 files changed, 2 insertions(+), 21826 deletions(-) delete mode 100644 3rdparty/amd_bins_linux/equiw200k9.bin delete mode 100644 3rdparty/amd_bins_linux/zcash/gpu/blake2bcl.h delete mode 100644 3rdparty/amd_bins_linux/zcash/gpu/common.h delete mode 100644 3rdparty/amd_bins_linux/zcash/gpu/equihash.cl delete mode 100644 3rdparty/amd_bins_windows/equiw200k9.bin delete mode 100644 3rdparty/amd_bins_windows/zcash/gpu/blake2bcl.h delete mode 100644 3rdparty/amd_bins_windows/zcash/gpu/common.h delete mode 100644 3rdparty/amd_bins_windows/zcash/gpu/equihash.cl delete mode 100644 3rdparty/amd_silentarmy_kernels/zcash/gpu/kernel.cl delete mode 100644 3rdparty/kernel_R92xx_linux_14.4/equiw200k9.bin delete mode 100644 3rdparty/kernel_RX4xx_windows_16.7/equiw200k9.bin delete mode 100644 3rdparty/silentarmy/16_kernel.cl delete mode 100644 3rdparty/silentarmy/19_kernel.cl delete mode 100644 3rdparty/silentarmy/kernel.cl delete mode 100644 nheqminer/AvailableSolvers.cpp delete mode 100644 ocl_device_utils/OpenCLDevice.h delete mode 100644 ocl_device_utils/cl_ext.hpp delete mode 100644 ocl_device_utils/ocl_device_utils.cpp delete mode 100644 ocl_device_utils/ocl_device_utils.h delete mode 100644 ocl_device_utils/ocl_device_utils.vcxproj delete mode 100644 ocl_device_utils/ocl_device_utils.vcxproj.filters delete mode 100644 ocl_device_utils/opencl.cpp delete mode 100644 ocl_device_utils/opencl.h delete mode 100644 ocl_silentarmy/ocl_silentarmy.cpp delete mode 100644 ocl_silentarmy/ocl_silentarmy.hpp delete mode 100644 ocl_silentarmy/ocl_silentarmy.vcxproj delete mode 100644 ocl_silentarmy/ocl_silentarmy.vcxproj.filters delete mode 100644 ocl_silentarmy/param.h delete mode 100644 ocl_silentarmy/sa_blake.cpp delete mode 100644 ocl_silentarmy/sa_blake.h delete mode 100644 ocl_silentarmy/zcash/gpu/input.cl delete mode 100644 ocl_silentarmy/zcash/gpu/kernel.cl delete mode 100644 ocl_xpm/ocl_xmp.cpp delete mode 100644 ocl_xpm/ocl_xmp.hpp delete mode 100644 ocl_xpm/ocl_xpm.vcxproj delete mode 100644 ocl_xpm/ocl_xpm.vcxproj.filters delete mode 100644 ocl_xpm/zcash/gpu/blake2bcl.h delete mode 100644 ocl_xpm/zcash/gpu/common.h delete mode 100644 ocl_xpm/zcash/gpu/equihash.cl diff --git a/3rdparty/amd_bins_linux/equiw200k9.bin b/3rdparty/amd_bins_linux/equiw200k9.bin deleted file mode 100644 index 45785dc4e67959ee6b0fff18f899efbacec76036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 434628 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

0J>$zwejKi`{7sc|cQBZqE0UU+>R77|q$DDh%pl zAA1ePY;+C!t*u?Z#&$%1r1~DNvuw^5I~IA-b(WzILcbj`9%B_n_h29UJ;^?HD;Ewr z+y+OC$G5x3*Ws^8c0-;EfA24e!-e(*alYI41&ze_Cr9F2>8`tKT1&3|s?>go&XGOd z&CwE7L06S{Xi5CGes)wfjX6e3cBt_%5_^4g4Ps}<*c-fW^xZ0_ah|;;TkcrQvwz4k z^vlSZzW-MY&ITu(Nfzb8S$~($y1u^ur}hC}a%c;24LQjh=k(jW@BfX*_nyIj6^``V zJNZlaj4RYHB>(i66nw?`9}M2Z=k7?XQ_wtcOZ@G0t``p9WzY2r;k)d$h5>8z`2BR( zITkv@I@MzTI^PvU-C8f)*Z0#~`2BRQyNj}w)+V(Wm(Q(}u=llp#5O`7dgNTLr;oBV zjzxZdlV#|Kv;C^MM`;L%%k4PyPf>f~i` z@xVcIONFg->>%u8XW5{bvq8haSvfeXNI1J?<-$RSb2eyLX=c!{a{QIXoY~%UaSVNu zbFLvLdE=ZmKWGZ%u`hwg!4u2zH$g|)yziF*PCf*E(hFab4?&;W5WXbe!gX{#_?UbP z*U|ON#~7;yO~UoCr-sMDlW{$K&z;BN<0s&+PRH)!JcDe1xUUyhzY}#)oe+=D8?UMp z;^zhakGiN%h@ThvKkA}7A%0%s|F{R;3*xTgE$%`0g1D=Ai+j+$Anslz9`~SoVcf;@ zU_a-9QHOIpf(QER;Id#JJ7w^@*Y$wm&j!4vS1ek+{(LDik$S@ZJ%pt?* zK7r{n%%uR+Wfy7GRDU zMr{bpal>2>FvksZokw6!80JQRIbj&JH83X)^I?EFX&ALXFsBUjQGhvR7}*3crwwy6 zz??RW>;#xIhPf4B&KO3v1I$^&d>mlT8b8rIuB_R{SC!}SHF75cvV z5ZF6yuM>0ZJm>m?A+Wn0m`CT4>kAyS!!TT5z_Oi&;rar{>@*D57Z9`CFkD~YnB9iq z`T}D17>4T$9J9wTTwg%UUc+#Gfn)X>hU*K6*=HE8FL2C0!*G28G5o$dkNm#6WB7e_ zp5HF5Zl7f93y68An%`H?Uthp|>?}K2TAKU5x_IaN1JD*B|L)I=2HH2{cwM#~aK(l% z4%(}j?>qHOx@MlpCfzz?2)N+%T1fsSGfchN(16jbUm6OpRe`3^T?s zV*<<=!;CRZonh(%Or2rs3{!8I`T$dJn0muB8m2M8G#aMSFwKT(4lvDzX*SGs!%Pn_ z(+xA-FtZFZE5OV$%q+u1hKT}9WSGb>X~U!gOxiGM!?YTvHNdnQrqwWQhG`2hZH8$x z%re6)3oy$Jv&=9n46`D@tT4<9!>lyS$^f&{Fe?qS#xQFF%o@Y2G0Zx{tP3#f471KK z9fs)$Fdc^JFw7>yYzi=&4715FTMe@{z-%?lR>O1}rZd2F8m7}QI}EcU!0a&04#Vs; z%+3I_(=a;?v)eGc1I%v2>^96E!|Vw#dknM3FnbNNH^A&Q%wEInGt9mKv(GU5471-b z`vc5=!|XTA0mB>!Fb52Cz%U05b1=XhG|WN695T$I0CUJNhYZtYn63cRWtc9*95&41 z0CU(dhYfSYFh>H+5yKoY%u&M}4KPOybJQ@$409~N95c)@!yGrv@c?t&FvksZ!Z0TS z%n8GsFw9BAoD4804Rg{krwnr{z??G7DZ`vL%;^Ag+AyaLbH*@d0?Zl1oH5KI*AN|-c-XAThj_)h%j}}$O_s;(4Z=pZ>m7?ZTMK$;hJT~{zCoMJ|?34b< z?N`6wfINWQ*AFR57h$}i2xB`%7^^G7Slz$@MR|Ls!|{ruA{#d?xHp9fM1AItD?KZOQ53!I);p>&Z|cW<_V;ux+bTi z6goZwgRoz>78+R6yLkCfwq)UC0t#-=DYuHDp>jORAAMAcI{ch!`wxACeG zn7c~Geq(IWP~<)sTdA7L@xZ2Rqhm21Sj;kv$7no|b63Tw;>nfC*p_5bE}YGya6GrV z3gdy8JK>T3K)#1_FS7Am37-3Ue?TG5$r(8x0M4B=*IfzDLj8H1;eA`=jJm}c)_+z) z7su0Yhn!7li7=Kd9-5s8jBD!}#J0qo4J9uahZ;VW5E>5j#CYdOm>W<}11PXcGv z7!RyTIFl^Og@XoG}U4w0Bd;cogJ{U6` zF=wf;m<%c6{Lt7*c*hgVCdF+xX)@Yw6xwb~(sq(Xxp2_oZ8vH1(##}`hw|7TzQghF zLVR-_rJhsZ+xJU)TULOxus!oQ!*>N}@6;{M>Sjl|IqPu0WNj2x%;7xQ>}=Y3z&x3* z5pXt!ykH!4*c`6sn4N8PEY@?>u?%CawD)10C#wZ#bqQyZMY(V`o~-p8IqiMe1CW1UDgJ6R;XBTx%l5l-u2%j7ebNg*(z6Qs)Q0dQ z`4z6C>%qU|SGbO@Xa2?U?_m>hJ&dvQSTU&%fAu<6RbjpfzQ*IEDX;_hAdjqv-cbVk z_BdCLI2Za|Xa|L29_>Iek86q$^V}B7VFTe@?Va`^rlP3b-*r=~cikj&wd2N_-`cxw zei`q%X*0X(?L9a3v@?wDk6W0A4Q8^-99xHXJF%=Tw!u2S=Vk(Ius*Rt$)a31=y1QS zo0`tl;XOAzvc1UjShSb(TMK^sYOg}?tmb=e{GHYQo*UO)i}&1w`a{1R-{YOtnJD>& zZzhTDvs`d)cyju(W z^VlDM3ArldFXW&8l7g=||K;F4j8o&so4sdR6{jYkUp4{#vWbu#57_~&t?d)hUzv!0 z8TE~aT})WAIHzv{^o8}AI3a%KjvsH&+}6d>1jtQbdn{g@v|Xkxny`fX&KGCbSbI#w zdURcb*tQrui@agYgk9&@ad@v2%f`j_K5iP?t_f||oV1-}Q7#;Gc-xJeHZL=7 zS_}T>^^5QRKA*^$o=@Q0IrC>*#uTmdUSh9bM1-i*c%K4z7pyNby)c7uUmk)OZ{@wFQ4o zI*wZaJAe=JsCwACK%b{AGOko7#Li;lRdqt_9LoPu7u5-|vz-5r=cNv7ENf3Dkn2XY{()pR6n>1Ibtr~X^gRLY#+4C@X5@L z8nT^^MQ*f=WoT3SmEMaw1Aa9t@hi!qTsZ4bvHy3sIZF5}D%59Ye(QZ^=PcJ}24~)W z%z^Sa>(OU!NczknXSIzH`kUfmhw~8jnT@j*-I(%05-?94_t4&}s?6SPT;vx!CKBiDyRAJ&AZPDBCbEX@gXdP&)WvAKrtBWaPQ-hi zST-?kyNO&QH4klIVoyzM4VT%4JR{DDV3bIH>ukQ*?+_1Nn4hKZSp|J+ zL->*W3fIx~;9v49Tu0Y4|5EH7hwEXzd>M}A;}Lt2-|{%T3S%?K5qX?A33dP<FLU`0^31;Soqx?Y zdiI-L^|t?QEA0&Z4}bsf0mmXY>SP)EAbjT5PKMtuh7GnQHYiz?3uogDj8nCfk)vR2 zhex)Tk6Agt9IpzWlVN*t%u0O<8w=yOzK@6TJ+3|;<~h0R=KFs`{h{Cb`+t-1us+`Z z+myWj_n`BDJVV!D|JvUFyMw%-?>1sS*Few99&#+!K<{K3`eo#71oMog;A~mKnPgEe zob`Fh*@$Ua1C4$zkK)YU|0|Axmz;AAImsL6^xF}0A&-75k0U3e-wOVD?2o^MTov*c z@=t$B!B?FB(qE}D5st@avR&35<1rrJ{oTL2**@q$`@4S+I~Mu<9+sgG&bHHcw3nmp zRwQjFS(FP09UiB;e@FXH{qWG<3-QhTR?jE!?K!#YE=4XK_VdFw9FOlMGDoCt<%l(z zNc*#B!{NJst6L*~pYIXp0eh!(4PtFfWG{Ka+R>7Q+@q4o9(64CsO)1I)}xWLl990Y zc5t>b;Y_k97Y;g{vyze6yMcWiJjzBbuM@|>OU}85oaBvj+Iz_y$RlUt5${dFU!#uF zHPyyNfs_A0pY+0y^sItDwITdSeueAkdhjp#6|SS}nSU`(l}yF;kPGryIt|x@uku(u z8S^&qH6FW<^OTIXaURIG8BeMY;-=yy>Y@4|ZmuxfQ+*IOSMq<P@|ulqo}?O-|Tulqo}-NgSV)05jAuD-2U^n3Vyh+%PK*Q)!qr z0jAP0YYbCkm~{cB#xUy)GsZ9-0cMP0It){1m`wqu&M>zt$FvW{JohHUzA>ify32aX zfuDnwm3iwfwVodRSD#BBg1O|r;$Xk#mHA$$Zu81veqB;xIfKnB_n1@uJim|UGs9dp z$nTHYbFR1ien0&Se&zZ7amOORKfp5hAfJiK?^ofOxF&ffN*3k9Szq|GlHZ?j9(u{| z50V!=t31Cy=~(3VhggQ^8adOP*jjM5F5yhFC>IVoJdX60--~15CFfj2PV&Y%;|TNm z&-42@zdvQ|(OZ7s#r8oQs+!uST=leL>+xPEmet2?SI_)@J=(4#X**#v$FZmU&qwAS}^*6t-p9DKVe$S)&Z|wIL7{~5!|Cx61|A+kkoY_@x z`Ta548Tx^q-=B9Z^84c~L!Xg0sQi92Y;bF0gOWwLaMl<8tmO9>oQGcW`xE2^eQVF} zFFF?a{YjRgA5PAc-){qFoe5`>MY(X$;eOj!elL!Jmz;AAImsL6^xMz#`_`xq>lnJ{ z^QYJzm=_zjkaND7>?Lcf@tE^H%`(inv8~1}KwR36w%U=jm1I#a9CXyBGFi6QI2`Lz z^Rl1hvxxKBp36_b9Qg#yk>_&xMXi12@)LUG^2phti|=2#-P)SWOI0t9N*C3nbGiHC zxaFQqsy;W=XUSew(W zfQ)!V4lP;d6S=E&j7Qtd!Q3fwbsoo0$>6V1N9q}8xq2P+$QK|leeelAcOb9!fltUs z{5tRz`G{W!z5;*EjKI7xk0Tdi3~XUW$EqnlPXraCo=K#vV1%U{;$Ef2!AhKu8G7kGY`EgF@+%5yy1$%}HYSHR1@d|reHMp(+FHfPIISnH2C zSdQ~Do`aW}K^zp9Gx1IZ>PHL^r-&ue!8o`Dad69K{2>lbMI6L2uqMy!65Lcnh)PV9OSWjA;zZ>2YDPiwGw|#I*#0e_=vjj$m`!J z=7jBADCX3oeHC*!r;3CQe!Uo9Kquo+V zm$o-RwgIw}9$c2^a}5n9yKK2+Cqs5JWE&yd0NDY{m$x@Uwh^+_*MMAd^1~}~`X)nP zXj_ewll%fYYhqWh!`a-IG?Y%C!;ohrCRk6!Svennzl?Dw+gclX&l|RwcZ&t%)YB zUYeFpmaU1)ZjcMCb*o?9mj00E=r7Ud>K_0v10OD)T%6B~@W2R5xzw8Mq*SYTnS}Ft zo`aX>N0K-pE}QZ02kM_^4J>uwP%_Zt;Aoej{ULukc&b#e-AjJ z&8J}R_kiDfXz!1&&Ff>`bC0#p+I6y7woeP}wgq-O4f6M}eb%jOp9cA9kf+Xj(Dp4G z*5`D#KxbH|X)SU4P`BD=-TJ5naxH9w_3M-NS=$k{Y*?3;PL_4VWgn5Vmg0f;Y*?GV z$@6>S_POT?w9jC)&(Qq#5gr&}DVJKGZAo>geOhpS56?frXUVj3b2FL=2Zy!dl! z$Wt40d-6Ds67q8IkeC;?nRuz#80md|y!VY86JE+UMMIvdNJ}TnHpOMP$OYcDGx(|U z^v68MUPjvO;Njq<6ugw@^CCPj!cs1^Dmx^#SiB6u`Cy)dm#G^PyA_vH@!lQkpJtq5 z-cLHF7Z04adVOZv>Q(q#pP9a-1AmKkq@HPJ|BMx~f5=Op+dt&hMzDYRgbRfR!0+dH1nz+0&ja{hrpaN%try{lwo8Oz??SB%>Z-SFtT%C&KTxafH`BB zTRZ}D)-WFjn6rlY*f4HOw5y^3S7mz(^S^)85YLl0G)4O{=Q{%S?epY3-;X)s5wJVX zlk<2Wz;K?Nm;;94JUKB30}SWMi8*K(&XW^!D8O)@oR~v~;XFApT>*yk4uY#2gJUoF^ydc0-Hi$&VWLotEC`$ti!Zp&@Uc zocp&^h<(0qdl2?*hy9-LSzl-mH^&XMhr1-+!|h`SgS56b8GGp0p5rp;2=*Owzj0WP zeyv;MI1JVb`r0Y3SquBs$+y!pxjw>p^by9RkHEZ%-!Rwy>rAHIbEomhnZkNZz@8e~ z;O*AMIUN(BVc#Z+t)-*tCy#xlV#SAEGmKj zPDZR+-JUMyIpPiD@sx)Uk1G(5EA!*A@W2R5ImF<}=sz-dn~d`*Jcoa4uMz6*Tuua+ zp`C?oQ;1jg-^l9#@ap|H*F6#aw@`n`%e09xFVrnw7O#)EFK8m~J?y`=c0?05EKW-& z%dG!4lw2SdPT0_zF6TMoDtVc(1iVy(mzsQDga<}g%AvnD(Z*pW;(UUQ!%SbD^i#wo z;<02Ahs7!4wsat_PknM#W-9s&JT_OMpMW*HJd$6H)q`KR_wlgzkl&DtLblI-AZwVzmKJemgHvZXd zx#twyE#&1s?APP^Lh2STnQc*SFW$Co2`}?Hqw&vXk~y2sxNHo$;CRTh^U`%ZN57AD zJ8mI(sRb`}`Md}ZjIfkTy_y}5e1rZx9_QnD4qooxlGv@dydV3fs2}}Caf*Jjbj&Iq zIPXd3~)nhHd(o?!R`u^c=LW)=P8j9&u+5 z+ISAyc;xfj^V)OH9P^#+J954g!FM9~&Rpo2L*Lu6qkS&q=R!XEwHNbzZ|+=^e{p9{ zejeoKL4H2u=hF9f?rfhA`T3Bi&bhe1c`xnC>6{0hp^eR-7uy(h%f@!@isnIX9{p?A zuEfS(+#St(X;WG{S++Yat7p5}WXr5DqUJf9oe*xaXKV-sLw_4zg?JTSsiF10H= zBeh#LHUsB#d5*Rrr*lwu=Q0A9;WI7ty+XV$pdRu9UKfCu1>nVXM_+t7*H+XY^0FX` zd7*Ccvg73_g06`7{_@KSFWdJ-(HD25rITfQ;<9FP5fu-d^TqAy={%nk^D^fJ@X`QY z8uNJ(9vERMm)et!QrpB!g!4H(2QQhI65kV-8SHhW{`tn~eWoK_JaGPR?8?mljXn6= zl}SIl8-Lq$?2qk-TomeaEd(dDeeTUz2!0pR?*F?l<=O4Rg=V*3+MBc6R@iMT>~<04 z7qWf!?rmQL`9+YY&V^|E)-S)3)7c80VVxGW#_dDhYM;HYM6Hl(WgEQmO42@G+84Ec zd1qQWS+*}On?=s%6%Sna99JxPZhSp%TfS2j{ya*4Bu#`)^oE@3!6fYxjK7!}qWxNmfs4NQN@md)U&h}nnZ?iT!(XS4)U(L!pD{!B4|(Zx`-i;R z2=*_(@aw=&91>wr-1NL2efPBkXT&?u=$V zyEQGHEVKSr8{3k7o@Y0wm+>6!N#B|I44x@7;5)POeMfj;gryvw@w3c#X5oCM`3^aq zhPr#sGaX!p?Hlq^h*$Oz$m;;`>U{*)Jso|7P=CnF{OK_-)Gb~*c16>nYdY^e>?5q- z9Zi3!BQ2dQvp&KKask_)_R{+FN}j`R$;-4S!OLv$66NzEJTSsi4t;{@mOo9$`83O) z($6N(6mbc^lPvs8oWj4P1O9T~7vR%h*p0t!nb}pH_^Z^B{zJQ;3Vz+*F$SB*Z^%U< z+h<>cwx5FCdtaj&eT;A(d%*&mQ+s)j>^1|N%~%{0&Aj(84zAiCHGgGIS~^)~aj=72;Q2lEE349*c#dZ~d71hcc*%g5)_h)s z2S!-RrQXgqqd&{ssTt=}c@A4!9mGL#xf*+ls2_1moFbM;2jk#7h=cFEjX%V}mkC>E zKL~m1d;q?;>}#*(bS{I=(8eBI7TXwg%f=4A7A=F^GTPB=uO)r0uO5n)eQj@AI$3ro zF5Aj>Z!I49z}LQ-?&SFcv5h_O-^0ch!^Yb3ZA^Gzgr!{SwQOtZkZi0K=MV54wn0ws zN8O#vrQou!cu|Pghp30VfY*n>%R}JBbuWG6^;}y~f5^*2OJiQBTf7{2Jz5G~OL_0F zzn<{&YFD)MjRR@vWLZ~Swu4+OEgpFP8?UB!@*Mph`riHj19({qUY6zaB0Mm{QZCh% zU7E^@m!&wrpXcCZ#n+N}Aud;7Un2ECXq+xF9m|UcKKQ$@Wgh(9F8sZgS^kwn_{-|p zAKMSPC}jH&gA>|*3U>c6_#mxzwB4WvL@-pJh0InCEDpJN0Ax z`%HP%c;)*`9|bRuf*03a{f)PB@2lzl{?bQ#yub9V59lWf}=S6s6gr!{S^=x%&zj&#}c@@vW%R^sJ>{eVp zg#D+~{|NS_^4MlNRu&I@2{H-JS+pi<_JYx3Gm?8Uzy!5&KLtgq| z|MCmJ4*W#E<=26qJot6^$JgJ)AN=F@;UB+$M8_q+mCY={HF;d|Mi>5G*OAwM&|((n zv)fp2Tvzq*n1$==+2%3J{nKNX`zKyOx{nCkUsu88^+mCU+U zglo6)h--2_XSUTbfBvyD+opZGyR=VtKI-H1k38o--TBbN`N#Rt!+pAr;rt`dxlfm6 zoPXqz`*a<{`A42}pDxQd|Hvcv={knoI@6>DaY9ry~s=ct~n2Yd&?bFSC1ht{2s%>x_T~D!i_y;w>#$^r$!GWH&xu7=g^X`Wzz?E4qs)= zUh-Rb_N~IRZ%zKQPk3O2gvJ%x>R2lC#^D zu-lceTgL21*gi*&HV9+(n@6LS z-#DC>PL^5B?qZv?BW`}<&GccOBc`x@9{KlZpY>>;j{No!9vERMmwGGPo;s?S-H!7| zc-{|QLtYB;y4rXh0A5$4FS8nb8E-S>W4Y%P+b!f}bvovSy2Z=xx1%(4rFrjfzn%1D zb{&h5)1{@8Wyj*OBjf_l_xbPaN+0DpVkUW+{{`@}5xi{5=S6s6gr!{SgKQdo80Noe zoX_Vuc-iueq%R{bw_u$M^*?HyB4$g+s^Wo7ke{W@0y>S$Ouj@!Xj|P1i z*+1l^&+Q-bY9rXc{KBsTKapSfb>Jrtegl1(Z@h&+^kx14{_zJ#bsYKz@?Tt&#}(g4 zUj}vIk=JL;xevDKv1T@6P3Sja`xc5jk5LbJSIj`%c?@m*7}|LDfB2)k_I&Iy^PN9B zp7Wix@SU~royVc$G3ZDgKi>X0L{5Gkd5*Rr zr;nlT&gEKg*;m^X;&lV{kQeZ}0laJgFRpv-x8KXP74?U_Y*-ufLfzu!_=vvEr zfA777mp?ict^M}#v~;rUR9tp~T&yh~_}I7qD1DOWkHx$^_CJG{ZQ!LdpBLeQ5teeP zQ`xl`bE5C9#rb1A2QMApN_>pqMs}s>x&0I@u%-*p7_&K_U zr`w-`{8Nyp&L`3K8^8OVoX(BV8P@5kjdA->x7z3QccP7u+sHQf&Ucdb`Li?8#_yg; zODD_D#AT<**}CF^Pk#5$(x-X;WZXVa{x4{s?P#AJ`RyY-Fv3zU^_}dx)ETwUI-Ebr z^H1=Z^0e_f0K7g8UY-Uo_whIIGW&b)=laKdW`(>wJv-)wZ6;ni-;ZWPZZ_}z{r3}I zww;Y;f3Gtwoh&;Wmz^OO$N}#A-nR5vo}UqlS zpZTxsAM(=Y_78cr5$s=n;n#tm$S?dl@RKLL3;+1;ckl=Q_;dKjpP$ij^&h^SS&eJ* z*zxUC_ftd9*VVJlW0w1;$1L|x#H=p6f7Rb(r`I2`PchZ& zkJzV}>h(wLV}0(Fe}%SDDF0&4q5O;QIYR#BW2l3WZ-jFn4?bvfAFmyfFE585FNYtq zZ~h?cNZ)%ubST$9Uygox_@1SQ9y0mYyClB?@+%g6t~DvVZj`uYL4ru75>+kHS}0p?~G$N2{POt)f4K z{j0Z*MXTO9nwCzMS^w%B+mC&mciu{$=Q-MtzVhfFz*ly`S9a(7itxY)OF2B#SDCM@ z!ug}-E9CMa)ZKF&jKB05`yP78o~_0w_sTe@>=TgF0pQg81g?7p`UIi=ke4S`#Jo_q zo*`ZDMk}Ce1@ArV6TE&hTJf!}v~;q}`UDrq1?>HyZ@r$r$aB~#d3oq}!OP3wWlugY z!UH2L<iF)d zv~;q};@%~;2cAhAzWZMKGSBgRVcTr@Q?$*O&^CMX+eUa`gryu}U5CZJ4xDeWxOXQ` z!@hJOP8s*~908{u_gwdK#J#Z1!ghLkdCUuS%VrO~A1#Nj<-GSW?!9(4TK>I5Y3XE{ z#l0)!f_e7$UQ1u)IiBa_<-y+pFRy@?efhiy4~(#sOI^(_NB@=mwdFW}kms#3|y3bTIDy1LEF4T*V*a-nS6~luP|6yEXN`c-e~c zEj$M=&;O?+PKf*GvA2)fn3q%;cqs)h<@vk_4~(#sOI^$kN}UxigK(bWIe6Lr zlf-7l<#z0MrT!O<)6J&i*NO+e_`}PY7k_vWf0r}A_7^|J-&q~0=S8!9#tGRzEU-@<5Bb`5iZ~Wvk{@@#b3*Y$LpX&JZU%a1r8rS6U`5*oWe;0M+ z^*b$2X}>G$kL#))9;a|!`Jl%s_f3ye?wg2Hm+byke~*`5f5bb*QLjJZo#Lq1AMuX$ z+0S`FT>Bi4xF+ZP)>s|2-<8+E@8@^~?ttOX2lxYqId7PQhPe=64jSfyVGbGQVt_eh zn2Uz#GR&m_(`6XlJL+@TFqZ?&VZ&TDJx2_4CBPgpj5vaxqlUQ}V2&C_ya98}FxLXi zF~fKp9yiSO0CU_hYFFqvVVD~M=7eEnbHJQ5%!dKyq+w)-z??G7M*-%PVPq4)oHoqO z0CUoNwki_q(!; z^UXYRzpG<7-^}ydZ=ckBGxxg^^UlfM=bKq}@a?zr_Pc7IG1@ES-~BnCe}6CcyHU}| zqz*+^hoX_VHuO0E#R10oFD3?caQ=q|80UYeVVwW+0OS0Z8^-ys3^2}rrD2@^ngHYc z*BHk69}{4l|1pMf{_6rvj{nM&+HYKE*zfnnKltfB-(Q4SS?IgdVf-#CvOZ@o-<{@| zO%dYifFZ~O@ZD*j7aNH2nsB^m^=j)Ey?spmqBZCjtwFztV;id}Ujq4K$8zHvYcQ@6 z=HE{|Ve;>ul>Bqx{CCbseiP(3L7sW)QA?(3RJxy!g}T`JenKEuAd0K4noUp0$Yg z+kbK~UCeXDZua-L{|)<;`1W%}e&0!WV1%U{`jO9DpYnN}Z?`@rx$H#Uox|tAVPAPr zXQ$bu@yR^MIc1-coDKk|-lufk&!JBl>d)&_J{R*s-Re{R;7arybUnv=5BroC{w{j% zXFo_wC(Eo)Ih0(WU)1@t3+Zy6qt8TMI{#1bQi(ogbv`e`10yWuQh%3y&c@50!+EET zm;HLsrxcgJj%OM5qfaPK(Z`Yw_9_1!eagT8JN%(fS%p3&#>;qQtfQ?z4Ssz*W;1L& z8Fifvv>0AHouE{aNjA|`!3k~F53G)T+OrDUAxR?ul}QK_9fWtOR(A9kln?$ z`Nw~3-woN_kfpv|sMkwBzn0VY67+@j+5J-7HoJCN+x+9T=q1R#MEzMgw7vCTqWUfvw@Lfx|2v)7}|(6yQO ze*JpF%lrQ&+WgOF)6&VZ{}PvtAs6UtKmE_|r|Wo*emi-2`Y*uC81Pb?&x`QD2urzC z@mDsdu85b-IDeYw;N{hyCwY*#d=>o->fddg?lc`=K!0k`&ojFR4O+6n_`9Mb z_3Sp=XC5TmhrIN;?L%H|1lyNS_;uhT@(I5VeB{NS!#93@4S(>B{|w*w&;O+3(4S$v z4AA3MP@*C>-4fxJ)z<0g`9ebc7^)LVO|IzlvaaERQ|L1T{8(X%p zoI5RBRIITLi;B}YLPZp^7s8-&vl=3;}r5!?;q#$y?dVTb=~*%y{`MY?}z7k^4fb~ ze-G@Z{p~R3UHJd&anC(!fB2J-{k^ci7xsCuzlUS^1?q1eWPfxhU4u6(#@27uB6rViznR70hd7tc!xaZTui7{;7 z?IJR>gU2^{lU814O`TcbfJ~+aqo#*pe(>&dx%QUoe*@iANJ`K-3 z(Q*d9zoh>>)%0%lF&*zN|98)*y#M|jzn)Rk-~SB1Zo#io`?eMX)qXxSVeNZR_xaE_ zpLPHLj`UkE^7D1QIPyPIw=+?*Gf}g%V4Kg}{LlYfI}5h6U`v1b$otGM`a=F@!k;~! zSu>s7X8p5o)U1E@;@3AS_~DoMeIQ6bv$XcPUP$f3Ui_KbhrQ$owJ&qR^n*Df^UCyt zIgPE~J^W1nG?yKx; zq+J^~-l%Jb-eYm?G51-#*O2=x-Y4Nc%lr*{9RGHGLHOT(yyFg?#~piR9^Z+1d?)5H z_vCk=j^sXR@7~b9{7&r0?fbOsY_;!vOYHB0{avuP|IwL-Q3&U1r6<-+WUd*Y|W|a$($NZxgVgWZfI)u1IG7V*bmtLZCa&)0@ zxrV&elW-S&-No4L{Xpku33q+^R-*XiIo%JWQ47?2_NSeRquEBSQkU%g&?O$aT-sk3 z;e#Vw+F|{_OYf8JLOWaUlcv8PzJ`dFm}_E-IVGB6PKgi9k-PtaIsA{$@arBmb?689 zMG11wu-5N@zNW_SM2*|}+FIOkhw7{KPJK%l_n_X*zT!^oC+wQN?>?>B-p{3G zXP{>b`?!&ldVBItRaP8?=v$JM6xw-E?&CTb12{T|fgZkU+UhkI) zGrssdQGD{8u6r5G2d+u?ebJjZmTg>Ln4A0l8@Wk9ZZ7Yi8{vZ^T-sr+o1yF847Bgl zb#E|D?V24(Q?7e*9f781-7~)L#JXqa%+6E6osKT_Ej7E><-ZfY?quxty4Mlmztg=h zQGD{8u6q-x1@EujdlDzIjq5pexnm!6NrWz=`s*TmaD+=cPjv83>|Oa@!JTN|!8U5G z#9H@6%MyI+L;qN}L{qFE;)Cnnd0&j0b>4YN#Nek`_de|rq@P(@`&{>=_F*snOzp#7 z{Gs+`PMCf$M`TWzelSPw{sMCY>mG6HQOpgjd&J03ai4@fiPO*f2Y%-z5x>ehW9N6E zb!HB7BI^wQo`!X14)!*4u(ug^$|>pgIx%OC&KvKye{uAv%QYACW-jJUA?)WMZ=P>` zJG~ILg|MCbo$sXEbFQ#ZZ6i+=+xuaAKWyj0wh*@N@1B}I54Q7QOMiu!bN8QiTFBr1 z@MqW7y!)NnDlF96`tE7|`(bxK>u1Pm;XPI4>Hhmq``<+I$#dUx&Sf&+Gx40@wC@Ba zv0doYR^k7mwvtg>SN5+h;e#Vw+IfZqXL`ODWNpnvyO3?v1ht%lu^SENLPPsHX6Izi z9KDXIp1h73O^fJtJa>k3E{j^s^+wDYdP*RhZR~M4=jMDH{}x3Gbopg}U4##gaB1f`BRJRN z5?$t^J%?@Rvf#A2Gh^=faz6jf1<`T=o^#XxJk_*7ea!bp%scb6qc;Kw>2Xfhdz{$@8ry@V8$j@*3=O;%w!lj+Z7rfu|L&?wmXg|O< z@-x_;)z)PoT^FmaZs@ugx-5n+#`m~$&PliT#I`Pr$2q#tx9Czc!aoka#xeF0=Y(~6 z@<;x0=d4c@pFH;?=Ug7+#PhKmw#XB*G3S+_T?$9ztMF4y+gMfl(dmv)}0;5bi& z=rRuN8`*{~MQ4TURfO`oTPrxn=snJehYE=EqrQ;fMKgHs;6KXA2g1+(`xKlel2$ znfMJAWdHMYtup`LrWB4Heal$PdWF8_`exQEGe^yOW#%Z>D_Q4E3})RlF<{-3_0+_G zbx+n)69exHF(%h{T z&RC1X=aJ-$RSus=k~6{L@OdOT6O_Z}k>pIYID8&S&e5pPt}W8 zNAfx17+kN+^TP~0KRnS|HD-)n3-wtduZ8A$BJcI&c_P0*#`8q;xAY9$=h<`o?z`1T z_Xo1?rjMz(o=(N}l=nq`o0YL2*O7YKDgJN1s|R-zYOhlgV^KRV<;$4dzUA)F3g7g zY}j)@Q@}AqctZOb`YeFXv$3Bs`{&v4X^&~%Z0Gt%-*WwnIL$vBcC+ED-+sn*x_|a* zo`Cq|Io;0`=(VWeGN4vn)`bk{^1J@J2p=5b(hhr=px*Ze(VnIE zz4m@aw8XViY;jE$O>vDBAII)zhJG(;KJI(x19=T(-RD7H^S6NMsCQdmTZ@5epZgKk zz6W)0_9N4=53%>)#l^Y@_nj?uy9hPA2sO(!yO_E8;o0eC&8EL%jB63rY~ybc{MqAK zyvWH-ak1v+hv)bg!EO=tx7Tdnx&B4x{2(Acc}~~t66RwebUNp(Kq=c;PnetHAE0K( zA~)mu=SKM82$y!A5y6F?AIX}%5ba{Nzk;UrTpmc%64lfVO-rzsDZyUG2}U+ zT}q}qy3n`O>}S#b>F_n3u}7a5-plly@5jAdqWI*w^PO{L)B@M`yz@RyEN2_*C3VUB z2WoZ#bouxGx(FW};nL2N5}b}b4DU^*qn*b#bg4Keyq6IzEAY+{{V!Hcv0jUhCEkd| zSD%x#`0A_iJ11$$&~xz{Do8(zt-XxYKJ3MxseRZ>j!^qDCrm$>BQhsUKbRx)&cR;h zoOAHQUglivWzIcUFmmY7QTQbh7hH|K48}ra|6FhGMs1pPW-8Vhd(PPT9cayYkba=M z{CyN_&V$JDgUIpJAO9G29{&64gAeMwiTR1ln};xO9>TmSh5duD_gwgs^itTC!uFw` z{YY?nH~hTq7f<>y_D-+6*xrRHrd2CDf-pb2Z?4n8%_jUpYIY@Rb|q@I9JY@zH<$k+y&SgXu%*98koT2=K)Ug_68`M* zl&^Gh^T;Ebo67_Km9Se${SyP>+$1FVR|b9_5T86Z$~jj{y&m>PJQDB+>ezn7$;~4_ zM{Xt|H~-Z?H^K);xU};m1|Rl}lH5Fu_9JY6gV&MOs;L{Au7)nFq08Mo23@9JaYed) zow9XVJ=M{L`I4IbAlW|^c2gO9@)coSy07$4z2d_}@yT;nI_Daw1@`=RU-5ooBiq>H zbDg;RL#z{7(B+Q)x(FW};nL0%ADrqrUv!y@_T6klm$E>(W<|>~ya!DG<*MmY^|1=; z#U+8H@=GqkFOanAf+YMd5Tu`St$p6}O6|j5{F&N^z2peBFLT25gE=B|!t{eVvMhkP z5eVRixsimqk(4A@a>02?CFqm5;*!hoyF`%vFVl5OzBlIh(XWidtW)S$u4`tUGIP_c zQ)X^rohs4zW&CEnG~>s5C+nygKh`^0N6q-L-f=vG-EY~oG0^=M?=j?li_Zmdzh(Yz znt}TZd%rhtp3dVTr^`H^k9j;F^O$?_d8i{<_r7;}=7PIdkottjZe{(tEx>r=B>z?Y#bE+(S^R{8gj-+{{r}0z}W5mK-9(l1tZT4h)HX32^TO8<(Gqh_Y%!-q zQ_LyxfjLrgG3M~a7vpzc($b;l;}YqqRRYc~Eeso52%*%i9(l`%J$UKU#S=&uapT7h-X_`|iQU(J@U zaB@>trn$K^;9mi|71ZBe_u`ZMD*~4V#3#?`y4TKp;F?qxxFpcQHm)zsP1$A0O)heC zPygHq9~|M*4r|>CUH4X?U8d{aV4B+d=Ycfkx+m8WXlm9y<9j~VJv(Q1o>tFybfIsl z+3#K9pATR28N0pi4Y|rc|BBNC;*;le-RqzjaXqIl^G=5@dC=v){<;Vs z9O2T=^B=+a*t>GCHXrSIY@^mTSnHl>xdGov(LdHL(G=^4_~5#C3)a0`Zov=h-bk!_ zBS#9-Pr24U*FC9y*o!|?`>+>(sC}6erXS1^nG>cT%#o4+<_6Y1;?krG@JkYm9EtlQ z^hsQP3)Vx7h4@w089ToNtuqzKiL5hxE{Jue0(+YZ>}@ixzPjH!QBk4uCgoQ$Z`NYo zti`-}6!sO!o9CCmN`Dl#kHU8CuYcWd&OQ35+NSnqLIOC(m8$ zoab%CaThAw}GF2?uT>#j?;{oA_yd99-heaoEt z<#qnG@U@n)kG?LfOUfAk+UtH55T87Ey>spmwOEV&({)z|4zrCt4(D9Oub_+Tx>GKQ zxbBo$-pZz!^S^w6|Msx(!4WR)JQ=~Yo@CKwE!q`qLzk*+!s~=+S%q&a>AzAnU9CPI z$6oD*YmzE&xB&9S`1Y4Pe2paya)CE1oVA^_5N@F)~{xtctUIT zcQ;DSK8c!r5;a>5+b5Wtu{Wky!?qf>^!Ehv{^a=a>Bira@Mn*w`bj4@PduTy89Uzp zBWe+%@o{e+X7Cw`0Ec#)fL_0Ns) z!4WR)JmZ3oc_v719z**Hwvn5`_N#Wy4y5UN)zl45*F%@}(8c)9xcTOE`}u>d%lZsQ z7y6c(t@w9;27F~O_J6-Qtjp?&{*0T~CW=p+roX{a34|Yt%=LH==sX_@wGF zWAGcFRCCo$_+2GPKh;|MTqmUVVK4qn?ZaMjgxZ%mVfw)wk$GkM!5pa^kGU~^JbsuP zH(_qvbd%uftFA~|jXsH0V{X82j3E23)OCvYN6j2R`jv5*bqf8;bQ>L6w zi&Lf?(FlIZm2<%2lq*Mc1E)ecT^6T8IVOjd%IUT^mCBL4!cUcQ4q2Qk2 z7N=zCZG%|O0)<@c)i-qrlwAOe3cu3qtqTOL1Rq|Gi_`GPRGpSnQX>emU&cK_w&YM+=S_N!pO3iiBDDyKd7(W8<=_e!g9k7W11dbQdoUnTZyV7~_T+zYRU zz30lSLVMvg*aO>rS5~TRTDsUi4%^3JyAHOM?EBjE^mSN!*J16Yze?;$9v?F%r~8D?%Bp%6Y#Q) zwT1h|%5>~WBJsWIkp640@WBx-?XccHj(sBU(H=*;l5Nx#wOoy{oBPc*(C|e2=+&!r zAFXT=mbfItAlUzC8zXrb6Fm`*dmVA?c&G@SV z;*;leuNFxyu5W)_%gupdY_E56v;Icp<_zR!SpVDz9~|M*4u4B{(vvAQ`y|@y+5QTe+WY8% zG~KA0x}oVt=&}*In0&3e?Y7W$i8-@%*|^Hlg}$X`N8RRM1z)Qe`+wdR)+O7&t@w=>q@N91``kxM?ZaOD znc9cF_(Sc>oG|@hj>w!a{a}u)y9ILte@h`&-HQG4t+xtBj>q3y&?m8GF81*l3z7YE zeOZRuG=H~Uj&;SJGj@KLEz>!pYYgX%S!bT1ALuUY1lE~nkmF~N;z>?>YFhYpeb_r?#GbR%VwCi&9S`1Y4o1qD7-h+DI41G7V-tWD)U(IgbtTlVjbg9`!)NCVab_;Ab zGdFqD)3?BO3vB6cGxFXzV@AkdBmCLp+0y9bX7gsvP2LQDBkUTf|9vyUxw&Vizj4N0 z0rAOm`Odj`>h+vAV)Kl90|{(zc5<`%F68EX06<&1q+Fsw`5Z2$7$ z#R2ija|O=1L~4P1hGoH#fn>IEU(a=7*~QT1Lg*6PUl-wnBV5{f?hY>ZOcGs|qrHr6 z=(1@>xMoGmP54fg{R#q^8?v;&;0s{cO?N=Q<&^4}0-v zY9IEJBh^5-s0l;(XWidtW)S$u4`tUGIP_cQ)X^ror==s5C+nygKh`^0N6q-L z-f=vUx!+fcXu;x2<^$Muot(-QC+P*#@!V1Q3D?}@WFj!HGFs` z+!We3)?mMAk72_Gwf~P>L-w_>uZ2DLR~tBn%v(eIEBf33jcT#KGJDZl__W8gvDTS4 z^eyuy^EQ7i>}okT?ETe$-0rWv?bd+!46r7)M=VvGqJ^d5-l;G#0Tcb#wnP;Q>Nf|Thh}*C*c=0iby}K^L5bG)HnW?3SF;* zu46>k%%6mHUAInk4b^(AQ|mXlT-;Nz);*|mv!|%SULxx!%bJ6(;;sDm%QtO0wSa$v zI(qjssnh3CqtC;ZYu+a2BzIb9&7;3f7}xVy^Nc@Schc?gY^6#Q=+Vou~C%H5H z&%^F{>Ta)jchB@cKVw=zeDa*Gc^S+Du1A|@Obv`>8`qW#k&{i+n3Jle*bAMU2oL9k zLq68G=dr%UA}7zIy@~A;YIy^+{5PjYe;U?e-8$7Gq~*^XEpK$WxYo&a16rE3&g7{I zYn`2|%%6tyv$e|6gL#q~%?SFd;H!!;+iTtRv;9@U8v^2!=X9-`Kn-x6UKbn_n8-G+ z;jz$T-3`>^$)=yhI(i5X=Y&JPXLYa&`_!L7k1Dj+u?;<5!y5N9tx?hNHGKa;zgVM0 zORN>*gKOLxtZ{4B;DKyxW-AX!(RNET8F*(L#@jkF#TXo$Q&^J zU`}kDfw_P+j`;M<+wq$z7&#gDLg^r#dxNw9wxIyB5~X0}I3Zr+JI~Eeody#3#=cJLfW) z??!LLOAF@*Cb9jJH{xfgsh6g+rfQnve&*Da@NiBz^-=NZ8E55ZOZc{C{ zs*mm7h;2(3CT&}~6u*T@+k=bn3kuTD@oW6|(DfE)9k@8GYe|XLSg6M1of^N@<$4)f zu*N;8@0X$L%dGE*9!k%$>|cIa?H_zt_bc(Wub@s}f&EU{zs$UpKAgT2_B&xupD!cl zuPk34^7#sUW?DXXzA{AWl)mNKSGwH)3hZ8?_RE%s^YY*d|0~NE1jHxLmFYQZ*5ZwL zdHF+uT()2KMqGrvyu5&UscnkC$jM8No)ZrFo@K!nPgyV?d1*oWWwuYK=dIB5Hm6Q6 zc_cL7OG-|2=6gubOC3FLce!?{o^I&53wrE=9wt{ySFQ}bZ^(Ua<|W}A?ON*S!CZ+R z=dbiHg|DTI`H_`jJ)&3nm#(}ZAU=7n+&P!WIG5tN%*yiu`D~Zqz5;rbTtGdZZn`wy z(L;DRCmixUi-Su&1;I<9$5OOQ*oGcEmd~Aesn)4zxC7sG(Csb#__mLjqh@y?-U~XqZ@Wby-4TsMI+2;4AJjdsOM1F5- zID8(+HorIJIX(|0@_SRm;qySY`MoL6@p&MT-o)f=9e*K21&?bGn_G<@*yof|QS-KW9Fq}xOHH&5ffCd=|s zU#~v?G$rJt0X`bwgM0CM`Zygva;Aj#;|MSa{iGvuQQKAPZz``0b-;mMyF z+P^ko-)fIx>sGa&H9KVA4Etu-bFZ?MV4u(WuVQ>RVXtEQ&-91uZAX)%2XiHQgCX*3GFRx zLl5p%F4r|cG{m)0Y;g@0Epbg0AII)hh88Dn$35$IApNk;>!GW;e{Vp2yWMv|*U8Ra z+4n5P^~A{O07?E_8P2p59-|PH5#zT$g=Er?o|6_E3{4%Yuiw#ZLsIsypwq; zTM=5DxqsP-v9)1sHa^?nGt=_9tL=MIr}Qm(DO>4pgIyc7x7X%ntNd*%9}b95p3}9t zgt>SH>*UJifl{`yhFp%k?0lGcX=qBk+{ugZa85YndmahC;wcX%A}_C?y_4+|>Ny2^ zPIc-uusT$y_4TJabsExhl%wY~m+Lj=g?d2G*RWT44SN-nE8I_ou1CyQW+0rS*BTr> zm@CmEXN|uBz8VNVlL%AeNyaZeTypFCILoGYUSxQ^GanH(r*8*5`C^r)XgJ)UnG zmFVapJe(5_`JSd=1NJDRphpAR^=w0rgDdCG9Hn(C8Xm-ZCG@*XwZxh%K3?@k?Ap3A zY1h`R_^nKOb;&CHmI%_%F4Q~yaIYfu4tw!u>K*oy8`QhZ1Je)Yh0Fuf59YHWEA}cF3z7ZvZ+{z6i)Jl(8f%H$Jq>xi*U4*AIIkNw zYF#wViM<3U@l3e=+=E@uJ zu^T>KhYwHX>%tXr3!W!dlEt@eL@B4pnI`wrOef&Ffdq3VhBJ+R*cd-~js z_&TbqLq0p;(;m~Fj?-nX(YMrARkgnZb{(vrC#%D?_2>2ej_MTw@yT;F&bbQa9ec9f z)$0P4Z146)j6!YgUcuUGY)T&G)RypYPB`Ryo(#5mYJ$nAtv0lGvyGfk%hxexqv0FS z(Cwa%oXl`?az#aGuD$+xlrz^tdS2=1In(9ZM?cg9dhUZB`=E#M{la$?bq3c9-Y;5XI`muO*HJp`+M}eN43Ph zSA6XCM(o*GowR4;M*OOi_O4lv-x@*s*@zhawbo}s*Pyc|Tou-J<3`mrRO=~Dtp`8r30>c0oj>zTdX{DX=9_B&^s`#0DYb8*PTzw4e%Qasywp9Lz907cVNaiL zBIj?_*N1$*1)rIg&;4&jNuAQSzv+#*5_x&^3Ff7_DdkEhFT%q);gIinF4*B|2&Nz}9caJF_6hZz4L#>N zb$a!qp*r2Tai~+LAw7TT=y|`(^|tEihMsRjkGG+R$<@=FH>cazrp&9uIePnPM-S#o z^q92S|1^9(&6uCx9Mple0xBA@?4{Hu7Mh0FTZi~ZGlF%v3E~_9vg3`9xpci zGR4tDcsM5<@;y%lpY~J)e+fOFMtdXM&|_cy+?l`BIu#A~;k{1!-LG1h`+2c{p)3z-L|AIytA^_UO! z_4r{vY{Golv`O%_wQG`IL!ZRX4IA;>AjtmrU`=BGynij=_|dP7!>mc@SFT}ZO)~S* ztVw1*VofU1_+|WNZ8YP@+9qqJ89&xGSu@S}v9@tMF68uI@1O2Roy~XV?XSXh=5lGB zh3=nHo%^Q+&OL+NKb^K9A{F;f=5L%4xL?S!d~DmMJ|0-4b2qhiJLc|o_~73Jx1omI zr^83_qR?J@JNDR_mX94f)W_nbAs?;q(Fz~j6YhWyPs!5Ip0E{rL3<3lcB%a%t3vj# z!v0m*a}TwPV<=x0+C$OjE?hre#U9H14d_+)w8!+?t3&1bLEkc8%GdZ`h25*16ZRhJ zk+uF;*Q^SNPoC2~R5NqQ{mhz`fflxr&tGD`>{`Y7($bXrOJ}|a59fqKKCa`hVveL@ zzPyU|F1C?ZYPkbrHuo#|8w%FB1<30{=lb#M%Fy*=$Br|c>qkh>-_(kpi=1_zdb**f zS@(_aR;>HB|IA;9Yh_QXqX%;(dX!ZATQR0q#%!kT@ZNYEbT#$89rf*YFM_U1ocZ$Gu&&#- zsji_~PjhO0sk47zt$R@CX8*7q`-ZIF{yCJFef!RI^77P1snbr>XeVsB#_eNHYBz?~ zIPORGVO*V9lm1Jk2kpzXSVsVBhu9OX*pb{X6fd{fpZ| z_V2>}UD&?|`*&dPZrPUp9_-(PJ$=4|x%Tdk9U-6Z!lyl^_uf5I<{EuVZME$1zYDu} zSwGu%g!fM`zU+T@$Fl+P$#bpFxi04YEpNm-J6;NOv;B@Y;#$(rL; za85Ynd$tGP^0Wp=qqg2c`yIBC6KZ)7V>TLgK|{BD1#+^|$;ow9q3h1UgTtKbPDsz| z9X(gMT<_Bl^?;u5Lyz~Nhwp;CndweNVM~TYYqUBi`G!Bk8?eyYSnQ)V=v-{5A{H z&+%)06?9$WtOsMly1HDdYpB*UoLXP&a(xIbSnD3t`G?T;L)Q6gucc>M_8)$z_OHIK zb(&Fo2z7c0_8-CiL*}LZ_4JQm{}Jrz^F!qP(C*#o#^)jU%(Q%dbZD5=DSb;`+IRa8 z!R`>Xe`9wzFR$+LAKJYwAU=7n!#USO&EEA!e7O6yKrh=LdLyn!UOwE$ytFrET<_#X zcsM5<@;z?^-}Q6^Gmw{e(f*L_6Y9AZdOqgV=?zbY>eS`>zEh_mJ%8uu`MAsVSJl%E zJ^u{a{|mTr&M&Uc9#(^I`XH{4gK(U_R{GBlz}~%}H;g zPvQqVcj32Fko~`hHHrPpccC0V`jv5*H3|L7HO#C@WgCrr`zIGDo64PKUK;(WO1sLBQ*z3jdBiKoEqgw9fDJ5sBiNem~DO+x(9W~=fFgM7iu_s4$L;c3*|XJ2PX2nP{ZMK zV7B>PD9`aZFp=Md8V;WWv(4{9d5+J4iTp0qaQGaU?GokiIWRf=F4S=N9GGo>7s_*d z4ou{Cp@zffz-;roP@dy+U?RT@H5@(%X8Y*s_3|8;--VL1riRafJDbMM+AGh2$3b5{ z2j;n=)obLt(6Klsy7PNnRkDW}Nd z6e*`jImOB;wm8MgDOOI2a!M>tiE>JmQ>vU&i&LtcQstB>r_AD%DW^<1<;p3yIOWPI zS5Ad;DlATgaw?QlshmoSQ>mOv^mvp8+aX;V(Sa@s9UyK>r<)1jOWi_@W;4&`(zr_i9I`lvlygWqhm~{K;v81aVdeBFr^n*-D5pm` zy~^peIK9g0Rn8IR9I-e@lygKmeah*xIDN|LQ;thHvM-9nz6g67?lH}NbOP=HXL-Z> zQ5SBF=U_kT8Xn%0xpYtF8t&}H%zo5sam;?ys~oc*jkGvsKN_hVvmYH|am;>nh;qz+ zG|J+b{b-bO%zkv3#WDNQVahT4QJ=*z`%#~A%zku)#j*FJkw=dn4Z0@Oj!^!DLH4BU z@&76b?MbOU_oUu`%|UWx(bjmL$Ngvm5&PdnBJO9CiMWsT(hm2%kwo0T4k6;cIf{t; z28oVbaMo5;9{ zi2GjDYBbyM!FCMW@WXa2+wjG99NX|0MdWyh91oG>A!0l(BJ$uRG9Du1AtIjmNFenf zQV$~aAVQC5BK0IvPa^dsLeD57^Fd@jh|C8O`EU_=UqNI(iOeSv`OKj%7+)?CygVZ6 zBA*C-Qkf6vlSYI-qlxg7L4=>NMEIFN#5g7rF^)_k#xaSAabyt@M>Y|0f9Q}(gbry$=r@`O{W6HqZ!8h|Pas17iA3n1Nre8Bh{$CY5qZoeB8NGe zms}#_CNgd!;%1IB*@h3cC$X(Hk;S&wL^j*-mqFxsh#U`*;~`=^DMZFYWIRO1Lqt3| z%m?(yB~k|>bjT+{pG+e4BvMZz^&~>i3?lPEWIl+@2NC&5A!1&o5}8jT^GQTL3#dEl zpqBbTk2)gsXdpt5Mk4GA$%9=H5q8By^jktizokUOLUE0MYqsVfn>mJpd2BJ)CIUWmv`0TFpG zBr>l==9P%N_D~m`?+KAAvoe2Fph|s^22>lNb zp??<<`gaqN%R@xu@h}lN?4kaQo5;9{jGKtKnd2_D_4?4ww${WUwzVb>vkiakM2?5Z z@eny4BF589WIRO1Lu5Qe#M8rkK#yJ`bs$2AJ|gt#B2rHx^(0bHBJ^x0G9N_dgUEak zk&k8~=2r`m`6M!*MC8+TO1$V1{~aLoNFYLwL?ZM^Cc@539_%8Cup2@|zfnZ=JB)~a zeMIy-f{1ZP6EW@>BE}s{#JJ;#h&!H$I1`A7Kaq&|lZntRg^2OHI1cFNB|^VQBJ>+V zg#J-P=s%1I{e48}KZ1x{MiY_87$R~QOGN(Sh+l9VIZpgU#!qDYM8wa!h-O=BA%<=E z;qh3u;fw7!w&5>|$ng+49wNs>#CTjp#zSO0M8-ozJn`QFQWqk1AyOA2bcrTXS0Z&K zQdc5$jUqBHMCOIaybzHW7ZLNoOJrV&%qtOj&7m$hpG!nt$qv8^?c%{KgH5IG(q$3x_Jh!{@_k?{~250UW@5l;^D0X=ew)PV>c@`=zV zlSn;@)RRa(iO@5H$b1l)4L5|PgW>JB|>sSot1BSMb`BJ^k^ z!mf}!*cB0BS4>2|B}DXFN<_b9MD$xu#JDSn7fIrg5$_> z;wLhGBI73_e%3_=+gb~iY{L(aSFsIWY}c?2er5qa&QE;!#y zL|q&qLYF=wbZKE;pi3(e_H9Jiw-aICK}7$ZMD%}vi2l2X=)aqY@gE{${D+Ace-9Dk z?;|4qULxW@LPY${>>u&B5TRcy5&E?ep8_O&n$${@RHg50T>`ay&$grVBG zc!-FnhxvdWy+rCjgbsZ~=+i}{ojv->) zu|$kJj)=J9iHI|Si1-tUh(DPK-BO6$KX4q-&r5`UkwoY>gb4kkh|qr+5&HXx(0>FG zxr`YIC7l$iHx7f_=$+0brH?B)VBGc!-RLhO!P0MCcMtq^?BjN~Eqt=o&?2UWm*Kk$E8^ zFD@eHftSd<5}8*b@|r_ka6Xray2v9!mwY00No8K3OBxaOqlvK3Ai{nu5&cgfqW_6R z^q)yY|C5Lqe-;tr&n9C0IYf*^$29fz7 zG9N_dgNS^j5V?OKGM_}|lZbp4P-!LEo1yJ8~xEg_=c zQX={-Bck7OBF0@o#JDSo7Lcby+ z^eZMp{}LkfFC{|%G9vUZCnA>>MC7rOh#XcCk-r+^7aT{96F-sh6B$1d@v|-}*w$L8 zWE*~Xyozo3V!MWI_$wiDJVcI%$ng*{o&qA{Au=8!;~^rRTIPqk5UC51x)7mD1(CWE zsVkAX5}|7ek$E99FGS{rh`baKk@rF(^Gal1iO6dYb;0>wBI@D@5xVpdp-T(%0$o~( zux}&6zMTmB4kG&RB%=QVMD*W9ME~7HjQsfL(656C{X2=!{{RvCcM+j~Hxao!L_{7B6OqFn>d&}|jGM@~iHMsy z?qXZ758Z5QO&nrdYvM55@Yhb{c!(Sik>ep^Jk3PLLu5Qe#zRCrJbjT+{pG+e4BvMZz^&~>i3?lPEWIl+@2NC&5A#(pfWIl<^ zClUE9pzhG4mij=CIwJIFAVQBuBJ2vugIy63cEv>WTS7#?r9|{wMnu2mM2x$Fh;dgE zG43iN#$7{1+_gl+Sw}?t4MfD>NQ7?9MD8Cr4(L}%gnmUt=vPdH{v|}{UrL1jWkl#- zPDCy%h{$6l5jm_PB7Zf+FF1}ICw?O1Co+B_;%8k{u&uRF$u|7(cop05#dZzb@K-|Q zc!(Sik>ep^JOxC?Lu5Qe#zRCrwagE7AyOA2bs<8R3LVosVMAXF*B6R5^LYEfi1-i5nVc$lCeLE5M9YplsNksn# zi0HqIi2l2Y82=$6#($WI@%Ioh{yrk&?EI73laLY5}{uk5&E?gpPe)YMCwU|p6x{D zgUEaknGYiJ(M;t2fyjIknNK3}$@fwC4FumkDTt^DHsk+^bu{Y9^k%$c@j^sR&=rMu zO`wZck>^@*&XtknydRAJe&v||Zae0`Up?l(+mHG0H;(!5j${6N?=k<~dCY&mbT+yfaL&Xt_KT?cVJYO+J z@j}H|#h)q0DPE))uXw3qg5u?hiHf5XlNFmQ)~356#?@Y_|9vzn>e>Q)T{O-$=k@mW zE_~fU&ubp{y#9r5f zZ@lKdT6lY_Pr~I4=)hAJ;Mw3tjGVa0pE2KnG@RCHnHsMfYW~@`#LbZAdbf( zo&JaLSmf{m_xEA^;PF7UDX4;JCyd zT(N3al^?ML6|pzm`B?py4^6&v{Z zd;P(rzvJ6vBIEx1%L8jFV~3si!Pq4R;}0=)A4Dt%590T7(tGvz#tpuS^xbXci{G%> zb>sa1wH;lh50fvW6Y?c_G<_qlQWvIg$mh#1$s z&Ku(+9xu-+)b)Kw>uBow{_uiS9{a%2I)=wSfY#?h>k9_fTI|6U8~AyD*UqH(@eM5T zczvg_pO2lsW7*Hg!wW|9*xOFuaXj`m`u;Kc{>i|7i#@nv13w>c#caGmyuSZ7^7;1L_#vPBkxyt!w7*CFcsFVY z<0EoR?_2Zv$H$w`T>Gdm#v|i1bK1-aGp9|RnK^Ch40Ae)_9iZKy)kj&+91~<6Bn)x za$PfV;o5M#n#g4Sb&X7+e~fDqkLenj%3~Ot`x4Z|WdqlQ*n=xJ@H5!@n8ki{eN1CN zh&h|bbbTDnV~E@BN8i5~xNorsS8U+tWY{#x5}!e~9U1*2f&ipzC7>V?eHQ zc}&;Gu{?%+xdVtRY2diT9$c~c3hQGY`_c7r0{cN7L~<0Kx#{B~art$#JJ)?yE?*uc+V>thl7(e*Kl{ouM$%wxJfX7d=X9qwPF z@81sGx7dR#Ht=(@>!XYvcH#$Pml%vc#B?(2V+mu>^)ZJr;CffeW4b=(@))jp?rRWN z`oM9CJ-A{6KZC80W$Z`S$2|6fYiT);>H3(@W4NBWuS4Hs2JTzz!4(_$Iob75#tu92 zgRx5t#vfw(I_sn43qGX}lP{wa@+EmReIu_@7p8CI_5W&pOrgFQkBraEX)`CxoHli4 z=Cr9Z%;^l;o4CyN#>9ndgItG9T(~yKbbyZRzH!-NmI@c<&3sCLzFXGIZ?{VusBi55slE- zFy)N3IKz}PR{i*tGr{8clp|Wg&j{sAv^XP_Bl?09t(;7Y6RjMR>lo!svN$oyk?RTk z#40Dt;>0RPY8IS0@|APEx~t%INB3m~%B$ot-Io=r5BCkY7X916*CMe;Es71sJ=ngiiv8%m ztcd+!uGR3E?#qgK4D-!>Bl;dcaNlANuGqlO$?nT!?64C*7`wz^{2`{3*_YKa2HlsH zFa}&B>Ud1|Wu-iZ>xBCz#C7w)afv;+Vgo;e{oSI0{ph}|jQ!yH)5v4GFDvIUT!Y-d zN8h&$+_%_+D>m?RvimX_JM6>{#x5}!e~9Vp?8_uy@F{(md>NgPFUh0n8+nzwFnuGh z-^9MGnY!w}tb)2?O=;mV-IrDJ7}gc{tkm$}}UxNvQd>yU{H*9N(+nYeImINti$#r*5~*i8Qz zS2vI8`q;u_7@Kwmu$WKe|4)vLD2Jn8$Q|Y~wM+?Vg6d?;W^r zu?JUd;OAu5M;SZp#1F15W&9>$>SV>@F&u6lV)*T)VXL%!V85!Z}?;}Uyt z#Rh%`TOW_GA6*|i*$?WVkH>UFcbIk}vp_K1{xhPRN(!(e#bHN?n+~k=JixeRO>fy6XDaMO`tsy*#GtV>gdse*5q& z$%kiP13eQHdvL`Deg<0~BiWCxkB8U~t{X#mOxMT5JcetB?-ca??ScCidvL`Deol6M zl(EB3{9x=7gYk!$PG)_KVhp-I_Amxq?}qW1u8+MuhHIYhJBaJlf#VW;aK#3G23sF} z>_^wfBkTv)(h)qS>ti2};d<&j4SkNgPFUh0n8+nzwFnuGh|5xi{Gxf!IWPD~$n>k_Tw5c;Qr%jzXajM5u66)9I-eJ$~mHb8kN&$aT=A=ryNsXC#pY} zWxHp6_<7*@?tgvWZG7=>Yp#%grxv|BmO{&)SI1JQ+(_jVS)54a6e(wja*8d^5akpr zCrUXb7AHzMCCVA5oKlN3OgW{>@hPXw;`o$PrkoMVDYrNylvA#pXysH`oM`1pEh3*W z%Bi$CG0Le_Ke5WGvN*BIsZvgya%wD2oN{WE6R(_FixaP$TID1tr_SOeD5p+2iOOlP zIEl(>P)@RP8ZAz;avGJBqMT-nlcJnv<)kX7#p0wYr$sqw%4xMYY07C;&S>SdS)9?z zX;V&ya@s9UhH~1KGgdhr7H6z-I+Qa(Ih__~f^s^QGf_DQEY3vb98gZCa=I)|rgFNJ zGf6q!7H5)jx|NfqoI@5TOF4&>ldYV?7AIRdhn16~oF0plqnsY)C zTgEd6^UfIkVV{%0W9FSP9>ZS8hj+$&gS|7R++pfxuzSly_G8`|qYd^@$vkG>8RIeR zqkMR0%s1FOW6B+&eopq@GD_`yL}(x}pl|W_HSaAYU+^h?n0&#f^nrXy9ud3rjk=ON zn!dlGd&?B+YTg-RjMx{a@|byNjK{Dy_Til|-(c^IDK|#_40dms#(vB@W3<7Zdo+)k zcgA=O`)(iJ8S@SH&X{uJ)X&M@TSlv0ED;(=4Cq_@o#ee`24gVqjL{$N6~^+Id1s8r zaKGTgJ7d1V-WgMFg8CWk-f{x_G4G7g2KONodCa^s#$&h_@!_2@-(c^IDK}aDob0`2 zyxJuap@GDJzQy0yytkBm!Kd_L@&%vL2l6F(MC{Tx>Pqrx`u+y)En|*zFDCODW0A3$ z`HZnhEt&a@vB=oWd^Reg<0`v)GS$UyL@0Ih)7K`(ixCwGr=&`38GmOu3`g&&jTh zDQcHSga#4=`WAmDxi;o72J^lc{UKMmJZ9b(<1yw7?~C~cdtXesW7W@KYhxb!G4G4f z26d3nW9EG^9^=}G_r-jJy)UNRiR$NM*TxLBn?QsH5(D}ce_wNLlzhRb^kMP^pV9~N zC3!^b(l_c#@@V@0hStUc>T2E>V~m*Fg*;~77vnLmjd)+oH`x1P%AKTs23s48*pGQ% zj5fG#6!VyQUyR4NHsXCT-(c^HDK}gFob1||sdiaJXdp45Z}E4MYhwvxFz<`eAFg+$ zJZ9b(<1wy{cwfvn*!yD2%~d~xt&L^u$Gk5_8>|oIJZ9b(<1wy{cwfvn*!yD2%~wAs zyEf*iT^GuV?~4s}-t|f$ zVjN%TeKF<@T!{&>c-2R$<-@C-R3bQ$%1N_0k;+L^&Jg8{wm3tSGg>)O%E_=eQOXgG z(AO~KjI}t!lrvWS_>?oj;`o#!TEfo=824p(U(7ey`(ny1RX>C6%Np2^d0&h+xc)Tqn0a4}$G9)U`(nPq z-WOADx%xTTeVN3L{>x|&4I~EiE&jgdzD)83pVEiP7ko+|$d}~N^o@FuJet10p?z61 zbv5scF-EK@Ej(u47vnMR%kaLKZ?N~plv}BO2HTglvLExl7;Ug#wegsFUyR4NFT?v{ zzQNuXQ*Mp=IoW+#h1yjSp@GDJzQx~3?#tR4gLz+!{;yU{H*9N%`nYd1{FY99ddELfy@n+_N*DW67H5ShtTX+n;?ZtPr#N(~ahu9C-LiF8ATf}&n$8>FO<1y&s!~0^s!QK~BuGqj& z^lUR*tl zf!8U-)y{DthrK+;y#O@r;4$Rahxf&NgS{`NT(NRP6{>1m_#N+jSg#B<`RI~2l0Ld5eiV^?e>BMd2S8$nos5HH zxBVgh?%jw5-wG4ozvLDC;ztpW7grQx;2Md#?x7!C_lEJP`)Nj6t-~QwF?PEXOU!w0Lw8gb_1ds8)0{QIYF_=p@+xAi^ziT<7;a~tE4@nMe3wVCxpEzR6Eb!O%^#v|jy+?H#Ci3`_;4%(Tx zaE*{_f{6>)2)QPhxOjcSIFJ2*n8d{}K~y3)M%9 z<)ctJ5+^uC%4xMYMapRW%VHj7iNoHpf@D5u@xlqg3uf}c|5bXc5H<%n+Jlqsjv z;*=>zv;?PIIR`9GxpG8ba4MA3WpOH$Be@2rQaRlgr&2kRe{ialbI9UUDMxA+oEqgE zwm3D)kvajVRyjQur&c*VL~!bq(`#|+l+&x62IU;FI1S1 zKbK|ev%b4L?t5hFi#6&B`A1BsbFZE&wETH>EQQLAR8En_iBwLJa)v0U*y0RPPO);L zlv84HqLfpjoMFl-wK&6+Q>q-Fa>^`@PdR1E8KInVi!(ww<;saxPKCvZR*uvnavr0c zN{bVtoJ#c*tDGu}6RVsm<-{qc#^S^&r$#yP%Bi(D@ye-HPJ(jkEKY)Q>XehHoCb@N zsGJ7nBrB)U;v_4lQ8_8fX|^~i%4t?ks&ZN^PO5TRl#`~MR*RFSoL1$GR!*D68LgZ) znITMuAX>lefr&Bo-m2<%2OjOPRlOZ>S1?ufD(L zRZgUGA}vm&aw3&8L^(q&&Jg7cQBIU{qAX67a-x(oOgY0W&M@T+Q;ttLK8xd1j!!uw zlrzHOj8M)9 z;>0T_UO5TMNw7Ex%1Ka8qH+=~PNH%Wm6NQTWQ&umoMh#sC@00@q$npvIjPD?wK%ED zNmWjoa?&hLnsU;VGg>*LEzW4=j8;yDaxyGVhH^5LGgdicEzVfwj8)DA&XPnHERhf5rUDRL&&zGs)siQa_WFlck(2i<70CEahY?C)?s= zD<@kyIm*egI62D6QBJOMaxG4-a&ncEr<^>Clc$_K<>dc=_U=C}_Oi?yIG%$?@ZieP z5ioJZ9F-Ci6BB1JN5v$i92FCjiV_o7?BI%ti83axn3!YYiYwWaXsBb3iHbVrm{_Ay zk>ZIGeJIhesAYHAUH0{`o#%61eD2Pr&3ERUwf*n;8BZ>88BvmW`HJ26E!AE6QvoX88l{)W{_rx zX2_T!njxBDnqgyxX@+THG%;ghG%=bHnh|40Xhvv8X-171r5UA()5ML5)5K{KGznu8 zGzpq9nlWR>XvS#9X~vBirx~Y7(j<*Z(j;k8G$~_JG%1=1nh9ejXeMaVG-+efG-;Yi znn`0OX(nl=Xr_#rqM4$ZrkOTonr512hGxc?8JZcIS(;g6W@%<==4j@OnWLGbnWvdI zW}arAW`SnGm<5^znnjvLV-{%^X_jb~j9H>tqFJU{HfEV-nP!D%#h4YE6`EC=Rby6Z zR%tRlH&w`*Q`y=&RNfwI???S+9V%abhwFC<_TQJ}+J8^0d2k=FYc!e4t~6_41(Fx* zB~|jfg0(fUBKaNGUP`e4z9iTFds@wdIInJcH25mk)+Lp)Uo~qenbyFx?Z~I~K;5+s zC|l#9{bi3~y$NeflD@L(zThi}Eor89RZAQA`A4zT3+qEQ@;iPe=9AxHji?0s?@My+ zzo*qai1Wr%`1}KF%93U(yH?8KXMtss7i(K}@;iS1Q7*s3`c(<`-w&s!8&I~!d-t0B z<5^G5S>eH~afot;BQZKBrHp%Z6*V3>vh1j$z5w) zn{ZvwYmjRbt_yk%a&5wOA=6xJm9gi&F(mavz1rk={EVhvekb=v?7uI`wf~-0^B_*H zdtuc9&W_$2we85K^+4UV4JcdV?clw! zQ`*3LV_52ivFeiF@!r@Zzmt0-_TQJ}+J8^0c@QVpy|G)$;k~h0@?swJ$nSV>Y?0r| zy%GEGOLFbMr`0@&v!nM$Z9DR5Jy3UT1IpHT@A2NKZ;VL4^4{1geT8$oPkzUHW1IX=?v2=gUy^J8J+0&Afm zj`zk6`JLPwvH!j#*ZzB2&4V~QdT-RWBcIj-b=NkaY>l^r_r|ESf%nEvsTZzygYrAx z8@uFpa&N@``;uJy?`bs;;^ewF4oNw@H+D;2TuX=Lcf2?D$nWIdi2e5^x%S`FY97Sd z(R-t|9r?5#sJpfSWox|mcyHA4LQE~gjTd5S85l1eM^`q+Rmahl{a3g*dVOB4=QQf0 z^>gPm>Z9|?ozrffxpUghGn~_UEpY8}*BjR^TpRQ{dyh^CRIm?msYF^%>S z%JR`P8RMgAVw^IXW@E}|v@a2-oTkN?avJSlm+(jPcXx_#;jwO}jCb zG&*Nts%SclsiM(&3{y?hX-qXur=&17G+oBj(CB#rQ%lorOf5|}m$v=Q3?O@@YL#cWnd8)_6F-c4W;WA#LDuSybwUYs8rRj?ZO-@;iAh z!~Xk{T>I~7H4ozCdM+E6a`;>}BzbZDNy_i|TsADfljkz*zc0zP|DIO!AkL0HmucIP zPwRoYYa39u#(R&?WjbDnsb#qFLQE|KinYJDIv>vFtwgF{pyd8Wlo02y0xhx^|!hLpHe#hssG5MW5mtp^XNv{3(w3-KT zay^&LNI85i8<)JehtJCI_*|Bh-^p_s_TQJ}+J8^0c@SqupUbrE$fxx{-L(xUTjRaQ z=Q15H#MCm}cp;{if$`FDbY){)bsSyU|BKIMdQPK0T0eJAqdq#H+&S&$nLDT5Ji|Gy z*8|FlvK(tcq;q8R&6`-X+2PPZ3D{IcxeCYo07rTv5qh4AMeN7HeySfsa;Fb2Dwh5 zT~ksojN!8Uj(;OIEx*I~mSF#VNv{3(w3-KTW*@`489rN(G*j6tQV#e2&q!X3|El~> zt~uCyH!Hux94f*7`;uJy?`bs;;>iBekeoB!uaX9qHL`L z##zS|WosQU&a&sxvB-MK2|GbjFKd}Gr)w}oRZe8~y{2!E3+4HZS*9jLE#bhU-Ep_T!i4+K*4Gc@Xc7=kd7+{y#ZM zGtGys>t5(BV0mxyIe0;0;QF(5-DGbOUwf-$tuBl5S_$fc{rRQ2_UF@T9>gm9x)y4T0oe#gHZT$a~xtt`cU{nA|f^=UN^;=Oyl`Y*?SOK%y=`@K9X;X1G) zF>tNlx^AYooUbkNnRQiO!}Ylo`}a$8?cb->Jc#$^1Ne*tpM^;({qp9^+s?&IpR;M7 zAfMI;ZP7NNY>kKhc>6`H#pCZgBz@}v{2yzGEvdwQ+l*(X&)IZ55mU=>^1z{i64XP|vKR4L9O@^j)aecL*@)MA zh+f-KAFUs*eR^$2eRRILYlEAI?%II*X#H?)&})io7p^VSc0S-5qt_JIF1beAF_P;W z>iOGi}TujrJSN5Y3D+Lp0i#FvB#n#thSF|H8y*=8TEa=vc#y z(99b%LZjmkGfJ~y%qWe{S(rG@qA_tAohL8}nk8crG)t1gjL|F`Ge)yaGfuN&%s9;o zO_FBSm?X_AO@zj4{^gmxCFV1?jQjT)OXg_apX0C1#eBZjXX53vE`78GH2uaD(Dc(3 z(F_<9xMMl)ng8O;z)InA&!ph+9kK$E6vq?t6Pk!F%6OfzLnm}ZKmiDufECYouQ zW||penrUWeT4-jCX`z{=X{DJnrj=%nrj2Iam^PYuns%B6W7=sJXgX*Xjp?9Sr0Jwt zGNzMeiKdHY*_bYxWtwi96=S+-R%m)?R*mVQS*6Kz?b^Do>Z%GpLzT#LE1s|N_FTKZ zZe3S>m7lMb$@4C*SNZZ9?wO_7msXlY?>PTeM9m zTjQZWO76#V72d~6TDA$#?s$JIY36o5+FQ-GyvjB0VyPFNZ?>)*@2%l$vs|C^$!mBP zD#gCF(p>x2Xf+Swz4|!zQsF(9q?zmTL~kw2dyQ*pWfB9=c3amad+Yex>wLa0m)EwS zF4)Ibnrj~$t>!_zKRkfFGkErtRO<4F$Fe_PYo8#W)(36THlb{dhyHl=RkRI%qblj_ z19&fw*pf=@SIu~4dcM~2L`*HijVEGi85mC;XID1HUB}s#jd3q|4C9UWwUU-Sj^}9f zv7~k%+bgf)y)Wt~Y39EFQE!O->)zW|NT1>PTHf2%^ELP0)-SKgdt2;lE6ug9jaKs@ z-uAq=ZD4tCat*6eV&EBF-rF|vwYRvwStYOGdA$_-+)8upbEDNfi1+%FSj)nihosUk zubcNmna(}!6XetSpe@=al&$gPy{*}sIsYWy>matInfv^u-Z0zZ-rH77{qUYd-rF|u zwcpA2)!=$pBd_6mJW8?etu)uZH(JeucyGUg_kZ|5(!_zw_e2iPrTQYRO<3pj`z0OC&*VTanKfR6Ux?j z=nwn8{dX_o{|QHINhNl!_qIBoh^b|`@kC551LLXV?8?Tt>o~izG4AhpZ~F?y8+|;F z^tBhU&V_nN`ua~W$MBw4QmNA$=6aBEADpxkbjCPbbIn~3+#Gb*12+e8J<#ij zYm>WHxi;atqSr9jCR|ta8s^%B>q_SNQFT=-=YYF6hoqjUpWK_<_?o*n*UM{iZ^pj3 z(p>xEXf+SwZO^^Ao#nZEbA!a-y}5(0xqEY?ye9W%?2{|awNH*#^B~@i-kY^gkWcG_ zwrHDBw#NG(+?zYu7I$wBOZ_mWa&PY9Ywq6MB(KT68T;l+bM2d>)jWu|J@@8rmgnxx z%@PCiNAAr%e9hgPTjVv&rBdvpE6uf!j#l#^-j3dzwNH>w>w~svn^3mKdyn^K9Z$s6 zGTe9~rj~*6)NyuYW88I|UDS>+a31(r36v$i2Cbuep13o4h9XX6&mg&9$$N zR`Vd<_S~EMS)RK$w@VCMkL2Dwz}MWpxkFx)do%XgmFC)KN2_@dZ%6OV+9$}T^+8*- zO((d`xUR~*d62KUdvlk(CiiCSyDQDL?~YdUAl~-en}=AQyEk`B z3|zzI-aO3L+`YL+UXyz>_TiQ0+J{H0c@S?$@6FmL$fxx|TeM9mTjRaQd$W!wVrm&~ zJP}jNzk4oipyklktbuHlZ!~j8Si5 zriX}TGwj;6<$I+`AuO!H3GY+}6rxaYzMy*w9=@HO{b*vFWq z*q2wDYhNC%=0Q8Q=ecl{<+!_z z?RhR7XL;_qa7bd{x+TwrNxtTu3y0;kEvO6j@s;M<$49Gq5N}7H3$;&>PwRuWXq!;B z#(R&?g*u*ysb#qFL`*FMg{iqC~9_OE*`j7gv2-Xzb36MW4*7mmnl z@?400eWkhf_0eh`#M_?d!Zgcs&xNBB1NT9BE}Z0R?zu27ugP;E_W70O+UG~Bc@S?$ zp9{55kWcG_wrHDBw#NG(JQq%}E$+E6A@#%kT%HT3`I>t!9Fy1Nxe)vQN^|Y|qt!f! zw>{5=Gc3*uZssE^J!cTI5f&|MSU zJj69YuO+Ts?t10gg=>pm$6UK`ZPDwPYZtC9UiarY&I5OUPRZD!esX`F=WAu$r#d08 zVeern_63&a+80Qxc@VGUmsp3!cQZH1di1+Tl7kKx6l&$NY=v`rX zuW|39g{hT$izrur${`LR!s(c(RY~HGF@t?4z^aCH$KCY$fA9 zLdMa0p-tL0#M8Lw7mbVkf;&rG?j3yh|5NaqSyRpQ8Hyqv*V0rWMc^ck7E=Y_m zQkNHci}>1`rE8x(EXr%8s0;QF`f}|bq}4o#x8<;SaLZvI3P>t-*<$v5X8Mdp`vm#4 zK4^=!31w?M^oRYPh&K+yUP8o{G;=#AdyCnYxA?inlGG2^(XH!V>hddvCR@40_;RbIpW z!-xHYzFhkUX*Cbxz4<)$4`TnQq*9kRf0F(4P3;rpTah?ui?#`6YdrLaz5l=cJU&Z8 zY)K{dTV^~noqIZ-h^b|`@kC551LLXV?8?Tt>o~izG4A&B6Z?5f>GOvLN>L98l1iOkH`fENbsW7Wpgvl^5?=FBADwURn&9T4yC%4Kh--pgOI*8fZJCz7bM3;l zMXx2UUAVUBwZyecu4}00yRX->juYW~@sy+}Pu6itO?xta|F4t{t8GGC`WR!v#OR}$ zkQAn$CT&bVO`2waX404enn{`{&6F`w8to&LHApjU%pi^S8_W>Rj4?wr+LtiHG_%GG z(`f&~#AxP>iP5;R9-)~xW`st^A8|%$7K|CC(K!nfr&%;6PNVY}CPA}gOoC=fQkXHC zWn;!@mTAUmR*V^^S)obNtQwP~S*3CF%WMASnY<;3ZQHk+asMF8lR29A=lE-LF`uvX znRxlEOCN0kO}{Y(H2pM1Gy}#I(G1WO(?pFaris${Xag>O`N8hCSgo9O@gL|X3Urx znlYMMnsH-lX~t>lXp+X%(Ija?G$~_3G%1>Tnh9g-X(nhIXwt?s(4=V^X(o+nq?x1% z(@Yr?rkSE?qM0_PiDsInnP$eAW||qA7MfXOT4-izT50BtX{DK?X``7prj2Hvrk!TN zn0A^4nhu&pV>)OSX*y|^jOnCVqUoYpHl~YanWmd&#h7lI6`CHJRbzT+R%tx1UEF(^ zXY$&6=W&_7|5x@T;@+9Z*!hf+Z(`)rG{rPN z8lN#f8Xrv=O_?!eG-Wj9H08#W)0ERx&{P;xK~q8Fr|}!(r}5KN(o`B#NmEHvMN?%= z6-^aQHBGfK)il*KH8eHG)X>z>)Y8-%Q%h4zQ%6&0OdU-fO^7CBOo%2#Q%_TGOg&9K zO#@AXF%2{gG>tTk#x&A2(u8Tk#)N6YG)**3#x&71(KORE8`DhFOw&TsVoVE73ys_N z+-i*Od&c?IO4G(TZN{`QP8&@-O}jDeH0?AUG#$ot&~(sr(sUZrNz+NwMbl+W7flyU zH%+%O-89`aJv2SW^w9LsL}(($L}(&3eKdW>^wIRu^wabk(@)b+Ge9$7%mB>*O_U~T zOq3={Ge|RN%plDm%@ECyF+(&%G{ZE*#thR8)5K_E#>8l1G$S-4#*EO6(2UZI8Z$~W zN)xAv8xyCA(a_v&PKQ z%+k!!%o#IBGegV8(k#*}(JUFWM6*P*OtWmvGR-p0 z3eAc!D>N%Kt2C>|tkSH~fTn<^h^EMxBAOzaVwz%OifM{zd^A2|d^A3qGMX}D%4o`H z%4y1tDW@r?si3Jarh=w|#!urn#!us?sidhirjn+Tri!M@m@1konrfPAW2$MYX=-R{ zjH#iip{b>*HKvxPmZpxT&X_uyI+_qo$e0jKh^C&V-k5rtdYT5B24fm%8fY468jWeB zX`~6$gpCQ)glU>+nv7|pX`*SSX*Q;rrkSRNrp1^RniiT?npR_4X{PMS_*I%zs-x@fwL>7wbP>89y6rkkdlriZ4-m>!xQng~tA zmTo zh-R2(*qC9OVVW3C%$OKWjAn#p#F!D95t>n&QDa7FMrqQie`dl!k7t~37Rxb+L$y=nr4z_(wIq_ zNt!8|DPyK+rf8;Vrj41VnWmYcnK5RDW`<^#X4aTlnpv7TnmJ?UXy$0;>e<O)A(q7 z#`tJ_G-Whp#+1>N(UjAa8&ghGPE$csVN3;01&yD^Z;YSDPg6-#X-p+eB~2Agl`&N` zRW#K!)y7oQRMXVZ)EHAkQ$tfrQ)^5uO)X6wO`S1yG<7r~nvgLenh;GrO}#PoH1#wM zG!4cy&@|9A(li>=NYh9YrU@GprU}zD(KH#;MAJmmOw(*kGfgv13r&kLEi^4Otu(F1 zw9>TFw9&K~(?-)q(@xWFOgl|GO$SYfF=G@Ue^#&ptj(sa>u8Pi46Mbk~wZA>>! zH%$*sk1;(oJv0%Th%phG2u&YNpD}$jeKh?v{l@gu^wSK`3>Y&&Ge8rii5e57iP8+x z3>q^?Ge|Q;Gi1yV%@EBn&9E`UG{ZD8nwT*$ni$Op&4@80G$S;lG^56h(u~r?Y2wDj zY2q{qnuIY4ngq=l&6qJ`G-EX5G~>pM(~Q$3X_CeyX_7Q4nv^jqniS0h&4e)%G!ryw znzS)#nl#NM&7?7tG?O$_G*iY*(M-`y(@YyPO*2h1Lo;K{49yJ9EX}Mjvoy0bb2M|t z%+buz%+t&pGfy*5vp}<8%mU2<%_7aBF^e>dG)pu~#w^h+(Ja#}8?#KaOtV6>V$2H7 z3e76bsxhlHt2CL`j`X`bxPQs*GtKj@t@CVM_o1u&e65uG$@1kjJTL7e`^h#vxUT6_ zfBKs2h1rEE4TPfda3#h#t5>+b8V;%l!I ztnFSs|#}56M@GcJ7_Mof=0h<865i z`>U|`Qqs(I8SkxSd9#aa`w7b=FZNN%9@IL%_8Pwfv|L`po+{rysLQ_D>!NXBH4oyw z`~RO`d?5SYHf;;?X&m&8w#mgq8@K!tZNt80NngDm-{XPrPLWjFxy9_e%Cxsl#}hHN z3^$&x-!Ps!&aP~XyNX+AKU+I46`~9=`y~csnJczeF`$`*F-aNmrv{K5${y5oJ+Q`@5 zoLxKjs^m57mGd2dx*V9jE*b|`^B|t=HGaoFW3vx2)48W@K|YOxwrHDNJhajNUCA4d z<2wtn$5+zKeLmS6W?S68(rRf7_5;ek(k8y<_LbJiYqGEOV6^iC+1sgcU^NfoZO^{a zW|rsnmDWmm*n24ZN?Z7v+gDmAugSjBLr|APv)4uAz-k`E+tGcc+7{%~IB1Ku$;Cq( z-^;#I9Z$s6GTeB&e#3a`IJ>ej?mBN=*%)`PeWkO{RLB(KfkwXycCFpF7zWcYh8`TQH__f9~RI z?*7~)ugSgRD75qF?CsPzu$l+)w&(ub&GOv+xmn7?{E_=}4_|Zl=N5SlbIBJ(U5?3K z7mWj}c@S?$@6Xy63#y?$3RE&E22d3 zxUS0md62KU`*WAPhHI?vB((G6+1sgcU^NfoZO{FAh~>HabGMX-Yq;E>hxwYjKljLM zxSsn?L0vwPy)GIDR`Vd_SL++a3=ApYLxOs?cLRj*_U`wq&|L>-Tr~);?DVNs4;dzx&9$^RSa|k@v=UkGvE97HoZ9t3TPUPDWGYfDWYjKriiAIrkEydOfgNE#z)g+ zjE|;?ri`Z9m@=AXnsS;JW6Eh-Xewx0jj5n%rSa3W8RMsEqp756H>Q%Nou-PW!7uEn={Ba8rkkdYrpK5%njV@=^H9IfgV!VXoEVY$jyWXH zi6eZ?Jty|bYnZFPQ*o_2E&H`f9DYwkI5SYE?5&36v!@|o;) z(KxW02l3v%AAd)PwH8TbF20>(9Y@=Od>RLB(KfkwXycZbv5tekzm#-G*Ku?_5mU=3 z;dr`!!+7dAyRtFvI&WOr829aZPJ9{bIH+G4(#+>xvNy&4b0jKdm+x=R|D_@@X8jMcd@!p^ZE8oGACtgw(xU+BMlb#df{L?_3>|*YF(-zVp$p z3$nLM4z^d15EyZgeUYXgP& zdDmC=!tqK_QZ2)*xs_(9tBw`Q(6ZcEp$shxW2Iw=vb7EvQ=JniTib>)eeLKcg0G=$ zNwq#t?HQ0hDSYawU?G0q^~b0W{?1*}-#w1+e#M%dq*^z#cAM#YRwL|lt)n~VQ8%4W z?woh?%$@V7o7NHMd{pwIP1-hhJwltbZMb#}$?L9dZ}Yl`Hfh^%?eLltDap4Le~&Eb z?wAvsF()qGHYaw?(9fC&R`Ve5*7d%tc3=OeUg@*l@v~Q1X({7x@O=l8?uN21L0Ok> zD=X9d(>$=62YIE8-S&N-&cEIEEf2`gQr>P`x2?mNx^eHafcz|dx^e&P z=d{)raWtN5tE&szp>g*w(Q|s^{uP0Z__^qaG8`Y)RLd~q_CBw1Lm66@8#k1peS~q- z@kH5L2REK5Tib^5-gW)oUR8uSS-igNs;#9M&vg&d!G*n z_Qo8L)N2mUNk6|2f448``_bRM53KX=w5`80jjQH?)jY`iz7uN#?>n&`M~!DW3le{S ztZzwLfzJ=tqnw?ym!o-LH4pOcf86nb{f`UbI9|)y|Hy6QndvhNttawn9M?t{5A}cF z38?o8$K$98y#Kg*93f4;`f5q){y}{Af}|fn8+Jh(3bVIC^T28zN< zIX^Sq*HY|rt)n|XQ8%6IyYl=*-L#H4Z}mEky6GInc{(Ne(I#yh&T~Dl(I#yh?lCj+ zI@+Xd!}+b}HQJ8QQ z;`h^}jp?UJ(+to|8Z$tn{ed`9nki$VG}=cngEZ5|4AN-7!3@#N7&AnpeF-y6Gi%H+ zjrK20jAqW57>$lK%m~fAF(WiO{xG973&xDn=$wFw(<~Yjr_p%=lb~5LCPAZf2WE_B z*_bgJolh|1G%Lo8)94(7Nz$wulcdpk2jk|K*Zj*fc{l97Ht+K8-0kE8cFMf27Qx!d zhQe*@YVvagYbP5pA7x!l(mrEkT}@0MjjXGQ={H8!)x`AE$hw-C0b^ucP0Rp|tgDHM z8YAm!Vxly%t|n&C7+F^nGe{%rYGQ_rk##jOLo~9kCT7?eSyvM?Oe5=RVq(U~x|*06 zjjXGQ88JrI)x?a@$hw-CQDbCXP0T2btgDHM8zbv#V&XKit|lg7jI67PNzll;nwT+T zWL-_n7>%r}i5WLW*44y})5yA-n4~eXt|lf)6QW5O6QW7c)YD8DQ%^HN(?F9prhz6+ z(?~OEOe4)CO_*lNm@v&0O%u(uF-~6vq;lPvt&#s%@R!)&9X6FG|M#IG%Ln*)2z_+(5xEM zL$gZbdHvc8_qPLZ?UD3AJX7tCXR2I#=V&z#@*Z%?#{vhOax#vOc|N-pNS^($S4q;p zMLF0P=g+k-j#l#^?|#R8G_c<>bvQn%V51- zaeORr;4vrTsMFM|uZkt!L3l49>7i%?_PqIX?RlfsJji>{IgNpX&iOQsM$f(~lRW!k z4~C@spd9RH^XJ;nMyq*{ci*D|fqjqq2#$c3v+pOe_m#E{`Lt};MwG4b(AI;3sCO`c zqcL#kQJ==~5lyA94l?7AaX*{X4KcM0Hx7uYeS&e&@o{ClIpWI3cpdNwjMFC?abTRz z!8oD+B>mf?>TrBS)BS>&8>pY8UgK9G_4p9_Q_>@mVy~J%*IqSenfF5%wgf(O;osqC z@hqoOYz_7XNqPjz!9Fy9u6<~*>x-)JxA1cW$D7IQcZn*a0950h`MZ2_p z?waP>w~zPxx{&0n#^=eB9)|j0&zL{go-ta@gS^$BYYkL??z1>rJ?CG88&$S}DLT zfy2)FERIiU>UFM$r9J`lrKCrr4cP1D&$ZW!R`Vcl;F7LD;F7<`(dF4!&61}Qdk-W% z80BCemp|7&E?Uilyp^Yh1C^(K5=U6esk}6MUuoNrPs?^~MA;e-Z4I1;dY=}?(G@uQ z)W65^Nlm4%0%jaC-IsJ65L3%==9+;rOJcRi|NYpnj5ijbE$uQ62UsNqPeM6??S&x%Oz$Y98dRyRJJ>cilhW==Ln9 zUGf}{Ju#9VhjOt0%Aafh6|Lq$-s7+73mkvVS8?=dImcg~ef+d-$fsqyHll2ehql&T zi+W$%hod`i!ZrVZgzrfW1}zTzji%H4pOE-_jqbzvUY^`aS!q zTk`CIJy4QvLOIwsRLd~ql4-qN#|33*S#DfVhV~K0MaK(e zYaQI2LD||ij9=XW7`Fr7j|1a&AjS>tlT_;V@oT=Jb^AERQhu(#7X6JemQ?CiXUN)M&=dK&BeK^OPWn9rNZJ)cQpWi-t+GJiu@7nJl^^bz(-`E%`+qSZXe8|sY&LcLevhq~lAeM#V2_hO*B&QY&4aur-!>RH`L=(= zG3eP>Lz1T!YnqZCg>tZe$)9Wg60PPz-rCKbf!fVq!qKVa)ZUuCue5E*r)9e~qHK+a zww`=3>V0u1j={hwoBt8Vmo$~WI@ydvrspFa2gKAe+&Cbn_6f#8$H$fJ=7=jB;}yCU z<8|LEJ|EXSu$l*XKYVUm;KS#B0Y{sb z^Wl55_m#E{`81Aeql<^OHl2t1o`+aS&p!A2IKH5%w4uq2L#DZ|0yi$`cKl+&ixLKFKBxDd6*lhpQKW!MsxmoJqPJI zi27*#+&PH)=)894AnK#_bLSxHqw@#npq{&~UGDne+J$pjuN$si?%L(rg>%_!{8KXS zpTyoENk4({$9^Ke*-w;d{521(=0V<1-Z32b&%7l)3vIw2A%CttLbRF(d7B?h1ezcG9*%@(U(HCKkKwa(Nl!#M*dydO zdxSFemF9ufJjna88wLU&yWwj%2DF@yJ(Rt#v~9?zaaM%4Sp0UU|ISvPzS z$JaEKzG^n(km;P%aX?Hh!;J%CYM)>nbbMUdZjQLJFGCdmSYGJo*)TfzHjf7l>B#An&K29SeN=*&pH<^DJjU z^0Z>lgruJg<~x6`KNz~1IsE%z4~fN>hlHc>yWe^ZNOfjb93zlqSZXe`-PuR1itX|DI61? z<*Z1aov}Ye()B0@dx6f)wHJt1^B}LhS6#nxgT6mszj4=q{4DKS|J=4d%k=(S+lVr? z4z8`PE@-pHeQtxk2VVc&L}0!A{PSILOlhiRm~qLt7l?J$vfQ|!4DBO~i;fq{);hR3 zgR-@47(cDUBO7!t(E3Nl0_*Yf&d;I_n1hnGKRt!x2bzB28T2>CSW>Nk5)KBZ_&P~)$=M~OPJ*UwwZJ)btpk3NNoa1^uLA$hl?wW>nY5Pv} zzAr`OeL3otk`(ok{XjeKvTZyw?g!#ra&78kj0qE?k7k17(od5%rk^HFGe9$G%mB?K zO_XNJm?(|*5!y0HGi}Tu%{1c-(aab#M5BF)IKwov#thTUGER(U&X^dDjy2+p(99b% zLZjmkGfJ~y%qWe{379y|qA_tAohL8}nk8crG&*-+#%Pv}8Kcqp1T#*vV$3*=&M}xI z&8jg;8l87AZhm=P|ME=U^&8jb-Nrk2$+{nC{f2GpLh^G2@BPl#mn0^{r7ZNjIjI0ZZ8K9AMAu&;7WL-#1lt$Kt#0(lE>q24%X=GhU z%#bm%E+l4%M%IPI3>zcsLSlw#WL-#1%otf05)-45bs;e$#>l#mm=PLT7ZNjSjI0ZZ z8KseRAu(}dWL-#1oJQ7##3YQ7bs;ec8d(<-GiHpe3yB${k#!+4Tnh9g-X(nhIXwt?s(4=V^X(o+nq?x1%(@Yr?rkSE?qM0_P ziDsInnP$eAW||qA7MfXOT4-izT50BtX{DK?X``7prj2Hvrk!TNn0A^4nhu&pV>)OS zX*y|^jOnCVqUoYpHl~YanWmd&#h7lI6`CHJRbzT+R%tx1U$UPO*ExF~bNA1@J2#$u zg8W}M8U9{458v^%Gv=rJdtv!G58v^%Gh*eV9-11Hk9vs7rzxN*Fs6W}fToD1$e1FU zBAQ~FVq=PFifMc_K4W||KAJL`GGoeU%4o`I%8e*#<2S}nl zsWhgNrjn+LrplNqnkt%VnrdUJX{u>zXljh9p{b#%rKvThmZp}bj;79-I+{9~5KYLK z5KV}to~GWIdYXEg2AT$A8fY458fhAhX{2eS3Dbm)3DbmWnrNDgX`*SOX{Kp5rkSRh zriG@(m=>BA8o7?ixzlQlT*u_xX{BkSX)~scrj4eZrrnr!ns%BFnhs++XgX**X*!MR zr0JyTqUkcGi>8aFo2J{CZkleI9-1CwdT4rRA~X?WA~X@2KAJvb`e^!S`f2)&>8I(Z z8K4<3W`JgZCQ1`ECQ1{f8KfCBW{_r(W{76Um?4@Wnqit@V}@ylX<{@nV`4Nhnh}~2 zV@7C3Xhvy9jTxmGrHRwTjfvC5X%aLEV-hq8nlYL&W5#I4XvS&AjTxsIr%BQzjY-lZ zX;L&PV^TCJnhBZ-VARhm^}R%upgJfEXVur75zo^K@mBEFMU*1>Z8f6IBa zng@B$|H)4S=l^69$4>)Z#Xvob!IRZM|fV41cGl^+Z06szWDqkjIUhe-?Y1CH)M_*&F5Tlf4|x1FLzE z_p?tX1D}2J2^>i+=d&+o?<=h*@@X8`Mi&qDzu+m<`>7<3mjYjUau&xEno3_?V8$WS z`nZk*Vrm&~99*AZ9CUnK*=~-wvN2xgzl?Eu`6V0}r`Iq}=s!u@o=oF-Leuk}!rVap zB=s7<3hB?ySQnS{%jnmA(Xabu?^n$Ot9g)j^B-OhZ2rR{j@LcQsg(GaV!x%NT_|UN zlygA#ax@RD=0V;|-~L_T(zh3I{7%cc^#5cZKdmS7X&l!^7Z3H{{Cm{<_rJsOdf>}% zFXC9x)T^(mrS6wu|F5JyXv2YM!@=3xpm|_55At62Uw;f-_FpSF{^;3PwGzJt`?MrI z2jzSK+zyC+z zihp0m@gJUj)hzKZ#Cav@-=UnNQBE*>IhqGn^C0hquWSii_{ubnEn3cn|Czn7w4TVP zaaNp^#mf^<1^$Es7$H$fJ=7=jB z<8|?WVx0c-KX722{vG3l{*$!hl^Gn&4avG7XIJBm4$^tNxjNxm-yFUkEx_zMLEZzoD;H_qj_L85At5K^De<_cHSAs zF8X~k*Zkk?ittawn9M?t{5B0zHfn9^wJ`fK``nCIgIPMEbDt&dW8HY@B zUB>}2wG1~7u1_!yIzFy!H%DCA7_TcgVw^T^3`*L!7sd(wC+S!3&&P3JK+vU(`qI=gvVluiZK5=8roE-Tc8h7?%95UGDne+J$pjuN$si?%L(r z^>^O)pS+T_b>xtwJHPXD*g~u$XZzmCcdsLd*Xo_eWjVYpOq$#Ee8&gaZrt#4<8RMgAqA8rh}%Mrqh^enogP;nl58%Xu4=>X}XQ6rRk=r zqvv|WF`F%A$FO@Wc>(D1~9Xd7pbx8BTY98dhdZ+clt9RN7$9m7}UBATd z#pkJ#UWIZ_Lpf(;FGushY98e6{qH{odjESB$Dj0i*SkLZ^-k-Fd>Y5K(Zxgkuim;Y zc=gsl1tg99cOH(_fTUi16_vW*fX{Lz9Y7n-L>tb^-UiJBt9g+3hP_LJH|)JPj#AHZ zh9v&w_^embZj^I2$~h-{IhqGn^C0i#|MIVa%l~Bw$G>V{U0#~Kue6@Xr*T{xT|CtP zhJPyw-tce#8jy70U&?SS1tgWey1|S?rh9{q17d0!ZX8^nU>tOOT-k1pxUw-`SC?Xb zm6qaIAB^n16OO$#z3N|916QFQlJ@=^<_78~sn__$q(5)OXWxAgD1)q&e`VExxd6aW*_Hr~2tmZ-9TMj%pc*}tY;y75# zxn-a1lpuwF#emfkH6-D)jY_1)4ux!Z`yZX9Q%3Bv$Vv&9($f8?MFEm zqnt~!m!o-LH4pM$ziH3l^_w=~*i*~7e!uMVOzVk!8ppNK#Y6pX+7tEOb59)m1;4&& zUmTk>_3EoBsr&8N-z(`5+Hfh_a9Q>?XdYP2gS@vNenjy0!w<)CglAvPNc`)t=ULK! zKslGAoGY@Iqj_L85At5O+wQ^ZcH0fd?pn@uM`Z6Sttawn9M?t{5B0x&chr0L-EkZd z9NO)09J^^MeRaDThfL?Bjss$98Ezb0pI{txd|cUXj<~WhUN;?qaXR7%92lp=F;3_| zN&9!(gkv{NuiqVW1ND>CYy9S}}9Iu$l*X z?>gh8;9X~&f#W34zFLv^VeFfg^i-5nh;lY&FGushY98bbe=8OUf9p;hF}?qUPs-j` zT2JKDIIfK@9_oMBw?7uV>)Ww_r1yU7bR2gEB$d9p%Zx*&xvt}Ym|BJ#2iGSU2OS?* zwwoiaY>d|(Ct;jUItd5H=?sh$`cKl>w?a7X3`qLzZy%2%7LZixbcZ?ryzW0K>0i`G z>vt2c-ELmHbI{G7>v_#}^9SePl;n5qa@PmfE}YAH-Ei%4*DlvCoXcMGEW-EUsSNMK zWgl0@{m@buyl2-ot(W&fYwzVJOpHDny+^_H)1-~*r%6i+Ge9$G%m9tvgJ7aGQ^rJT zw2xp0X{L=Cq|y5T%n;3tF+()kmoURLv&Ib5=ye_@Ml)wjj7G;AW`t(mm=PMiuEC7b zEEqFNqjMG}PP1rCoJOx(FbSF^V-hq=lERG9EE_XMqt_0Yaherl#%Wdg z4T$6Bm)HEuGkM*9=)(WMA6obF4q@#=_W8>CkEFwrZdhB_lJy_?d6-7lf5gO$k@X)j zF&bI_5i??ptpA7^p^^0;F{8%F`j41V8d?7l6E{ZIf5gOTWc^1>!Wdcq5tE>i^&c@~ z#>o1Qm@yhz{}D58jI95N8K;r;A2CT|Wc^1>k|soxGA2ZmqN%5uFs7bnf~J8cZA=4A znx>Iv(wIh?Nt!UtlrdqNDViplX=9pbrfHgKW{hd3nW1T+nKh<`W|pRvX3m&anmL*_ znt5Z|Xy$3!X%>uWr&*xspjkAggJzMYlV-`7PMRf}E}CUyx@eYZx@lI7>84qs>7iLQ zriW&g#`F4BifiiKSbLUq1p9d8`N{m9S*HCpd9<1bdGG%CDZ#rx{&5_qcs{2UNS<$D zPmZK_;yDf9!+1}Q?_tzDu$l*Xzje&9!EYUN431;9oNt|y{W(qRiF_Kzwb8{xTkk#= z^*;7k9H#_Fj`=u_V>I>Zt7579eb|#D=>up3zT@$p9N+P%d0;gU^4@pOnZf(cIS0p? zo_$p&@xO`drli9t2j9bZPmb?l)I6}72YJ7FbTIhMqmRZB)N;OgX7;|)dLp03acy+* zQ2+aasCO`k6uo?0Wq}jMF(7C-k4BcOHEVj-xgGRuFRo^^??V{3@hBzlS|Jl0Jfd#rIC$ljD0QH4m)j zLEi6O_?h7MF1!%OXFSWPl=x%VlOyTFCEK^+b+u9S6WZx(>Sh;E*|Rt=wYb$VTa+kDEQ=|m*F^6Q|YTm%{XM5>pBjIsb#ov zaD9St(D89)yE)>@#&~`2B8<~T7vaD-U50T&|4I7rq37c`RMWA;FgH*?Nu^HTGv}Yz z`?oylU(`qI=gvVluiZK5=8roE-Tc8hSSC3+_lTK3+J-eJPS$O z1oq@e`XJo<<^Qxlk^iUtNo)US-vRtT`)Jf6PvUc*4<Hi#+kO&JM=UIt$0y8bAJdH?K}yxAyt`JIm6xAfLu@ZF2F@w#3<} z@7ZVL_P zlZ%IXKXDrBd)jF@E)70@>LoZ%)l~ZC3DfUu=bY>Jwb1g(bTJNI;GANg^?~vpGVz4 z6W-R7e;y{jUs-vcYL)lYLVyW{SOGXbC+*V_H#o#$5` z{@>J)^egJ4^-J&^bMx1oV{X2boMU0h@7m?gf7dRYt9o5p`LPI z*miwiJLmFBW$mso5|VUh^qcuUgkAr<59crQ$@}S@H>~+QyhoCsLy{s^zPyIC-k5xv zdYS^724f0n8fc1W8jUHUX{0Hp2^&*P6Q=ReG#TTgX`(5kX*Q;erkSRkrp1_YniiT0 z8hJnM`lo`XmBvrgW{jVvji!>O-Iz+6cA6@h4r8ilI%ukCI*qBO>7=Ql=`yBU-st zIIa#peMK*hD>U`$o2bKwn+vXNj8E!TjLWUJ;=s7vhH*i^N&3|0 zD{ySq^amGXE}(vrdW~01`f;)_G9u~A=+A(6f2xI1i#(Ixy*)Vj-S6VK-825E#C@qS z5|{Mnh+pR&UoDJUB7jEq`ySnKk8j~wJ>UtXZqoLgVPT`jN@Lv*`bU*h<>vVV?oxfkPd@4YxME)Qc|&~K9d{M@^6 zoU7?e=V30Oev(R^Ce8Wf^&AtCenow>e(oG|^VgkYsE^jqonxqv&Oe-EQOWPx<<5WC zE}W}+U2yGk*Cf|2xi)z`$D}0gPx0(1=}+K}_a1k(Flv$Kr+0ia_|rS?!0}Dbd6ky9 zY4oe4KSum|@AztA)FMy%rkjK5n{L8!v&K(kIU|j)yDT%>`FB#^=#xq$jf>NQ?-(vQC?jLb{=YxL*I-ue)wvzk2pr9FKU$Uy!(Sg^@)` z{}19fddF7_qZWDQo_;1c_w>^^p3(Sok7OS&tsnAf9M>in5B2`lGpO$~&)|3@`0J;i z#qqSJUVXD9b^c9ZWLeVRqVAvcuDejhomv>R$RppWm$!4CeqUhT&iMiPS=y2J+_pYi`@X<;#?g8rj>dCsb9In5 zO5Epm((en*d+xcQ{JidGJLC9SP*N?!jKkXZ1-`Qk9S4-5Ww~)c8QM1(2OS@jt#z2= zc%y7>o6HfZ!y`NC_XXxX@<>pAUiU2OfVn2=Z=e2I@V6K{Nq_SU`Wa&?sn*S$cV73E z6#HB2>CQdWPv^Be_fS8rr#tshKb@C9<~fUYY5UxD0qxTE$#p^Eqg~oQcdbIZw0&~T z^0===qPF4d1qfoIEP%D`WR!v#OR}$V7vQi(#G`Dq-h3d zCXE@OnWTx*Oc@iUnW7n_nKovSW}0S*X2zHy8tqH;$uP~VF~c;oj1!}oGbTo(V~sc? zH1o!c(CGNXjM6L^GfJa#0wzwgXiS_&=Lt-LX33ZYjm{mIF`8v##%Odt!Hm}kgUflO=$oQ^njFEL2F#|NRE+ZytjI7IuiPFfrjF>@V zWL-wgAdRfch#4|Q)@8&D(a5@tm|jjYRvi5Vm7GGbyhvMwWL#28tZ5i>#~ z>oQ_SjgfU3F{3oHE+ZyxjI7IuiPOlsjF^NmvMwVgK_lxjV#bV-br~^ZG_o!uX51KA zmk~2gBkM9^lE%oojF==%h$dxBh$cl-PcvamJO)A(q7#`tJ_G-Whp#+1>N(UjAa8&ghGPE$csVN3;01&yD^Z;YSD zPg6-#X-p+eB~2Agl`&N`RW#K!)y7oQRMXVZ)EHAkQ$tfrQ)^5uO)X6wO`S1yG<7r~ znvgLenh;GrO}#PoH1#wMG!4cy&@|9A(li>=NYh9YrU@GprU}zD(KH#;MAJmmOw(*k zGfgv13r&kLEi^4Otu(F1xa(OfO&d*{F>Q>~M$=ByZcIB(J52{ohcO*A9WG(9vCnuswGng~rFO`kD+G<`JvH2uc()AZ8} z&Dwl<22*OjMI$MBx#byBx#Z~ zDVmfqDVh|`1kHpo6EqVvX_~Y#X__?6B+aBTlQfewQ#4b?OwmlyOw&voGfgv1Gea|D z%nZ#8%`DBVF|#zYG;=g_#>~;o(ah7#8#7NcPqRR?V9Wx|0?i`LqA`m!i!@6#OU5kG zEYU2}EE}^-vrMx>vtrB&%?iyb&8ji0G^;fFcM*7Q@_eq6?_tI>kUkgjePJG+r>@DD z?_bXFJhexL=cqm2^&DkPKI@ZDQ@}bG7*jw~KvP6hWK0oF5lt~ou`$Io#WX$|pD{if zA59renK5NFWi;h9<;IlLl+#quR2Wl1Q$gdW@f+i(@zYe&R2oxBQ%O@rQ)NsQO%+Ww zO|>!AG}SaUG&RQ5(A3b>($pGLOH)fzM^k4^9Zelgh$duAh$ci+Pg8G9Jxx7L15JZ5 z4KxijjWmtMG}1KEglWRYglWPwO*Bo$G|@ECG}AO2(@fJ$(?Zi?Obbm5O)E{SF|9PM zG;K6(#5zO%F|kCSpv4CPLFk(`QT{O&?7^O}{byH2pLKGy}#A&ahfb znkG#%Ni%88B+Vqv6wQ<|Q#4aF(=^k@Ow&x$%+SmjGea{&GfOjT%q-0;%^b~~F>^F? zH1jm`#>~^q(=5;|7_&gLK(k1*Xv`wbBFz%bk}*p(OEk+g%f>9zEYqyetQfOGvqG~< zvueyL%_>cvJY(TGDQ{2n{3Fj;SX0W|lg~di`NrhaG{rPN8lN#f8Xrv=O_?!eG-Wj9H08#W)0ERx&{P;xK~q8Fr|}!(r}5KN(o`B# zNmEHvMN?%=6-^aQHBGfK)il*KH8eHG)X>z>)Y8-%Q%h4zQ%6&0OdU-fO^7CBOo%2# zQ%_TGOg&9KO#@AXF%2{gG>tTk#x&A2(u8Tk#)N6YG)**3#x&71(KORE8`DhFOw&Ts zVoVE73r#Cct1+!Ktu$>kZN{|Gw9&NFv>Ve-(@xVt(_u^pO$SXUO{X!PG@UeEG+oAY z(R9&t({vltP18-&L(^kS4^0nEgeGE4geF4MN7H9aA59-kKTW?e{WSeF12hB14A2bF zL}{YNL}{WlgEWK24AKnJ4ABf3Gek2)GfXpV%rMO`O^haHOpGQ*GeR?B%m~d0%_z;N zF{3o2G;x}^F>#tWO@bz2OoApsGe$FJ%oxoW%{a}tG2=AjG)bDIF-e*vO^POEOo}E& zGeI+9%mmE@O`0ZcOqwQ5Gf6XP%p}bu%@oa)F;g^CG}AQG#!S;p)6CG!7&AjNLo-V= zYs@UoEX^FvoH27Wb2Rfb^Ty26%+oB;EEuyuvp};*vuMmB%_7Yb&5|)oG)pwgG|R>; z(=5}h(5x7A}Gmu$FT6f5{eJ#J1&*lF7w}5MZD^l$H zx8F|{%I9uKOA7USDW=K`BfjEa{(kCx5(~fIgugq&9+~3e|5ST1e$JDh@%v&Q(!IqY zm9p`7F%_&wHDmi3yH0+O*foq@VPaRC*cFUj&Da$tc8IaVj9t&zEsWj7*dY@;Y+{EP zJIvT26T6kMI~lu;v3nT1i?Lfx>`oKAm9aY+yVb;wFm{x&`xtweu?HDDVq!;4>yGxjQDFEjR>iM?cE&oTBAW6zn`c{q<`J{IrA`MrtrTYfL|dlTokyzb`r zCNsa~XPMu7aehnc<~L(kGq#_x>lnL+u`5jMY7@JHv8x%o!o&_Sc9^m28M}qCn;1J} zVuwxa5MzfKJ7i+FGIl3pw=s4PV|OujtBKudVz)AOCu6so*b&B#GIk$h4>R^4V@FKv zsEHk6>?mVLOzaqACm4H#v6GBF#@I0vJ7HqS7(2n(F%vt**i(!>!Pv8mJ`7OVf`Mn3{ zx4iD=_a0_`%g-{uOE|wJb@Q9Cs~OwR*maCu!`KxjcD0FJ!PwP|U14H}7(2|^^^D!Z z*iDQbGO@!Zc8IaVj2$wuTN%5PvD+BChq1dDyVb<*G_hM5yOXh7P3#C`NB>{DcI?_j z6vqMlm%GauG@g-25*6DMJ33@22;z{zDIf%KbhyDmI!FgM>+u?bNQRi9N`)XN1YI+9 zv!o~V4~WpALxvkNh&W{ESQ>vXd>{Rx|A51LaJ=_>`Q7LD^5YGK26hMb0QL@SCG5Vi z73@B2CF}(D2=);6KI}c%iLgh)PGFB=gC{b}H-)_8j&M z_9^TW*qN~B!p>mNVQ0c7{`+TnzpJ?4W!!JQukUvm_gjB%?sr+-Z@t#{yNdg*XLG+{ z*I}>0egJzNb|~z+utV5&*rBi+uv@Sn!hQ<-3G9ZjTf%O@ZozH{JA%Cl`x)#l*e_v6 z!rl~i1bY*9By0t{54!_<0DA|v5_VtM3U(j15_ST61bYa3ANC&XMA#!?C$LAb6Je*Y zC$JA;PhlUyPK7-Yb_#m}I~8^Ydk%XB`xN#G>`d5mVP~-Curt^p|1SO7<$6Yr=hXD< zdXD~|ubY4SI@~zxuEd|ZH>h*4!g&kFkB_brQK_D}VKrJf7vp2Z`J#@C@f5M|>Ntoq z#24~9F2%nQ7yN2OtI0TABx--?(rxv*9foRLTh{U78S)&b8tLM z{ierft?^ka@rQ1}XRR!af6r!W`^(z9H1vL=XYtfHx3p(rM|j!MZIeWY!YoBaL4Sh9k3m+9k3m+ z9k3m+9k3m+9k3m+9k3m+9k3m+9k3m+9r!;xkmF;y{De5(I?wm9)|38Rk4yZ>ycZn5 z*BclnugtMyHhC_1L=kV8y#nu*__@iCd54$u+$TD&pYNE}oxk!L_j2?~zkp%#?sBZx frp`Cc^D8Fnyq5lcI*-dO$M;7$N+0JDo#*`lV0b$X diff --git a/3rdparty/amd_bins_linux/zcash/gpu/blake2bcl.h b/3rdparty/amd_bins_linux/zcash/gpu/blake2bcl.h deleted file mode 100644 index 13cad965c..000000000 --- a/3rdparty/amd_bins_linux/zcash/gpu/blake2bcl.h +++ /dev/null @@ -1,150 +0,0 @@ -// Blake2-B CUDA Implementation -// tpruvot@github July 2016 -// permission granted to use under MIT license -// modified for use in Zcash by John Tromp September 2016 - -/** - * uint2 direct ops by c++ operator definitions - */ - -// static __device__ __forceinline__ uint2 operator^ (uint2 a, uint2 b) { -// return make_uint2(a.x ^ b.x, a.y ^ b.y); -// } - -// uint2 ROR/ROL methods -uint2 ROR2(const uint2 a, const int offset) { - uint2 result; - if (!offset) - result = a; - else if (offset < 32) { - result.y = ((a.y >> offset) | (a.x << (32 - offset))); - result.x = ((a.x >> offset) | (a.y << (32 - offset))); - } else if (offset == 32) { - result.y = a.x; - result.x = a.y; - } else { - result.y = ((a.x >> (offset - 32)) | (a.y << (64 - offset))); - result.x = ((a.y >> (offset - 32)) | (a.x << (64 - offset))); - } - return result; -} - -uint2 SWAPUINT2(uint2 value) { - uint2 result; - result.x = value.y; - result.y = value.x; - return result; -// return make_uint2(value.y, value.x); -} - -#define ROR24(u) ROR2(u,24) -#define ROR16(u) ROR2(u,16) - -__constant int8_t blake2b_sigma[12][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } , - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } -}; - -void G(const int32_t r, const int32_t i, uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d, uint64_t const m[16]) { - *a += *b + m[ blake2b_sigma[r][2*i] ]; - ((uint2*)d)[0] = SWAPUINT2( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR24( ((uint2*)b)[0] ^ ((uint2*)c)[0] ); - *a += *b + m[ blake2b_sigma[r][2*i+1] ]; - ((uint2*)d)[0] = ROR16( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR2( ((uint2*)b)[0] ^ ((uint2*)c)[0], 63U); -} - -#define ROUND(r) \ - G(r, 0, &v[0], &v[4], &v[ 8], &v[12], m); \ - G(r, 1, &v[1], &v[5], &v[ 9], &v[13], m); \ - G(r, 2, &v[2], &v[6], &v[10], &v[14], m); \ - G(r, 3, &v[3], &v[7], &v[11], &v[15], m); \ - G(r, 4, &v[0], &v[5], &v[10], &v[15], m); \ - G(r, 5, &v[1], &v[6], &v[11], &v[12], m); \ - G(r, 6, &v[2], &v[7], &v[ 8], &v[13], m); \ - G(r, 7, &v[3], &v[4], &v[ 9], &v[14], m); - -void blake2b_gpu_hash(blake2b_state *state, uint32_t idx, uint8_t *hash, uint32_t outlen) { - const uint32_t leb = idx; - *(uint32_t*)(state->buf + state->buflen) = leb; - state->buflen += 4; - state->counter += state->buflen; - for (unsigned i = 0; i < BLAKE2B_BLOCKBYTES - state->buflen; i++) - state->buf[i+state->buflen] = 0; - - uint64_t *d_data = (uint64_t *)state->buf; - uint64_t m[16]; - - m[0] = d_data[0]; - m[1] = d_data[1]; - m[2] = d_data[2]; - m[3] = d_data[3]; - m[4] = d_data[4]; - m[5] = d_data[5]; - m[6] = d_data[6]; - m[7] = d_data[7]; - m[8] = d_data[8]; - m[9] = d_data[9]; - m[10] = d_data[10]; - m[11] = d_data[11]; - m[12] = d_data[12]; - m[13] = d_data[13]; - m[14] = d_data[14]; - m[15] = d_data[15]; - - uint64_t v[16]; - - v[0] = state->h[0]; - v[1] = state->h[1]; - v[2] = state->h[2]; - v[3] = state->h[3]; - v[4] = state->h[4]; - v[5] = state->h[5]; - v[6] = state->h[6]; - v[7] = state->h[7]; - v[8] = 0x6a09e667f3bcc908; - v[9] = 0xbb67ae8584caa73b; - v[10] = 0x3c6ef372fe94f82b; - v[11] = 0xa54ff53a5f1d36f1; - v[12] = 0x510e527fade682d1 ^ state->counter; - v[13] = 0x9b05688c2b3e6c1f; - v[14] = 0x1f83d9abfb41bd6b ^ 0xffffffffffffffff; - v[15] = 0x5be0cd19137e2179; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - ROUND( 10 ); - ROUND( 11 ); - - state->h[0] ^= v[0] ^ v[ 8]; - state->h[1] ^= v[1] ^ v[ 9]; - state->h[2] ^= v[2] ^ v[10]; - state->h[3] ^= v[3] ^ v[11]; - state->h[4] ^= v[4] ^ v[12]; - state->h[5] ^= v[5] ^ v[13]; - state->h[6] ^= v[6] ^ v[14]; - state->h[7] ^= v[7] ^ v[15]; - - for (unsigned i = 0; i < outlen; i++) - hash[i] = ((uint8_t*)state->h)[i]; -} diff --git a/3rdparty/amd_bins_linux/zcash/gpu/common.h b/3rdparty/amd_bins_linux/zcash/gpu/common.h deleted file mode 100644 index 22ba9548e..000000000 --- a/3rdparty/amd_bins_linux/zcash/gpu/common.h +++ /dev/null @@ -1,156 +0,0 @@ -#if defined(__OPENCL_HOST__) -#define __global -#include "../blake2.h" -#else -typedef char int8_t; -typedef uchar uint8_t; -typedef short int16_t; -typedef ushort uint16_t; -typedef int int32_t; -typedef uint uint32_t; -typedef long int64_t; -typedef ulong uint64_t; - -#if defined(_MSC_VER) -#define ALIGN(x) __declspec(align(x)) -#else -#define ALIGN(x) __attribute__ ((__aligned__(x))) -#endif - -enum blake2b_constant -{ - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 -}; - -#pragma pack(push, 1) -ALIGN( 64 ) typedef struct __blake2b_state { - uint64_t h[8]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - uint16_t counter; - uint8_t buflen; - uint8_t lastblock; -} blake2b_state; -#pragma pack(pop) -#endif - -#define COLLISION_BIT_LENGTH (WN / (WK+1)) -#define COLLISION_BYTE_LENGTH ((COLLISION_BIT_LENGTH+7)/8) -#define FINAL_FULL_WIDTH (2*COLLISION_BYTE_LENGTH+sizeof(uint32_t)*(1 << (WK))) - - -#define NDIGITS (WK+1) -#define DIGITBITS (WN/(NDIGITS)) -#define PROOFSIZE (1u< 64 -#error cant use XBITMAP with more than 64 slots -#endif - uint64_t xhashmap[NRESTS]; - uint64_t xmap; -#else - xslot nxhashslots[NRESTS]; - xslot xhashslots[NRESTS][XFULL]; - xslot *xx; - uint32_t n0; - uint32_t n1; -#endif - uint32_t s0; -} collisiondata; - - -typedef struct equi { - blake2b_state blake_ctx; - htalloc hta; - __global bsizes *nslots; - __global proof *sols; - uint32_t nsols; - uint32_t nthreads; -} equi; diff --git a/3rdparty/amd_bins_linux/zcash/gpu/equihash.cl b/3rdparty/amd_bins_linux/zcash/gpu/equihash.cl deleted file mode 100644 index 213a8e4d6..000000000 --- a/3rdparty/amd_bins_linux/zcash/gpu/equihash.cl +++ /dev/null @@ -1,1038 +0,0 @@ -#include "common.h" - -#include "blake2bcl.h" - -#define tree0_ptr(heap, r) ((__global bucket0 *)(heap + r)) -#define tree1_ptr(heap, r) ((__global bucket1 *)(heap + r)) - -uint32_t tree_bucket(tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS) & SLOTMASK; -} - -uint32_t tree_slotid1(tree t) -{ - const uint32_t slotMask = ((1u<> (BUCKBITS+SLOTBITS)) & SLOTMASK; -} - -uint32_t tree_xhash(tree t) -{ - return t >> (2*SLOTBITS + BUCKBITS); -} - -uint32_t tree_getindex(const tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS); -} - -void tree_setindex(tree *t, uint32_t idx) -{ - const uint32_t bucketMask = ((1u<> SLOTBITS); - (*t) |= ((idx & slotMask) << BUCKBITS); -} - -void tree_setxhash(tree *t, uint32_t xhash) -{ - const uint32_t xhashMask = ((1u << RESTBITS)-1); - (*t) &= ~(xhashMask << (2*SLOTBITS + BUCKBITS)); - (*t) |= (xhash << (2*SLOTBITS + BUCKBITS)); -} - -tree tree_create3(uint32_t bucketId, uint32_t s0, uint32_t s1) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)); -} - -tree tree_create4(uint32_t bucketId, uint32_t s0, uint32_t s1, uint32_t xhash) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)) | (xhash << (2*SLOTBITS+BUCKBITS));; -} - -// size (in bytes) of hash in round 0 <= r < WK -uint32_t hashsize(const uint32_t r) -{ -#ifdef XINTREE - const uint32_t hashbits = WN - (r+1) * DIGITBITS; -#else - const uint32_t hashbits = WN - (r+1) * DIGITBITS + RESTBITS; -#endif - return (hashbits + 7) / 8; -} - -uint32_t hashwords(uint32_t bytes) -{ - return (bytes + 3) / 4; -} - -htlayout htlayout_create_2(uint32_t r) -{ - htlayout R; - R.prevhashunits = 0; - R.dunits = 0; - - uint32_t nexthashbytes = hashsize(r); - R.nexthashunits = hashwords(nexthashbytes); - - R.prevbo = 0; - R.nextbo = R.nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3 - if (r) { - uint32_t prevhashbytes = hashsize(r-1); - R.prevhashunits = hashwords(prevhashbytes); - R.prevbo = R.prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3 - R.dunits = R.prevhashunits - R.nexthashunits; - } - - return R; -} - -uint32_t htlayout_getxhash0(uint32_t prevbo, __global const slot0 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] >> 4; -#elif WN == 200 && RESTBITS == 8 - return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return (pslot->hash->bytes[prevbo] & 0x3) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#else -#error non implemented -#endif -} - -uint32_t htlayout_getxhash1(uint32_t prevbo, __global const slot1 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 8 - return pslot->hash->bytes[prevbo]; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return pslot->hash->bytes[prevbo] & 0x3f; -#else -#error non implemented -#endif -} - -bool htlayout_equal(uint32_t prevhashunits, __global const hashunit *hash0, __global const hashunit *hash1) -{ - return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; -} - -void collisiondata_clear(collisiondata *data) -{ -#ifdef XBITMAP - // memset(xhashmap, 0, NRESTS * sizeof(u64)); - for (unsigned i = 0; i < NRESTS; i++) - data->xhashmap[i] = 0; -#else - // memset(nxhashslots, 0, NRESTS * sizeof(xslot)); - for (unsigned i = 0; i < NRESTS; i++) - data->nxhashslots[i] = 0; -#endif -} - -bool collisiondata_addslot(collisiondata *data, uint32_t s1, uint32_t xh) -{ -#ifdef XBITMAP - data->xmap = data->xhashmap[xh]; - data->xhashmap[xh] |= (uint64_t)1 << s1; - data->s0 = ~0; - return true; -#else - data->n1 = (uint32_t)data->nxhashslots[xh]++; - if (data->n1 >= XFULL) - return false; - data->xx = data->xhashslots[xh]; - data->xx[data->n1] = s1; - data->n0 = 0; - return true; -#endif -} - -bool collisiondata_nextcollision(collisiondata *data) -{ -#ifdef XBITMAP - return data->xmap != 0; -#else - return data->n0 < data->n1; -#endif -} - -uint64_t __ffsll(uint64_t x) -{ - return x ? (64 - clz(x & -x)) : 0; -} - -uint32_t collisiondata_slot(collisiondata *data) { -#ifdef XBITMAP - const uint32_t ffs = __ffsll(xmap); - data->s0 += ffs; - data->xmap >>= ffs; - return data->s0; -#else - return (uint32_t)data->xx[data->n0++]; -#endif -} - -uint32_t equi_getnslots(__global bsizes *nslots, const uint32_t r, const uint32_t bid) -{ - __global uint32_t *nslot = &nslots[r&1][bid]; - const uint32_t n = min(*nslot, NSLOTS); - *nslot = 0; - return n; -} - -void equi_orderindices(__global uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - -void local_orderindices(uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - - -void equi_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - equi_orderindices(indices, size); -} - -void equi_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - equi_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - equi_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - equi_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - equi_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - equi_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - equi_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - equi_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - equi_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void local_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - local_orderindices(indices, size); -} - -void local_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - local_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - local_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - local_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - local_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - local_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - local_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - local_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - local_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -// proper dupe test is a little costly on GPU, so allow false negatives -bool equi_probdupe(uint32_t *prf) { - unsigned short susp[PROOFSIZE]; - for (unsigned i = 0; i < PROOFSIZE; i++) - susp[i] = 0xFFFF; - - for (unsigned i = 0; i < PROOFSIZE; i++) { - uint32_t bin = prf[i] & (PROOFSIZE-1); - unsigned short msb = prf[i] >> WK; - if (msb == susp[bin]) - return true; - susp[bin] = msb; - } - - return false; -} - -void equi_candidate(__global uint32_t *heap0, - __global uint32_t *heap1, - __global proof *sols, - __global uint32_t *nsols, - const tree t) -{ - proof prf; -#if WK==9 - local_listindices9(heap0, heap1, t, (uint32_t*)&prf); -#elif WK==5 - local_listindices5(heap0, heap1, t, (uint32_t*)&prf); -#else -#error not implemented -#endif - if (equi_probdupe(prf)) - return; - uint32_t soli = atomic_inc(nsols); - if (soli < MAXSOLS) -#if WK==9 - equi_listindices9(heap0, heap1, t, sols[soli]); -#elif WK==5 - equi_listindices5(heap0, heap1, t, sols[soli]); -#else -#error not implemented -#endif -} - - -__kernel void digitH(__global blake2b_state *blake2bState, - __global const uint32_t *heap0, - __global bsizes *nslots) -{ - uint8_t hash[HASHOUT]; - blake2b_state state; - // equi::htlayout htl(eq, 0); - htlayout htl = htlayout_create_2(0); - const uint32_t hashbytes = hashsize(0); - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - for (uint32_t block = id; block < NBLOCKS; block += get_global_size(0)) { - state = *blake2bState; - blake2b_gpu_hash(&state, block, hash, HASHOUT); - for (uint32_t i = 0; i < HASHESPERBLAKE; i++) { - const uint8_t *ph = hash + i * WN/8; -#if BUCKBITS == 16 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 8) | ph[1]; -#ifdef XINTREE - const uint32_t xhash = ph[2] >> 4; -#endif -#elif BUCKBITS == 14 && RESTBITS == 6 - const uint32_t bucketid = ((uint32_t)ph[0] << 6) | ph[1] >> 2; -#elif BUCKBITS == 12 && RESTBITS == 8 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; -#elif BUCKBITS == 20 && RESTBITS == 4 - const uint32_t bucketid = ((((uint32_t)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; -#ifdef XINTREE - const uint32_t xhash = ph[2] & 0xf; -#endif -#elif BUCKBITS == 12 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; - const uint32_t xhash = ph[1] & 0xf; -#else -#error not implemented -#endif - const uint32_t slot = atomic_inc(&nslots[0][bucketid]); - if (slot >= NSLOTS) - continue; - tree leaf; - tree_setindex(&leaf, block*HASHESPERBLAKE+i); -#ifdef XINTREE - tree_setxhash(&leaf, xhash); -#endif - __global slot0 *s = &tree0_ptr(heap0, 0)[bucketid][slot]; - s->attr = leaf; - - // memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); - for (unsigned i = 0; i < hashbytes; i++) - ((__global uint8_t*)s->hash->bytes+htl.nextbo)[i] = ((uint8_t*)(ph+WN/8-hashbytes))[i]; - } - } -} - -__kernel void digitOdd(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?! - __global slot0 *buck = tree0_ptr(heap0, (r-1)/2)[bucketid]; // optimize by updating previous buck?! - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); // optimize by putting bucketsize with block?! - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (xhash = bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; - xhash &= 0xf; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 2 - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 6; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot1 *xs = &htl.hta.trees1[r/2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i = htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -__kernel void digitEven(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - __global slot1 *buck = tree1_ptr(heap1, (r-1)/2)[bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 6) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 2; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot0 *xs = &htl.hta.trees0[r/2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i=htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -#ifdef UNROLL - -__kernel void digit_1(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - htlayout htl = htlayout_create_2(1); - collisiondata cd; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 0, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[0][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 0)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - xs->hash[4].word = pslot0->hash[5].word ^ pslot1->hash[5].word; - } - } - } -} -__kernel void digit_2(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(2); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[0][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); - // __global slot0 *xs = &htl.hta.trees0[1][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[4].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_3(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(3); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[1][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 2, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[1][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_4(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(4); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[1][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 3, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_5(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(5); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[2][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 4, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_6(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(6); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[2][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 5, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[3][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - } - } - } -} -__kernel void digit_7(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(7); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[3][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 6, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[3][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -__kernel void digit_8(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(8); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[3][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 7, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[4][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 4)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -#endif //UNROLL - -__kernel void digitK(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots, - __global proof *sols, - __global uint32_t *nsols) { - collisiondata cd; - htlayout htl = htlayout_create_2(WK); - const uint32_t id = get_global_id(0); - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, (WK-1)/2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, WK-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) // assume WK odd - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) { - tree xort = tree_create3(bucketid, s0, s1); - equi_candidate(heap0, heap1, sols, nsols, xort); - } - } - } - } -} diff --git a/3rdparty/amd_bins_windows/equiw200k9.bin b/3rdparty/amd_bins_windows/equiw200k9.bin deleted file mode 100644 index 868842f93ffdc1c8f24b35e1cddb9fb376ce1696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 889324 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≫@IPUR78%N)#h8feP)89J%BXF1>-U|SSn8Iht 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 P?Prld{NLWz^dJ3S@{jt0 diff --git a/3rdparty/amd_bins_windows/zcash/gpu/blake2bcl.h b/3rdparty/amd_bins_windows/zcash/gpu/blake2bcl.h deleted file mode 100644 index 13cad965c..000000000 --- a/3rdparty/amd_bins_windows/zcash/gpu/blake2bcl.h +++ /dev/null @@ -1,150 +0,0 @@ -// Blake2-B CUDA Implementation -// tpruvot@github July 2016 -// permission granted to use under MIT license -// modified for use in Zcash by John Tromp September 2016 - -/** - * uint2 direct ops by c++ operator definitions - */ - -// static __device__ __forceinline__ uint2 operator^ (uint2 a, uint2 b) { -// return make_uint2(a.x ^ b.x, a.y ^ b.y); -// } - -// uint2 ROR/ROL methods -uint2 ROR2(const uint2 a, const int offset) { - uint2 result; - if (!offset) - result = a; - else if (offset < 32) { - result.y = ((a.y >> offset) | (a.x << (32 - offset))); - result.x = ((a.x >> offset) | (a.y << (32 - offset))); - } else if (offset == 32) { - result.y = a.x; - result.x = a.y; - } else { - result.y = ((a.x >> (offset - 32)) | (a.y << (64 - offset))); - result.x = ((a.y >> (offset - 32)) | (a.x << (64 - offset))); - } - return result; -} - -uint2 SWAPUINT2(uint2 value) { - uint2 result; - result.x = value.y; - result.y = value.x; - return result; -// return make_uint2(value.y, value.x); -} - -#define ROR24(u) ROR2(u,24) -#define ROR16(u) ROR2(u,16) - -__constant int8_t blake2b_sigma[12][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } , - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } -}; - -void G(const int32_t r, const int32_t i, uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d, uint64_t const m[16]) { - *a += *b + m[ blake2b_sigma[r][2*i] ]; - ((uint2*)d)[0] = SWAPUINT2( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR24( ((uint2*)b)[0] ^ ((uint2*)c)[0] ); - *a += *b + m[ blake2b_sigma[r][2*i+1] ]; - ((uint2*)d)[0] = ROR16( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR2( ((uint2*)b)[0] ^ ((uint2*)c)[0], 63U); -} - -#define ROUND(r) \ - G(r, 0, &v[0], &v[4], &v[ 8], &v[12], m); \ - G(r, 1, &v[1], &v[5], &v[ 9], &v[13], m); \ - G(r, 2, &v[2], &v[6], &v[10], &v[14], m); \ - G(r, 3, &v[3], &v[7], &v[11], &v[15], m); \ - G(r, 4, &v[0], &v[5], &v[10], &v[15], m); \ - G(r, 5, &v[1], &v[6], &v[11], &v[12], m); \ - G(r, 6, &v[2], &v[7], &v[ 8], &v[13], m); \ - G(r, 7, &v[3], &v[4], &v[ 9], &v[14], m); - -void blake2b_gpu_hash(blake2b_state *state, uint32_t idx, uint8_t *hash, uint32_t outlen) { - const uint32_t leb = idx; - *(uint32_t*)(state->buf + state->buflen) = leb; - state->buflen += 4; - state->counter += state->buflen; - for (unsigned i = 0; i < BLAKE2B_BLOCKBYTES - state->buflen; i++) - state->buf[i+state->buflen] = 0; - - uint64_t *d_data = (uint64_t *)state->buf; - uint64_t m[16]; - - m[0] = d_data[0]; - m[1] = d_data[1]; - m[2] = d_data[2]; - m[3] = d_data[3]; - m[4] = d_data[4]; - m[5] = d_data[5]; - m[6] = d_data[6]; - m[7] = d_data[7]; - m[8] = d_data[8]; - m[9] = d_data[9]; - m[10] = d_data[10]; - m[11] = d_data[11]; - m[12] = d_data[12]; - m[13] = d_data[13]; - m[14] = d_data[14]; - m[15] = d_data[15]; - - uint64_t v[16]; - - v[0] = state->h[0]; - v[1] = state->h[1]; - v[2] = state->h[2]; - v[3] = state->h[3]; - v[4] = state->h[4]; - v[5] = state->h[5]; - v[6] = state->h[6]; - v[7] = state->h[7]; - v[8] = 0x6a09e667f3bcc908; - v[9] = 0xbb67ae8584caa73b; - v[10] = 0x3c6ef372fe94f82b; - v[11] = 0xa54ff53a5f1d36f1; - v[12] = 0x510e527fade682d1 ^ state->counter; - v[13] = 0x9b05688c2b3e6c1f; - v[14] = 0x1f83d9abfb41bd6b ^ 0xffffffffffffffff; - v[15] = 0x5be0cd19137e2179; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - ROUND( 10 ); - ROUND( 11 ); - - state->h[0] ^= v[0] ^ v[ 8]; - state->h[1] ^= v[1] ^ v[ 9]; - state->h[2] ^= v[2] ^ v[10]; - state->h[3] ^= v[3] ^ v[11]; - state->h[4] ^= v[4] ^ v[12]; - state->h[5] ^= v[5] ^ v[13]; - state->h[6] ^= v[6] ^ v[14]; - state->h[7] ^= v[7] ^ v[15]; - - for (unsigned i = 0; i < outlen; i++) - hash[i] = ((uint8_t*)state->h)[i]; -} diff --git a/3rdparty/amd_bins_windows/zcash/gpu/common.h b/3rdparty/amd_bins_windows/zcash/gpu/common.h deleted file mode 100644 index 22ba9548e..000000000 --- a/3rdparty/amd_bins_windows/zcash/gpu/common.h +++ /dev/null @@ -1,156 +0,0 @@ -#if defined(__OPENCL_HOST__) -#define __global -#include "../blake2.h" -#else -typedef char int8_t; -typedef uchar uint8_t; -typedef short int16_t; -typedef ushort uint16_t; -typedef int int32_t; -typedef uint uint32_t; -typedef long int64_t; -typedef ulong uint64_t; - -#if defined(_MSC_VER) -#define ALIGN(x) __declspec(align(x)) -#else -#define ALIGN(x) __attribute__ ((__aligned__(x))) -#endif - -enum blake2b_constant -{ - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 -}; - -#pragma pack(push, 1) -ALIGN( 64 ) typedef struct __blake2b_state { - uint64_t h[8]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - uint16_t counter; - uint8_t buflen; - uint8_t lastblock; -} blake2b_state; -#pragma pack(pop) -#endif - -#define COLLISION_BIT_LENGTH (WN / (WK+1)) -#define COLLISION_BYTE_LENGTH ((COLLISION_BIT_LENGTH+7)/8) -#define FINAL_FULL_WIDTH (2*COLLISION_BYTE_LENGTH+sizeof(uint32_t)*(1 << (WK))) - - -#define NDIGITS (WK+1) -#define DIGITBITS (WN/(NDIGITS)) -#define PROOFSIZE (1u< 64 -#error cant use XBITMAP with more than 64 slots -#endif - uint64_t xhashmap[NRESTS]; - uint64_t xmap; -#else - xslot nxhashslots[NRESTS]; - xslot xhashslots[NRESTS][XFULL]; - xslot *xx; - uint32_t n0; - uint32_t n1; -#endif - uint32_t s0; -} collisiondata; - - -typedef struct equi { - blake2b_state blake_ctx; - htalloc hta; - __global bsizes *nslots; - __global proof *sols; - uint32_t nsols; - uint32_t nthreads; -} equi; diff --git a/3rdparty/amd_bins_windows/zcash/gpu/equihash.cl b/3rdparty/amd_bins_windows/zcash/gpu/equihash.cl deleted file mode 100644 index 213a8e4d6..000000000 --- a/3rdparty/amd_bins_windows/zcash/gpu/equihash.cl +++ /dev/null @@ -1,1038 +0,0 @@ -#include "common.h" - -#include "blake2bcl.h" - -#define tree0_ptr(heap, r) ((__global bucket0 *)(heap + r)) -#define tree1_ptr(heap, r) ((__global bucket1 *)(heap + r)) - -uint32_t tree_bucket(tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS) & SLOTMASK; -} - -uint32_t tree_slotid1(tree t) -{ - const uint32_t slotMask = ((1u<> (BUCKBITS+SLOTBITS)) & SLOTMASK; -} - -uint32_t tree_xhash(tree t) -{ - return t >> (2*SLOTBITS + BUCKBITS); -} - -uint32_t tree_getindex(const tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS); -} - -void tree_setindex(tree *t, uint32_t idx) -{ - const uint32_t bucketMask = ((1u<> SLOTBITS); - (*t) |= ((idx & slotMask) << BUCKBITS); -} - -void tree_setxhash(tree *t, uint32_t xhash) -{ - const uint32_t xhashMask = ((1u << RESTBITS)-1); - (*t) &= ~(xhashMask << (2*SLOTBITS + BUCKBITS)); - (*t) |= (xhash << (2*SLOTBITS + BUCKBITS)); -} - -tree tree_create3(uint32_t bucketId, uint32_t s0, uint32_t s1) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)); -} - -tree tree_create4(uint32_t bucketId, uint32_t s0, uint32_t s1, uint32_t xhash) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)) | (xhash << (2*SLOTBITS+BUCKBITS));; -} - -// size (in bytes) of hash in round 0 <= r < WK -uint32_t hashsize(const uint32_t r) -{ -#ifdef XINTREE - const uint32_t hashbits = WN - (r+1) * DIGITBITS; -#else - const uint32_t hashbits = WN - (r+1) * DIGITBITS + RESTBITS; -#endif - return (hashbits + 7) / 8; -} - -uint32_t hashwords(uint32_t bytes) -{ - return (bytes + 3) / 4; -} - -htlayout htlayout_create_2(uint32_t r) -{ - htlayout R; - R.prevhashunits = 0; - R.dunits = 0; - - uint32_t nexthashbytes = hashsize(r); - R.nexthashunits = hashwords(nexthashbytes); - - R.prevbo = 0; - R.nextbo = R.nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3 - if (r) { - uint32_t prevhashbytes = hashsize(r-1); - R.prevhashunits = hashwords(prevhashbytes); - R.prevbo = R.prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3 - R.dunits = R.prevhashunits - R.nexthashunits; - } - - return R; -} - -uint32_t htlayout_getxhash0(uint32_t prevbo, __global const slot0 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] >> 4; -#elif WN == 200 && RESTBITS == 8 - return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return (pslot->hash->bytes[prevbo] & 0x3) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#else -#error non implemented -#endif -} - -uint32_t htlayout_getxhash1(uint32_t prevbo, __global const slot1 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 8 - return pslot->hash->bytes[prevbo]; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return pslot->hash->bytes[prevbo] & 0x3f; -#else -#error non implemented -#endif -} - -bool htlayout_equal(uint32_t prevhashunits, __global const hashunit *hash0, __global const hashunit *hash1) -{ - return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; -} - -void collisiondata_clear(collisiondata *data) -{ -#ifdef XBITMAP - // memset(xhashmap, 0, NRESTS * sizeof(u64)); - for (unsigned i = 0; i < NRESTS; i++) - data->xhashmap[i] = 0; -#else - // memset(nxhashslots, 0, NRESTS * sizeof(xslot)); - for (unsigned i = 0; i < NRESTS; i++) - data->nxhashslots[i] = 0; -#endif -} - -bool collisiondata_addslot(collisiondata *data, uint32_t s1, uint32_t xh) -{ -#ifdef XBITMAP - data->xmap = data->xhashmap[xh]; - data->xhashmap[xh] |= (uint64_t)1 << s1; - data->s0 = ~0; - return true; -#else - data->n1 = (uint32_t)data->nxhashslots[xh]++; - if (data->n1 >= XFULL) - return false; - data->xx = data->xhashslots[xh]; - data->xx[data->n1] = s1; - data->n0 = 0; - return true; -#endif -} - -bool collisiondata_nextcollision(collisiondata *data) -{ -#ifdef XBITMAP - return data->xmap != 0; -#else - return data->n0 < data->n1; -#endif -} - -uint64_t __ffsll(uint64_t x) -{ - return x ? (64 - clz(x & -x)) : 0; -} - -uint32_t collisiondata_slot(collisiondata *data) { -#ifdef XBITMAP - const uint32_t ffs = __ffsll(xmap); - data->s0 += ffs; - data->xmap >>= ffs; - return data->s0; -#else - return (uint32_t)data->xx[data->n0++]; -#endif -} - -uint32_t equi_getnslots(__global bsizes *nslots, const uint32_t r, const uint32_t bid) -{ - __global uint32_t *nslot = &nslots[r&1][bid]; - const uint32_t n = min(*nslot, NSLOTS); - *nslot = 0; - return n; -} - -void equi_orderindices(__global uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - -void local_orderindices(uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - - -void equi_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - equi_orderindices(indices, size); -} - -void equi_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - equi_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - equi_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - equi_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - equi_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - equi_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - equi_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - equi_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - equi_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void local_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - local_orderindices(indices, size); -} - -void local_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - local_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - local_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - local_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - local_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - local_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - local_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - local_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - local_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -// proper dupe test is a little costly on GPU, so allow false negatives -bool equi_probdupe(uint32_t *prf) { - unsigned short susp[PROOFSIZE]; - for (unsigned i = 0; i < PROOFSIZE; i++) - susp[i] = 0xFFFF; - - for (unsigned i = 0; i < PROOFSIZE; i++) { - uint32_t bin = prf[i] & (PROOFSIZE-1); - unsigned short msb = prf[i] >> WK; - if (msb == susp[bin]) - return true; - susp[bin] = msb; - } - - return false; -} - -void equi_candidate(__global uint32_t *heap0, - __global uint32_t *heap1, - __global proof *sols, - __global uint32_t *nsols, - const tree t) -{ - proof prf; -#if WK==9 - local_listindices9(heap0, heap1, t, (uint32_t*)&prf); -#elif WK==5 - local_listindices5(heap0, heap1, t, (uint32_t*)&prf); -#else -#error not implemented -#endif - if (equi_probdupe(prf)) - return; - uint32_t soli = atomic_inc(nsols); - if (soli < MAXSOLS) -#if WK==9 - equi_listindices9(heap0, heap1, t, sols[soli]); -#elif WK==5 - equi_listindices5(heap0, heap1, t, sols[soli]); -#else -#error not implemented -#endif -} - - -__kernel void digitH(__global blake2b_state *blake2bState, - __global const uint32_t *heap0, - __global bsizes *nslots) -{ - uint8_t hash[HASHOUT]; - blake2b_state state; - // equi::htlayout htl(eq, 0); - htlayout htl = htlayout_create_2(0); - const uint32_t hashbytes = hashsize(0); - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - for (uint32_t block = id; block < NBLOCKS; block += get_global_size(0)) { - state = *blake2bState; - blake2b_gpu_hash(&state, block, hash, HASHOUT); - for (uint32_t i = 0; i < HASHESPERBLAKE; i++) { - const uint8_t *ph = hash + i * WN/8; -#if BUCKBITS == 16 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 8) | ph[1]; -#ifdef XINTREE - const uint32_t xhash = ph[2] >> 4; -#endif -#elif BUCKBITS == 14 && RESTBITS == 6 - const uint32_t bucketid = ((uint32_t)ph[0] << 6) | ph[1] >> 2; -#elif BUCKBITS == 12 && RESTBITS == 8 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; -#elif BUCKBITS == 20 && RESTBITS == 4 - const uint32_t bucketid = ((((uint32_t)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; -#ifdef XINTREE - const uint32_t xhash = ph[2] & 0xf; -#endif -#elif BUCKBITS == 12 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; - const uint32_t xhash = ph[1] & 0xf; -#else -#error not implemented -#endif - const uint32_t slot = atomic_inc(&nslots[0][bucketid]); - if (slot >= NSLOTS) - continue; - tree leaf; - tree_setindex(&leaf, block*HASHESPERBLAKE+i); -#ifdef XINTREE - tree_setxhash(&leaf, xhash); -#endif - __global slot0 *s = &tree0_ptr(heap0, 0)[bucketid][slot]; - s->attr = leaf; - - // memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); - for (unsigned i = 0; i < hashbytes; i++) - ((__global uint8_t*)s->hash->bytes+htl.nextbo)[i] = ((uint8_t*)(ph+WN/8-hashbytes))[i]; - } - } -} - -__kernel void digitOdd(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?! - __global slot0 *buck = tree0_ptr(heap0, (r-1)/2)[bucketid]; // optimize by updating previous buck?! - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); // optimize by putting bucketsize with block?! - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (xhash = bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; - xhash &= 0xf; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 2 - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 6; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot1 *xs = &htl.hta.trees1[r/2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i = htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -__kernel void digitEven(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - __global slot1 *buck = tree1_ptr(heap1, (r-1)/2)[bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 6) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 2; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot0 *xs = &htl.hta.trees0[r/2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i=htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -#ifdef UNROLL - -__kernel void digit_1(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - htlayout htl = htlayout_create_2(1); - collisiondata cd; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 0, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[0][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 0)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - xs->hash[4].word = pslot0->hash[5].word ^ pslot1->hash[5].word; - } - } - } -} -__kernel void digit_2(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(2); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[0][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); - // __global slot0 *xs = &htl.hta.trees0[1][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[4].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_3(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(3); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[1][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 2, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[1][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_4(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(4); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[1][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 3, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_5(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(5); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[2][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 4, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_6(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(6); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[2][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 5, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[3][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - } - } - } -} -__kernel void digit_7(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(7); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[3][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 6, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[3][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -__kernel void digit_8(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(8); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[3][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 7, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[4][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 4)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -#endif //UNROLL - -__kernel void digitK(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots, - __global proof *sols, - __global uint32_t *nsols) { - collisiondata cd; - htlayout htl = htlayout_create_2(WK); - const uint32_t id = get_global_id(0); - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, (WK-1)/2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, WK-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) // assume WK odd - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) { - tree xort = tree_create3(bucketid, s0, s1); - equi_candidate(heap0, heap1, sols, nsols, xort); - } - } - } - } -} diff --git a/3rdparty/amd_silentarmy_kernels/zcash/gpu/kernel.cl b/3rdparty/amd_silentarmy_kernels/zcash/gpu/kernel.cl deleted file mode 100644 index 0fdc74d83..000000000 --- a/3rdparty/amd_silentarmy_kernels/zcash/gpu/kernel.cl +++ /dev/null @@ -1,555 +0,0 @@ -# 1 "input.cl" -# 1 "" -# 1 "" -# 1 "/usr/include/stdc-predef.h" 1 3 4 -# 1 "" 2 -# 1 "input.cl" -# 1 "param.h" 1 -# 60 "param.h" -typedef struct sols_s -{ - uint nr; - uint likely_invalids; - uchar valid[2000]; - uint values[2000][(1 << 9)]; -} sols_t; -# 2 "input.cl" 2 -# 36 "input.cl" -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - - - - -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32) = 0; -} -# 80 "input.cl" -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; -# 111 "input.cl" - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xf00000) >> 4); - else - row = ((xi0 & 0xf0000) >> 0) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); - - - - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32; - cnt = atomic_inc((__global uint *)p); - if (cnt >= ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)) - return 1; - p += cnt * 32 + (8 + ((round) / 2) * 4); - - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - - *(__global uint *)(p + 0) = xi0; - } - return 0; -} -# 188 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = (1 << (200 / (9 + 1))) / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - - - ulong word1 = (ulong)input << 32; - - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - - v[12] ^= 140 + 4 ; - - v[14] ^= -1; - - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + word1); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + word1); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + word1); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - - - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - - - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); - - - - - input++; - } - - - - -} -# 415 "input.cl" -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; - - - - if (round == 1 || round == 2) - { - - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - if (round == 2) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8) | (xi2 << (64 - 8)); - xi2 = (xi2 >> 8); - } - } - else if (round == 3) - { - - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - if (round == 4) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 6) - { - - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - if (round == 6) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 7 || round == 8) - { - - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - if (round == 8) - { - - xi0 = (xi0 >> 8); - } - } - - - if (!xi0 && !xi1) - return 0; - - - - return ht_store(round, ht_dst, ((row << 12) | ((slot_b & 0x3f) << 6) | (slot_a & 0x3f)), - xi0, xi1, xi2, 0); -} - - - - - -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)]; - uchar mask; - uint i, j; - - - ushort collisions[((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 3]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - - xi_offset = (8 + ((round - 1) / 2) * 4); -# 524 "input.cl" - mask = 0; - - - - p = (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)); - p += xi_offset; - for (i = 0; i < cnt; i++, p += 32) - first_words[i] = *(__global uchar *)p; - - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else - - - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); - - - - } - - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + i * 32 + xi_offset); - b = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + j * 32 + xi_offset); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - if (round < 8) - - *(__global uint *)(ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32) = 0; - - - - -} -# 585 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round1(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(1, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round2(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(2, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round3(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(3, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round4(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(4, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round5(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(5, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round6(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(6, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round7(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(7, ht_src, ht_dst, debug); } - - -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round8(__global char *ht_src, __global char *ht_dst, - __global uint *debug, __global sols_t *sols) -{ - uint tid = get_global_id(0); - equihash_round(8, ht_src, ht_dst, debug); - if (!tid) - sols->nr = sols->likely_invalids = 0; -} - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + - slot * 32 + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = (8 + ((round) / 2) * 4); - do - { - ins[j] = expand_ref(ht, xi_offset, - (ins[i] >> 12), ((ins[i] >> 6) & 0x3f)); - ins[j - 1] = expand_ref(ht, xi_offset, - (ins[i] >> 12), (ins[i] & 0x3f)); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - - - - -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= 2000) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = 9 - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - - - - -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (9 - 1) % 2; - uint cnt; - uint xi_offset = (8 + ((9 - 1) / 2) * 4); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - - - ulong collisions[5]; - uint coll; - - - - uint mask = 0xffffff; - - - - a = htabs[ht_i] + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)); - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += 32) - for (j = i + 1, b = a + 32; j < cnt; j++, b += 32) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalids); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/3rdparty/kernel_R92xx_linux_14.4/equiw200k9.bin b/3rdparty/kernel_R92xx_linux_14.4/equiw200k9.bin deleted file mode 100644 index 45785dc4e67959ee6b0fff18f899efbacec76036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 434628 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

0J>$zwejKi`{7sc|cQBZqE0UU+>R77|q$DDh%pl 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 diff --git a/3rdparty/kernel_RX4xx_windows_16.7/equiw200k9.bin b/3rdparty/kernel_RX4xx_windows_16.7/equiw200k9.bin deleted file mode 100644 index 868842f93ffdc1c8f24b35e1cddb9fb376ce1696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 889324 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≫@IPUR78%N)#h8feP)89J%BXF1>-U|SSn8Iht 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 P?Prld{NLWz^dJ3S@{jt0 diff --git a/3rdparty/silentarmy/16_kernel.cl b/3rdparty/silentarmy/16_kernel.cl deleted file mode 100644 index b7d23e4bd..000000000 --- a/3rdparty/silentarmy/16_kernel.cl +++ /dev/null @@ -1,526 +0,0 @@ -# 1 "input.cl" -# 1 "" -# 1 "" -# 1 "/usr/include/stdc-predef.h" 1 3 4 -# 1 "" 2 -# 1 "input.cl" -# 1 "param.h" 1 -# 60 "param.h" -typedef struct sols_s -{ - uint nr; - uint likely_invalidss; - uchar valid[2000]; - uint values[2000][(1 << 9)]; -} sols_t; -# 2 "input.cl" 2 -# 35 "input.cl" -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - - - - -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32) = 0; -} -# 79 "input.cl" -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; - - if (!(round % 2)) - row = (xi0 & 0xffff); - else - - - - - row = ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -# 119 "input.cl" - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32; - cnt = atomic_inc((__global uint *)p); - if (cnt >= ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3)) - return 1; - p += cnt * 32 + (8 + ((round) / 2) * 4); - - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - - *(__global uint *)(p + 0) = xi0; - } - return 0; -} -# 187 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = (1 << (200 / (9 + 1))) / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - - - ulong word1 = (ulong)input << 32; - - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - - v[12] ^= 140 + 4 ; - - v[14] ^= -1; - - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + word1); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + word1); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + word1); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - - - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - - - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); - - - - - input++; - } - - - - -} -# 409 "input.cl" -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; - - - - if (round == 1 || round == 2) - { - - - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - } - else if (round == 3) - { - - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - } - else if (round == 6) - { - - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - } - else if (round == 7 || round == 8) - { - - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - } - - - if (!xi0 && !xi1) - return 0; - - - - return ht_store(round, ht_dst, ((row << 16) | ((slot_b & 0xff) << 8) | (slot_a & 0xff)), - xi0, xi1, xi2, 0); -} - - - - - -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[((1 << (((200 / (9 + 1)) + 1) - 16)) * 3)]; - uchar mask; - uint i, j; - - - ushort collisions[((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 2]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - - xi_offset = (8 + ((round - 1) / 2) * 4); - - - mask = ((!(round % 2)) ? 0x0f : 0xf0); -# 499 "input.cl" - p = (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 16)) * 3)); - p += xi_offset; - for (i = 0; i < cnt; i++, p += 32) - first_words[i] = *(__global uchar *)p; - - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else - - - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); - - - - } - - uint adj = (!(round % 2)) ? 1 : 0; - - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32 + i * 32 + xi_offset - + adj); - b = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32 + j * 32 + xi_offset - + adj); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - - - - -} -# 557 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round1(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(1, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round2(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(2, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round3(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(3, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round4(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(4, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round5(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(5, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round6(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(6, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round7(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(7, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round8(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(8, ht_src, ht_dst, debug); } - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32 + - slot * 32 + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = (8 + ((round) / 2) * 4); - do - { - ins[j] = expand_ref(ht, xi_offset, - (ins[i] >> 16), ((ins[i] >> 8) & 0xff)); - ins[j - 1] = expand_ref(ht, xi_offset, - (ins[i] >> 16), (ins[i] & 0xff)); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - - - - -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= 2000) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = 9 - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - - - - -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (9 - 1) % 2; - uint cnt; - uint xi_offset = (8 + ((9 - 1) / 2) * 4); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - - - ulong collisions[5]; - uint coll; - - - - uint mask = 0xffffff; - - - - if (tid == 0) - sols->nr = sols->likely_invalidss = 0; - mem_fence(CLK_GLOBAL_MEM_FENCE); - a = htabs[ht_i] + tid * ((1 << (((200 / (9 + 1)) + 1) - 16)) * 3) * 32; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 16)) * 3)); - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += 32) - for (j = i + 1, b = a + 32; j < cnt; j++, b += 32) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalidss); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/3rdparty/silentarmy/19_kernel.cl b/3rdparty/silentarmy/19_kernel.cl deleted file mode 100644 index fd0f29a7a..000000000 --- a/3rdparty/silentarmy/19_kernel.cl +++ /dev/null @@ -1,531 +0,0 @@ -# 1 "input.cl" -# 1 "" -# 1 "" -# 1 "/usr/include/stdc-predef.h" 1 3 4 -# 1 "" 2 -# 1 "input.cl" -# 1 "param.h" 1 -# 60 "param.h" -typedef struct sols_s -{ - uint nr; - uint likely_invalidss; - uchar valid[2000]; - uint values[2000][(1 << 9)]; -} sols_t; -# 2 "input.cl" 2 -# 35 "input.cl" -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - - - - -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32) = 0; -} -# 79 "input.cl" -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; -# 103 "input.cl" - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xe00000) >> 5); - else - row = ((xi0 & 0xe0000) >> 1) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -# 119 "input.cl" - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32; - cnt = atomic_inc((__global uint *)p); - if (cnt >= ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9)) - return 1; - p += cnt * 32 + (8 + ((round) / 2) * 4); - - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - - *(__global uint *)(p + 0) = xi0; - } - return 0; -} -# 187 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = (1 << (200 / (9 + 1))) / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - - - ulong word1 = (ulong)input << 32; - - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - - v[12] ^= 140 + 4 ; - - v[14] ^= -1; - - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + word1); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + word1); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + word1); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - - - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - - - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); - - - - - input++; - } - - - - -} -# 409 "input.cl" -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; - - - - if (round == 1 || round == 2) - { - - - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - } - else if (round == 3) - { - - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - } - else if (round == 6) - { - - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - } - else if (round == 7 || round == 8) - { - - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - } - - - if (!xi0 && !xi1) - return 0; - - - - return ht_store(round, ht_dst, ((row << 13) | ((slot_b & 0x3f) << 6) | (slot_a & 0x3f)), - xi0, xi1, xi2, 0); -} - - - - - -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[((1 << (((200 / (9 + 1)) + 1) - 19)) * 9)]; - uchar mask; - uint i, j; - - - ushort collisions[((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 2]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - - xi_offset = (8 + ((round - 1) / 2) * 4); - - - - - - - mask = ((!(round % 2)) ? 0x01 : 0x10); - - - - - - p = (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 19)) * 9)); - p += xi_offset; - for (i = 0; i < cnt; i++, p += 32) - first_words[i] = *(__global uchar *)p; - - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else - - - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); - - - - } - - uint adj = (!(round % 2)) ? 1 : 0; - - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32 + i * 32 + xi_offset - + adj); - b = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32 + j * 32 + xi_offset - + adj); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - - - - -} -# 557 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round1(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(1, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round2(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(2, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round3(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(3, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round4(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(4, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round5(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(5, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round6(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(6, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round7(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(7, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round8(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(8, ht_src, ht_dst, debug); } - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32 + - slot * 32 + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = (8 + ((round) / 2) * 4); - do - { - ins[j] = expand_ref(ht, xi_offset, - (ins[i] >> 13), ((ins[i] >> 6) & 0x3f)); - ins[j - 1] = expand_ref(ht, xi_offset, - (ins[i] >> 13), (ins[i] & 0x3f)); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - - - - -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= 2000) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = 9 - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - - - - -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (9 - 1) % 2; - uint cnt; - uint xi_offset = (8 + ((9 - 1) / 2) * 4); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - - - ulong collisions[5]; - uint coll; - - - - uint mask = 0xffffff; - - - - if (tid == 0) - sols->nr = sols->likely_invalidss = 0; - mem_fence(CLK_GLOBAL_MEM_FENCE); - a = htabs[ht_i] + tid * ((1 << (((200 / (9 + 1)) + 1) - 19)) * 9) * 32; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 19)) * 9)); - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += 32) - for (j = i + 1, b = a + 32; j < cnt; j++, b += 32) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalidss); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/3rdparty/silentarmy/kernel.cl b/3rdparty/silentarmy/kernel.cl deleted file mode 100644 index 2099bd049..000000000 --- a/3rdparty/silentarmy/kernel.cl +++ /dev/null @@ -1,526 +0,0 @@ -# 1 "input.cl" -# 1 "" -# 1 "" -# 1 "/usr/include/stdc-predef.h" 1 3 4 -# 1 "" 2 -# 1 "input.cl" -# 1 "param.h" 1 -# 60 "param.h" -typedef struct sols_s -{ - uint nr; - uint likely_invalidss; - uchar valid[2000]; - uint values[2000][(1 << 9)]; -} sols_t; -# 2 "input.cl" 2 -# 35 "input.cl" -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - - - - -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32) = 0; -} -# 79 "input.cl" -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; -# 110 "input.cl" - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xf00000) >> 4); - else - row = ((xi0 & 0xf0000) >> 0) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); - - - - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32; - cnt = atomic_inc((__global uint *)p); - if (cnt >= ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13)) - return 1; - p += cnt * 32 + (8 + ((round) / 2) * 4); - - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - - *(__global uint *)(p + 0) = xi0; - } - return 0; -} -# 187 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = (1 << (200 / (9 + 1))) / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - - - ulong word1 = (ulong)input << 32; - - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - - v[12] ^= 140 + 4 ; - - v[14] ^= -1; - - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + word1); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + word1); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + word1); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - - - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - - - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); - - - - - input++; - } - - - - -} -# 409 "input.cl" -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; - - - - if (round == 1 || round == 2) - { - - - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - } - else if (round == 3) - { - - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - } - else if (round == 6) - { - - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - } - else if (round == 7 || round == 8) - { - - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - } - - - if (!xi0 && !xi1) - return 0; - - - - return ht_store(round, ht_dst, ((row << 12) | ((slot_b & 0x3f) << 6) | (slot_a & 0x3f)), - xi0, xi1, xi2, 0); -} - - - - - -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[((1 << (((200 / (9 + 1)) + 1) - 20)) * 13)]; - uchar mask; - uint i, j; - - - ushort collisions[((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 2]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - - xi_offset = (8 + ((round - 1) / 2) * 4); -# 495 "input.cl" - mask = 0; - - - - p = (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 13)); - p += xi_offset; - for (i = 0; i < cnt; i++, p += 32) - first_words[i] = *(__global uchar *)p; - - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else - - - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); - - - - } - - uint adj = (!(round % 2)) ? 1 : 0; - - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32 + i * 32 + xi_offset - + adj); - b = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32 + j * 32 + xi_offset - + adj); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - - - - -} -# 557 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round1(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(1, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round2(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(2, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round3(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(3, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round4(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(4, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round5(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(5, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round6(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(6, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round7(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(7, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round8(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(8, ht_src, ht_dst, debug); } - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32 + - slot * 32 + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = (8 + ((round) / 2) * 4); - do - { - ins[j] = expand_ref(ht, xi_offset, - (ins[i] >> 12), ((ins[i] >> 6) & 0x3f)); - ins[j - 1] = expand_ref(ht, xi_offset, - (ins[i] >> 12), (ins[i] & 0x3f)); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - - - - -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= 2000) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = 9 - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - - - - -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (9 - 1) % 2; - uint cnt; - uint xi_offset = (8 + ((9 - 1) / 2) * 4); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - - - ulong collisions[5]; - uint coll; - - - - uint mask = 0xffffff; - - - - if (tid == 0) - sols->nr = sols->likely_invalidss = 0; - mem_fence(CLK_GLOBAL_MEM_FENCE); - a = htabs[ht_i] + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 13) * 32; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 13)); - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += 32) - for (j = i + 1, b = a + 32; j < cnt; j++, b += 32) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalidss); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/nheqminer/AvailableSolvers.cpp b/nheqminer/AvailableSolvers.cpp deleted file mode 100644 index cd6d6f3e6..000000000 --- a/nheqminer/AvailableSolvers.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "AvailableSolvers.h" - diff --git a/nheqminer/AvailableSolvers.h b/nheqminer/AvailableSolvers.h index 3adfd9840..07bf23108 100644 --- a/nheqminer/AvailableSolvers.h +++ b/nheqminer/AvailableSolvers.h @@ -21,6 +21,7 @@ CREATE_SOLVER_STUB(cpu_xenoncat, "cpu_xenoncat_STUB") CREATE_SOLVER_STUB(cuda_tromp, "cuda_tromp_STUB") CREATE_SOLVER_STUB(cuda_djezo, "cuda_djezo_STUB") #endif +// OpenCL solvers are fropped replace with new OS solvers #ifdef USE_OCL_XMP #include "../ocl_xpm/ocl_xmp.hpp" #else diff --git a/nheqminer/nheqminer.sln b/nheqminer/nheqminer.sln index 11eece2c6..42fcd0e06 100644 --- a/nheqminer/nheqminer.sln +++ b/nheqminer/nheqminer.sln @@ -5,12 +5,9 @@ VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nheqminer", "nheqminer.vcxproj", "{6FF7D209-05A3-4550-93CC-211D33503719}" ProjectSection(ProjectDependencies) = postProject - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48} = {AB01E715-795A-4089-8DF0-AE6EBDC1AB48} {299E011B-5242-4EDA-B2F2-73C9B48F12FD} = {299E011B-5242-4EDA-B2F2-73C9B48F12FD} {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B} = {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B} {33C2B469-F025-4223-B9B6-E69D42FEA7D6} = {33C2B469-F025-4223-B9B6-E69D42FEA7D6} - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135} = {5DBCE38A-C8D2-4498-A92A-9AF8D5196135} - {5EC9EDEB-8E49-4126-9161-1560683CBC71} = {5EC9EDEB-8E49-4126-9161-1560683CBC71} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cuda_tromp", "..\cuda_tromp\cuda_tromp.vcxproj", "{33C2B469-F025-4223-B9B6-E69D42FEA7D6}" @@ -19,12 +16,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpu_xenoncat", "..\cpu_xeno EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpu_tromp", "..\cpu_tromp\cpu_tromp.vcxproj", "{6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ocl_xpm", "..\ocl_xpm\ocl_xpm.vcxproj", "{5EC9EDEB-8E49-4126-9161-1560683CBC71}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ocl_device_utils", "..\ocl_device_utils\ocl_device_utils.vcxproj", "{5DBCE38A-C8D2-4498-A92A-9AF8D5196135}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ocl_silentarmy", "..\ocl_silentarmy\ocl_silentarmy.vcxproj", "{AB01E715-795A-4089-8DF0-AE6EBDC1AB48}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cuda_djezo", "..\cuda_djezo\cuda_djezo.vcxproj", "{268B10AD-D845-498B-8663-AB8911CA2039}" EndProject Global @@ -73,33 +64,6 @@ Global {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|Win32.ActiveCfg = ReleaseSSE2|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|x64.ActiveCfg = ReleaseSSE2|x64 {6C180164-4DBE-45D7-85E0-7BDFACF3FC7B}.ReleaseSlow|x64.Build.0 = ReleaseSSE2|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|Win32.ActiveCfg = Debug|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|x64.ActiveCfg = Debug|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Debug|x64.Build.0 = Debug|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|Win32.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|x64.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.Release|x64.Build.0 = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|Win32.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|x64.ActiveCfg = Release|x64 - {5EC9EDEB-8E49-4126-9161-1560683CBC71}.ReleaseSlow|x64.Build.0 = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|Win32.ActiveCfg = Debug|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|x64.ActiveCfg = Debug|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Debug|x64.Build.0 = Debug|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|Win32.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|x64.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.Release|x64.Build.0 = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|Win32.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|x64.ActiveCfg = Release|x64 - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135}.ReleaseSlow|x64.Build.0 = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|Win32.ActiveCfg = Debug|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|x64.ActiveCfg = Debug|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Debug|x64.Build.0 = Debug|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|Win32.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|x64.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.Release|x64.Build.0 = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|Win32.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|x64.ActiveCfg = Release|x64 - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48}.ReleaseSlow|x64.Build.0 = Release|x64 {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|Win32.ActiveCfg = Debug|x64 {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|x64.ActiveCfg = Debug|x64 {268B10AD-D845-498B-8663-AB8911CA2039}.Debug|x64.Build.0 = Debug|x64 diff --git a/nheqminer/nheqminer.vcxproj b/nheqminer/nheqminer.vcxproj index 07a56f8cc..8aeb77e1e 100644 --- a/nheqminer/nheqminer.vcxproj +++ b/nheqminer/nheqminer.vcxproj @@ -84,7 +84,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;USE_CPU_TROMP;USE_CPU_XENONCAT;USE_CUDA_TROMP;USE_OCL_XMP;USE_OCL_SILENTARMY;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;USE_CPU_TROMP;USE_CPU_XENONCAT;USE_CUDA_TROMP;%(PreprocessorDefinitions) NotSet -D_WIN32_WINNT=0x0601 %(AdditionalOptions) 4068;4996;4503;4267;4180;4290;4244;4800;4334;4251 @@ -153,7 +153,6 @@ - /bigobj %(AdditionalOptions) diff --git a/nheqminer/nheqminer.vcxproj.filters b/nheqminer/nheqminer.vcxproj.filters index 737fb0d7f..92d63fe46 100644 --- a/nheqminer/nheqminer.vcxproj.filters +++ b/nheqminer/nheqminer.vcxproj.filters @@ -226,9 +226,6 @@ Source Files\stuff - - Source Files - Source Files diff --git a/ocl_device_utils/OpenCLDevice.h b/ocl_device_utils/OpenCLDevice.h deleted file mode 100644 index ab0f5f437..000000000 --- a/ocl_device_utils/OpenCLDevice.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -// This will list OpenCL devices, but AMD will only have aditional BusID -struct OpenCLDevice { - unsigned int DeviceID; - std::string _CL_DEVICE_NAME; - std::string _CL_DEVICE_TYPE; - unsigned long long _CL_DEVICE_GLOBAL_MEM_SIZE; - std::string _CL_DEVICE_VENDOR; - std::string _CL_DEVICE_VERSION; - std::string _CL_DRIVER_VERSION; -}; - diff --git a/ocl_device_utils/cl_ext.hpp b/ocl_device_utils/cl_ext.hpp deleted file mode 100644 index 507598171..000000000 --- a/ocl_device_utils/cl_ext.hpp +++ /dev/null @@ -1,12355 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2008-2013 The Khronos Group Inc. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and/or associated documentation files (the -* "Materials"), to deal in the Materials without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Materials, and to -* permit persons to whom the Materials are furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Materials. -* -* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -******************************************************************************/ - -/*! \file -* -* \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and -* OpenCL 1.2 (rev 15) -* \author Benedict R. Gaster, Laurent Morichetti and Lee Howes -* -* Additions and fixes from: -* Brian Cole, March 3rd 2010 and April 2012 -* Matt Gruenke, April 2012. -* Bruce Merry, February 2013. -* -* \version 1.2.5 -* \date June 2013 -* -* Optional extension support -* -* cl -* cl_ext_device_fission -* #define USE_CL_DEVICE_FISSION -*/ - -/*! \mainpage -* \section intro Introduction -* For many large applications C++ is the language of choice and so it seems -* reasonable to define C++ bindings for OpenCL. -* -* -* The interface is contained with a single C++ header file \em cl.hpp and all -* definitions are contained within the namespace \em cl. There is no additional -* requirement to include \em cl.h and to use either the C++ or original C -* bindings it is enough to simply include \em cl.hpp. -* -* The bindings themselves are lightweight and correspond closely to the -* underlying C API. Using the C++ bindings introduces no additional execution -* overhead. -* -* For detail documentation on the bindings see: -* -* The OpenCL C++ Wrapper API 1.2 (revision 09) -* http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf -* -* \section example Example -* -* The following example shows a general use case for the C++ -* bindings, including support for the optional exception feature and -* also the supplied vector and string classes, see following sections for -* decriptions of these features. -* -* \code -* #define __CL_ENABLE_EXCEPTIONS -* -* #if defined(__APPLE__) || defined(__MACOSX) -* #include -* #else -* #include -* #endif -* #include -* #include -* #include -* -* const char * helloStr = "__kernel void " -* "hello(void) " -* "{ " -* " " -* "} "; -* -* int -* main(void) -* { -* cl_int err = CL_SUCCESS; -* try { -* -* std::vector platforms; -* cl::Platform::get(&platforms); -* if (platforms.size() == 0) { -* std::cout << "Platform size 0\n"; -* return -1; -* } -* -* cl_context_properties properties[] = -* { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; -* cl::Context context(CL_DEVICE_TYPE_CPU, properties); -* -* std::vector devices = context.getInfo(); -* -* cl::Program::Sources source(1, -* std::make_pair(helloStr,strlen(helloStr))); -* cl::Program program_ = cl::Program(context, source); -* program_.build(devices); -* -* cl::Kernel kernel(program_, "hello", &err); -* -* cl::Event event; -* cl::CommandQueue queue(context, devices[0], 0, &err); -* queue.enqueueNDRangeKernel( -* kernel, -* cl::NullRange, -* cl::NDRange(4,4), -* cl::NullRange, -* NULL, -* &event); -* -* event.wait(); -* } -* catch (cl::Error err) { -* std::cerr -* << "ERROR: " -* << err.what() -* << "(" -* << err.err() -* << ")" -* << std::endl; -* } -* -* return EXIT_SUCCESS; -* } -* -* \endcode -* -*/ -#ifndef CL_HPP_ -#define CL_HPP_ - -#ifdef _WIN32 - -#include -#include -#include -#include - -#if defined(__CL_ENABLE_EXCEPTIONS) -#include -#endif // #if defined(__CL_ENABLE_EXCEPTIONS) - -#pragma push_macro("max") -#undef max -#if defined(USE_DX_INTEROP) -#include -#include -#endif -#endif // _WIN32 - -// -#if defined(USE_CL_DEVICE_FISSION) -#include // AMD topology not needed here -#endif - -#if defined(__APPLE__) || defined(__MACOSX) -#include -#include -#include -#else -#include -#include -#endif // !__APPLE__ - -// To avoid accidentally taking ownership of core OpenCL types -// such as cl_kernel constructors are made explicit -// under OpenCL 1.2 -#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS explicit -#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) -#define __CL_EXPLICIT_CONSTRUCTORS -#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - -// Define deprecated prefixes and suffixes to ensure compilation -// in case they are not pre-defined -#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) - -#if !defined(CL_CALLBACK) -#define CL_CALLBACK -#endif //CL_CALLBACK - -#include -#include - -#if !defined(__NO_STD_VECTOR) -#include -#endif - -#if !defined(__NO_STD_STRING) -#include -#endif - -#if defined(__linux__) || defined(__APPLE__) || defined(__MACOSX) -#include - -#include -#include -#endif // __linux__ - -#include - - -/*! \namespace cl -* -* \brief The OpenCL C++ bindings are defined within this namespace. -* -*/ -namespace cl { - - class Memory; - - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __INIT_CL_EXT_FCN_PTR(name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddress(#name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - -#if defined(CL_VERSION_1_2) -#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ - if(!pfn_##name) { \ - pfn_##name = (PFN_##name) \ - clGetExtensionFunctionAddressForPlatform(platform, #name); \ - if(!pfn_##name) { \ - } \ - } -#endif // #if defined(CL_VERSION_1_1) - - class Program; - class Device; - class Context; - class CommandQueue; - class Memory; - class Buffer; - -#if defined(__CL_ENABLE_EXCEPTIONS) - /*! \brief Exception class - * - * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. - */ - class Error : public std::exception - { - private: - cl_int err_; - const char * errStr_; - public: - /*! \brief Create a new CL error exception for a given error code - * and corresponding message. - * - * \param err error code value. - * - * \param errStr a descriptive string that must remain in scope until - * handling of the exception has concluded. If set, it - * will be returned by what(). - */ - Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) - {} - - ~Error() throw() {} - - /*! \brief Get error string associated with exception - * - * \return A memory pointer to the error message string. - */ - virtual const char * what() const throw () - { - if (errStr_ == NULL) { - return "empty"; - } - else { - return errStr_; - } - } - - /*! \brief Get error code associated with exception - * - * \return The error code. - */ - cl_int err(void) const { return err_; } - }; - -#define __ERR_STR(x) #x -#else -#define __ERR_STR(x) NULL -#endif // __CL_ENABLE_EXCEPTIONS - - - namespace detail - { -#if defined(__CL_ENABLE_EXCEPTIONS) - static inline cl_int errHandler( - cl_int err, - const char * errStr = NULL) - { - if (err != CL_SUCCESS) { - throw Error(err, errStr); - } - return err; - } -#else - static inline cl_int errHandler(cl_int err, const char * errStr = NULL) - { - (void)errStr; // suppress unused variable warning - return err; - } -#endif // __CL_ENABLE_EXCEPTIONS - } - - - - //! \cond DOXYGEN_DETAIL -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) -#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) -#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) -#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) -#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) -#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) -#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) -#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) -#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) -#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) -#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) -#if defined(CL_VERSION_1_2) -#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) -#endif // #if defined(CL_VERSION_1_2) -#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) -#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) -#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) -#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) - -#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) -#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) -#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) - -#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) -#define __COPY_ERR __ERR_STR(cl::copy) -#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) -#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) -#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) -#if defined(CL_VERSION_1_2) -#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) -#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) -#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) -#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) - -#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) -#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) -#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) -#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) - -#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) -#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) -#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) -#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) -#if defined(CL_VERSION_1_2) -#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) -#endif // #if defined(CL_VERSION_1_2) -#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) -#if defined(CL_VERSION_1_2) -#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) - -#endif // #if defined(CL_VERSION_1_2) -#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) - -#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) -#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) -#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) -#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) -#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) -#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) -#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) -#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) -#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) -#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) -#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) -#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) -#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) -#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) -#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) -#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) -#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) -#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) -#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) -#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) -#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) -#endif // #if defined(CL_VERSION_1_2) - -#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) -#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) - - -#define __RETAIN_ERR __ERR_STR(Retain Object) -#define __RELEASE_ERR __ERR_STR(Release Object) -#define __FLUSH_ERR __ERR_STR(clFlush) -#define __FINISH_ERR __ERR_STR(clFinish) -#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) - - /** - * CL 1.2 version that uses device fission. - */ -#if defined(CL_VERSION_1_2) -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) -#else -#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) -#endif // #if defined(CL_VERSION_1_2) - - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) -#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) -#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) -#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) -#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) -#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) -#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) -#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) -#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) -#endif // #if defined(CL_VERSION_1_1) - -#endif // __CL_USER_OVERRIDE_ERROR_STRINGS - //! \endcond - - /** - * CL 1.2 marker and barrier commands - */ -#if defined(CL_VERSION_1_2) -#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) -#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) -#endif // #if defined(CL_VERSION_1_2) - -#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) - typedef std::string STRING_CLASS; -#elif !defined(__USE_DEV_STRING) - - /*! \class string - * \brief Simple string class, that provides a limited subset of std::string - * functionality but avoids many of the issues that come with that class. - - * \note Deprecated. Please use std::string as default or - * re-define the string class to match the std::string - * interface by defining STRING_CLASS - */ - class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - private: - ::size_t size_; - char * str_; - public: - //! \brief Constructs an empty string, allocating no memory. - string(void) : size_(0), str_(NULL) - { - } - - /*! \brief Constructs a string populated from an arbitrary value of - * specified size. - * - * An extra '\0' is added, in case none was contained in str. - * - * \param str the initial value of the string instance. Note that '\0' - * characters receive no special treatment. If NULL, - * the string is left empty, with a size of 0. - * - * \param size the number of characters to copy from str. - */ - string(const char * str, ::size_t size) : - size_(size), - str_(NULL) - { - if (size > 0) { - str_ = new char[size_ + 1]; - if (str_ != NULL) { - memcpy(str_, str, size_ * sizeof(char)); - str_[size_] = '\0'; - } - else { - size_ = 0; - } - } - } - - /*! \brief Constructs a string populated from a null-terminated value. - * - * \param str the null-terminated initial value of the string instance. - * If NULL, the string is left empty, with a size of 0. - */ - string(const char * str) : - size_(0), - str_(NULL) - { - if (str) { - size_ = ::strlen(str); - } - if (size_ > 0) { - str_ = new char[size_ + 1]; - if (str_ != NULL) { - memcpy(str_, str, (size_ + 1) * sizeof(char)); - } - } - } - - void resize(::size_t n) - { - if (size_ == n) { - return; - } - if (n == 0) { - if (str_) { - delete[] str_; - } - str_ = NULL; - size_ = 0; - } - else { - char *newString = new char[n + 1]; - int copySize = n; - if (size_ < n) { - copySize = size_; - } - size_ = n; - - if (str_) { - memcpy(newString, str_, (copySize + 1) * sizeof(char)); - } - if (copySize < size_) { - memset(newString + copySize, 0, size_ - copySize); - } - newString[size_] = '\0'; - - delete[] str_; - str_ = newString; - } - } - - const char& operator[] (::size_t pos) const - { - return str_[pos]; - } - - char& operator[] (::size_t pos) - { - return str_[pos]; - } - - /*! \brief Copies the value of another string to this one. - * - * \param rhs the string to copy. - * - * \returns a reference to the modified instance. - */ - string& operator=(const string& rhs) - { - if (this == &rhs) { - return *this; - } - - if (str_ != NULL) { - delete[] str_; - str_ = NULL; - size_ = 0; - } - - if (rhs.size_ == 0 || rhs.str_ == NULL) { - str_ = NULL; - size_ = 0; - } - else { - str_ = new char[rhs.size_ + 1]; - size_ = rhs.size_; - - if (str_ != NULL) { - memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); - } - else { - size_ = 0; - } - } - - return *this; - } - - /*! \brief Constructs a string by copying the value of another instance. - * - * \param rhs the string to copy. - */ - string(const string& rhs) : - size_(0), - str_(NULL) - { - *this = rhs; - } - - //! \brief Destructor - frees memory used to hold the current value. - ~string() - { - delete[] str_; - str_ = NULL; - } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t size(void) const { return size_; } - - //! \brief Queries the length of the string, excluding any added '\0's. - ::size_t length(void) const { return size(); } - - /*! \brief Returns a pointer to the private copy held by this instance, - * or "" if empty/unset. - */ - const char * c_str(void) const { return (str_) ? str_ : ""; } - }; - typedef cl::string STRING_CLASS; -#endif // #elif !defined(__USE_DEV_STRING) - -#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) -#define VECTOR_CLASS std::vector -#elif !defined(__USE_DEV_VECTOR) -#define VECTOR_CLASS cl::vector - -#if !defined(__MAX_DEFAULT_VECTOR_SIZE) -#define __MAX_DEFAULT_VECTOR_SIZE 10 -#endif - - /*! \class vector - * \brief Fixed sized vector implementation that mirroring - * - * \note Deprecated. Please use std::vector as default or - * re-define the vector class to match the std::vector - * interface by defining VECTOR_CLASS - - * \note Not recommended for use with custom objects as - * current implementation will construct N elements - * - * std::vector functionality. - * \brief Fixed sized vector compatible with std::vector. - * - * \note - * This differs from std::vector<> not just in memory allocation, - * but also in terms of when members are constructed, destroyed, - * and assigned instead of being copy constructed. - * - * \param T type of element contained in the vector. - * - * \param N maximum size of the vector. - */ - template - class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - private: - T data_[N]; - unsigned int size_; - - public: - //! \brief Constructs an empty vector with no memory allocated. - vector() : - size_(static_cast(0)) - {} - - //! \brief Deallocates the vector's memory and destroys all of its elements. - ~vector() - { - clear(); - } - - //! \brief Returns the number of elements currently contained. - unsigned int size(void) const - { - return size_; - } - - /*! \brief Empties the vector of all elements. - * \note - * This does not deallocate memory but will invoke destructors - * on contained elements. - */ - void clear() - { - while (!empty()) { - pop_back(); - } - } - - /*! \brief Appends an element after the last valid element. - * Calling this on a vector that has reached capacity will throw an - * exception if exceptions are enabled. - */ - void push_back(const T& x) - { - if (size() < N) { - new (&data_[size_]) T(x); - size_++; - } - else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Removes the last valid element from the vector. - * Calling this on an empty vector will throw an exception - * if exceptions are enabled. - */ - void pop_back(void) - { - if (size_ != 0) { - --size_; - data_[size_].~T(); - } - else { - detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); - } - } - - /*! \brief Constructs with a value copied from another. - * - * \param vec the vector to copy. - */ - vector(const vector& vec) : - size_(vec.size_) - { - if (size_ != 0) { - assign(vec.begin(), vec.end()); - } - } - - /*! \brief Constructs with a specified number of initial elements. - * - * \param size number of initial elements. - * - * \param val value of initial elements. - */ - vector(unsigned int size, const T& val = T()) : - size_(0) - { - for (unsigned int i = 0; i < size; i++) { - push_back(val); - } - } - - /*! \brief Overwrites the current content with that copied from another - * instance. - * - * \param rhs vector to copy. - * - * \returns a reference to this. - */ - vector& operator=(const vector& rhs) - { - if (this == &rhs) { - return *this; - } - - if (rhs.size_ != 0) { - assign(rhs.begin(), rhs.end()); - } - else { - clear(); - } - - return *this; - } - - /*! \brief Tests equality against another instance. - * - * \param vec the vector against which to compare. - */ - bool operator==(vector &vec) - { - if (size() != vec.size()) { - return false; - } - - for (unsigned int i = 0; i < size(); ++i) { - if (operator[](i) != vec[i]) { - return false; - } - } - return true; - } - - //! \brief Conversion operator to T*. - operator T* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const T* () const { return data_; } - - //! \brief Tests whether this instance has any elements. - bool empty(void) const - { - return size_ == 0; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int max_size(void) const - { - return N; - } - - //! \brief Returns the maximum number of elements this instance can hold. - unsigned int capacity() const - { - return N; - } - - /*! \brief Returns a reference to a given element. - * - * \param index which element to access. * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - T& operator[](int index) - { - return data_[index]; - } - - /*! \brief Returns a const reference to a given element. - * - * \param index which element to access. - * - * \note - * The caller is responsible for ensuring index is >= 0 and < size(). - */ - const T& operator[](int index) const - { - return data_[index]; - } - - /*! \brief Assigns elements of the vector based on a source iterator range. - * - * \param start Beginning iterator of source range - * \param end Enditerator of source range - * - * \note - * Will throw an exception if exceptions are enabled and size exceeded. - */ - template - void assign(I start, I end) - { - clear(); - while (start != end) { - push_back(*start); - start++; - } - } - - /*! \class iterator - * \brief Const iterator class for vectors - */ - class iterator - { - private: - const vector *vec_; - int index_; - - /** - * Internal iterator constructor to capture reference - * to the vector it iterates over rather than taking - * the vector by copy. - */ - iterator(const vector &vec, int index) : - vec_(&vec) - { - if (!vec.empty()) { - index_ = index; - } - else { - index_ = -1; - } - } - - public: - iterator(void) : - index_(-1), - vec_(NULL) - { - } - - iterator(const iterator& rhs) : - vec_(rhs.vec_), - index_(rhs.index_) - { - } - - ~iterator(void) {} - - static iterator begin(const cl::vector &vec) - { - iterator i(vec, 0); - - return i; - } - - static iterator end(const cl::vector &vec) - { - iterator i(vec, vec.size()); - - return i; - } - - bool operator==(iterator i) - { - return ((vec_ == i.vec_) && - (index_ == i.index_)); - } - - bool operator!=(iterator i) - { - return (!(*this == i)); - } - - iterator& operator++() - { - ++index_; - return *this; - } - - iterator operator++(int) - { - iterator retVal(*this); - ++index_; - return retVal; - } - - iterator& operator--() - { - --index_; - return *this; - } - - iterator operator--(int) - { - iterator retVal(*this); - --index_; - return retVal; - } - - const T& operator *() const - { - return (*vec_)[index_]; - } - }; - - iterator begin(void) - { - return iterator::begin(*this); - } - - iterator begin(void) const - { - return iterator::begin(*this); - } - - iterator end(void) - { - return iterator::end(*this); - } - - iterator end(void) const - { - return iterator::end(*this); - } - - T& front(void) - { - return data_[0]; - } - - T& back(void) - { - return data_[size_]; - } - - const T& front(void) const - { - return data_[0]; - } - - const T& back(void) const - { - return data_[size_ - 1]; - } - }; -#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) - - - - - - namespace detail { -#define __DEFAULT_NOT_INITIALIZED 1 -#define __DEFAULT_BEING_INITIALIZED 2 -#define __DEFAULT_INITIALIZED 4 - - /* - * Compare and exchange primitives are needed for handling of defaults - */ - inline int compare_exchange(volatile int * dest, int exchange, int comparand) - { -#ifdef _WIN32 - return (int)(InterlockedCompareExchange( - (volatile long*)dest, - (long)exchange, - (long)comparand)); -#elif defined(__APPLE__) || defined(__MACOSX) - return OSAtomicOr32Orig((uint32_t)exchange, (volatile uint32_t*)dest); -#else // !_WIN32 || defined(__APPLE__) || defined(__MACOSX) - return (__sync_val_compare_and_swap( - dest, - comparand, - exchange)); -#endif // !_WIN32 - } - - inline void fence() { _mm_mfence(); } - }; // namespace detail - - - /*! \brief class used to interface between C++ and - * OpenCL C calls that require arrays of size_t values, whose - * size is known statically. - */ - template - class size_t - { - private: - ::size_t data_[N]; - - public: - //! \brief Initialize size_t to all 0s - size_t() - { - for (int i = 0; i < N; ++i) { - data_[i] = 0; - } - } - - ::size_t& operator[](int index) - { - return data_[index]; - } - - const ::size_t& operator[](int index) const - { - return data_[index]; - } - - //! \brief Conversion operator to T*. - operator ::size_t* () { return data_; } - - //! \brief Conversion operator to const T*. - operator const ::size_t* () const { return data_; } - }; - - namespace detail { - - // Generic getInfoHelper. The final parameter is used to guide overload - // resolution: the actual parameter passed is an int, which makes this - // a worse conversion sequence than a specialization that declares the - // parameter as an int. - template - inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) - { - return f(name, sizeof(T), param, NULL); - } - - // Specialized getInfoHelper for VECTOR_CLASS params - template - inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) - { - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - T* value = (T*)alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - param->assign(&value[0], &value[required / sizeof(T)]); - return CL_SUCCESS; - } - - /* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ - template - inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) - { - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - typename T::cl_type * value = (typename T::cl_type *) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t elements = required / sizeof(typename T::cl_type); - param->assign(&value[0], &value[elements]); - for (::size_t i = 0; i < elements; i++) - { - if (value[i] != NULL) - { - err = (*param)[i].retain(); - if (err != CL_SUCCESS) { - return err; - } - } - } - return CL_SUCCESS; - } - - // Specialized for getInfo - template - inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) - { - cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); - - if (err != CL_SUCCESS) { - return err; - } - - return CL_SUCCESS; - } - - // Specialized GetInfoHelper for STRING_CLASS params - template - inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) - { - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - char* value = (char*)alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - *param = value; - return CL_SUCCESS; - } - - // Specialized GetInfoHelper for cl::size_t params - template - inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) - { - ::size_t required; - cl_int err = f(name, 0, NULL, &required); - if (err != CL_SUCCESS) { - return err; - } - - ::size_t* value = (::size_t*) alloca(required); - err = f(name, required, value, NULL); - if (err != CL_SUCCESS) { - return err; - } - - for (int i = 0; i < N; ++i) { - (*param)[i] = value[i]; - } - - return CL_SUCCESS; - } - - template struct ReferenceHandler; - - /* Specialization for reference-counted types. This depends on the - * existence of Wrapper::cl_type, and none of the other types having the - * cl_type member. Note that simplify specifying the parameter as Wrapper - * does not work, because when using a derived type (e.g. Context) the generic - * template will provide a better match. - */ - template - inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) - { - typename T::cl_type value; - cl_int err = f(name, sizeof(value), &value, NULL); - if (err != CL_SUCCESS) { - return err; - } - *param = value; - if (value != NULL) - { - err = param->retain(); - if (err != CL_SUCCESS) { - return err; - } - } - return CL_SUCCESS; - } - -#define __PARAM_NAME_INFO_1_0(F) \ - F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ - F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ - F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ - F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ - F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ - F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ - F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ - F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ - F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ - F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ - F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ - F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ - F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ - F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ - F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ - F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ - F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ - F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ - F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ - \ - F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ - F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ - F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ - \ - F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ - F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ - F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ - F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_uint) \ - \ - F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ - F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ - \ - F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ - F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ - F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ - F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ - F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ - F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ - \ - F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ - F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ - F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ - F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ - F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ - F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ - \ - F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ - F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ - F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ - F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ - F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ - \ - F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ - F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ - F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ - F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ - F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ - F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ - F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ - F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ - \ - F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ - F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ - F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ - F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ - F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ - \ - F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ - F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ - F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ - F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) - -#if defined(CL_VERSION_1_1) -#define __PARAM_NAME_INFO_1_1(F) \ - F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ - F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ - F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ - F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ - F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ - F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ - \ - F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ - F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ - \ - F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ - F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ - \ - F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) -#endif // CL_VERSION_1_1 - - -#if defined(CL_VERSION_1_2) -#define __PARAM_NAME_INFO_1_2(F) \ - F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ - \ - F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ - F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ - \ - F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ - \ - F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ - \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ - F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ - \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ - F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ - F(cl_device_info, CL_DEVICE_TOPOLOGY_AMD, cl_device_topology_amd) \ - F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) -#endif // #if defined(CL_VERSION_1_2) - -#if defined(USE_CL_DEVICE_FISSION) -#define __PARAM_NAME_DEVICE_FISSION(F) \ - F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ - F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ - F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ - F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) -#endif // USE_CL_DEVICE_FISSION - - template - struct param_traits {}; - -#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ -struct token; \ -template<> \ -struct param_traits \ - { \ - enum { value = param_name }; \ - typedef T param_type; \ - }; - - __PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) -#if defined(CL_VERSION_1_1) - __PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 -#if defined(CL_VERSION_1_2) - __PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) -#endif // CL_VERSION_1_1 - -#if defined(USE_CL_DEVICE_FISSION) - __PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); -#endif // USE_CL_DEVICE_FISSION - -#ifdef CL_PLATFORM_ICD_SUFFIX_KHR - __CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) -#endif - -#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) -#endif - -#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) -#endif -#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_WIDTH_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) -#endif -#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) -#endif - -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) -#endif -#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) -#endif -#ifdef CL_DEVICE_WARP_SIZE_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) -#endif -#ifdef CL_DEVICE_GPU_OVERLAP_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) -#endif -#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) -#endif -#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV - __CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) -#endif - - // Convenience functions - - template - inline cl_int - getInfo(Func f, cl_uint name, T* param) - { - return getInfoHelper(f, name, param, 0); - } - - template - struct GetInfoFunctor0 - { - Func f_; const Arg0& arg0_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { - return f_(arg0_, param, size, value, size_ret); - } - }; - - template - struct GetInfoFunctor1 - { - Func f_; const Arg0& arg0_; const Arg1& arg1_; - cl_int operator ()( - cl_uint param, ::size_t size, void* value, ::size_t* size_ret) - { - return f_(arg0_, arg1_, param, size, value, size_ret); - } - }; - - template - inline cl_int - getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) - { - GetInfoFunctor0 f0 = { f, arg0 }; - return getInfoHelper(f0, name, param, 0); - } - - template - inline cl_int - getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) - { - GetInfoFunctor1 f0 = { f, arg0, arg1 }; - return getInfoHelper(f0, name, param, 0); - } - - template - struct ReferenceHandler - { }; - -#if defined(CL_VERSION_1_2) - /** - * OpenCL 1.2 devices do have retain/release. - */ - template <> - struct ReferenceHandler - { - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int retain(cl_device_id device) - { - return ::clRetainDevice(device); - } - /** - * Retain the device. - * \param device A valid device created using createSubDevices - * \return - * CL_SUCCESS if the function executed successfully. - * CL_INVALID_DEVICE if device was not a valid subdevice - * CL_OUT_OF_RESOURCES - * CL_OUT_OF_HOST_MEMORY - */ - static cl_int release(cl_device_id device) - { - return ::clReleaseDevice(device); - } - }; -#else // #if defined(CL_VERSION_1_2) - /** - * OpenCL 1.1 devices do not have retain/release. - */ - template <> - struct ReferenceHandler - { - // cl_device_id does not have retain(). - static cl_int retain(cl_device_id) - { - return CL_SUCCESS; - } - // cl_device_id does not have release(). - static cl_int release(cl_device_id) - { - return CL_SUCCESS; - } - }; -#endif // #if defined(CL_VERSION_1_2) - - template <> - struct ReferenceHandler - { - // cl_platform_id does not have retain(). - static cl_int retain(cl_platform_id) - { - return CL_SUCCESS; - } - // cl_platform_id does not have release(). - static cl_int release(cl_platform_id) - { - return CL_SUCCESS; - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_context context) - { - return ::clRetainContext(context); - } - static cl_int release(cl_context context) - { - return ::clReleaseContext(context); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_command_queue queue) - { - return ::clRetainCommandQueue(queue); - } - static cl_int release(cl_command_queue queue) - { - return ::clReleaseCommandQueue(queue); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_mem memory) - { - return ::clRetainMemObject(memory); - } - static cl_int release(cl_mem memory) - { - return ::clReleaseMemObject(memory); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_sampler sampler) - { - return ::clRetainSampler(sampler); - } - static cl_int release(cl_sampler sampler) - { - return ::clReleaseSampler(sampler); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_program program) - { - return ::clRetainProgram(program); - } - static cl_int release(cl_program program) - { - return ::clReleaseProgram(program); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_kernel kernel) - { - return ::clRetainKernel(kernel); - } - static cl_int release(cl_kernel kernel) - { - return ::clReleaseKernel(kernel); - } - }; - - template <> - struct ReferenceHandler - { - static cl_int retain(cl_event event) - { - return ::clRetainEvent(event); - } - static cl_int release(cl_event event) - { - return ::clReleaseEvent(event); - } - }; - - - // Extracts version number with major in the upper 16 bits, minor in the lower 16 - static cl_uint getVersion(const char *versionInfo) - { - int highVersion = 0; - int lowVersion = 0; - int index = 7; - while (versionInfo[index] != '.') { - highVersion *= 10; - highVersion += versionInfo[index] - '0'; - ++index; - } - ++index; - while (versionInfo[index] != ' ') { - lowVersion *= 10; - lowVersion += versionInfo[index] - '0'; - ++index; - } - return (highVersion << 16) | lowVersion; - } - - static cl_uint getPlatformVersion(cl_platform_id platform) - { - ::size_t size = 0; - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); - char *versionInfo = (char *)alloca(size); - clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); - return getVersion(versionInfo); - } - - static cl_uint getDevicePlatformVersion(cl_device_id device) - { - cl_platform_id platform; - clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); - return getPlatformVersion(platform); - } - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - static cl_uint getContextPlatformVersion(cl_context context) - { - // The platform cannot be queried directly, so we first have to grab a - // device and obtain its context - ::size_t size = 0; - clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); - if (size == 0) - return 0; - cl_device_id *devices = (cl_device_id *)alloca(size); - clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); - return getDevicePlatformVersion(devices[0]); - } -#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - - template - class Wrapper - { - public: - typedef T cl_type; - - protected: - cl_type object_; - - public: - Wrapper() : object_(NULL) { } - - Wrapper(const cl_type &obj) : object_(obj) { } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - - Wrapper& operator = (const Wrapper& rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - return *this; - } - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - - protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - cl_int retain() const - { - return ReferenceHandler::retain(object_); - } - - cl_int release() const - { - return ReferenceHandler::release(object_); - } - }; - - template <> - class Wrapper - { - public: - typedef cl_device_id cl_type; - - protected: - cl_type object_; - bool referenceCountable_; - - static bool isReferenceCountable(cl_device_id device) - { - bool retVal = false; - if (device != NULL) { - int version = getDevicePlatformVersion(device); - if (version > ((1 << 16) + 1)) { - retVal = true; - } - } - return retVal; - } - - public: - Wrapper() : object_(NULL), referenceCountable_(false) - { - } - - Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) - { - referenceCountable_ = isReferenceCountable(obj); - } - - ~Wrapper() - { - if (object_ != NULL) { release(); } - } - - Wrapper(const Wrapper& rhs) - { - object_ = rhs.object_; - referenceCountable_ = isReferenceCountable(object_); - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - } - - Wrapper& operator = (const Wrapper& rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs.object_; - referenceCountable_ = rhs.referenceCountable_; - if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } - return *this; - } - - Wrapper& operator = (const cl_type &rhs) - { - if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } - object_ = rhs; - referenceCountable_ = isReferenceCountable(object_); - return *this; - } - - cl_type operator ()() const { return object_; } - - cl_type& operator ()() { return object_; } - - protected: - template - friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); - - template - friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); - - cl_int retain() const - { - if (referenceCountable_) { - return ReferenceHandler::retain(object_); - } - else { - return CL_SUCCESS; - } - } - - cl_int release() const - { - if (referenceCountable_) { - return ReferenceHandler::release(object_); - } - else { - return CL_SUCCESS; - } - } - }; - - } // namespace detail - //! \endcond - - /*! \stuct ImageFormat - * \brief Adds constructors and member functions for cl_image_format. - * - * \see cl_image_format - */ - struct ImageFormat : public cl_image_format - { - //! \brief Default constructor - performs no initialization. - ImageFormat(){} - - //! \brief Initializing constructor. - ImageFormat(cl_channel_order order, cl_channel_type type) - { - image_channel_order = order; - image_channel_data_type = type; - } - - //! \brief Assignment operator. - ImageFormat& operator = (const ImageFormat& rhs) - { - if (this != &rhs) { - this->image_channel_data_type = rhs.image_channel_data_type; - this->image_channel_order = rhs.image_channel_order; - } - return *this; - } - }; - - /*! \brief Class interface for cl_device_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_device_id - */ - class Device : public detail::Wrapper - { - public: - //! \brief Default constructor - initializes to NULL. - Device() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device(const Device& device) : detail::Wrapper(device) { } - - /*! \brief Constructor from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device(const cl_device_id &device) : detail::Wrapper(device) { } - - /*! \brief Returns the first device on the default context. - * - * \see Context::getDefault() - */ - static Device getDefault(cl_int * err = NULL); - - /*! \brief Assignment operator from Device. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device& operator = (const Device& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_device_id. - * - * This simply copies the device ID value, which is an inexpensive operation. - */ - Device& operator = (const cl_device_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetDeviceInfo(). - template - cl_int getInfo(cl_device_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetDeviceInfo, object_, name, param), - __GET_DEVICE_INFO_ERR); - } - - //! \brief Wrapper for clGetDeviceInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_device_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /** - * CL 1.2 version - */ -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clCreateSubDevicesEXT(). - cl_int createSubDevices( - const cl_device_partition_property * properties, - VECTOR_CLASS* devices) - { - cl_uint n = 0; - cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); - err = clCreateSubDevices(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(CL_VERSION_1_2) - - /** - * CL 1.1 version that uses device fission. - */ -#if defined(CL_VERSION_1_1) -#if defined(USE_CL_DEVICE_FISSION) - cl_int createSubDevices( - const cl_device_partition_property_ext * properties, - VECTOR_CLASS* devices) - { - typedef CL_API_ENTRY cl_int - (CL_API_CALL * PFN_clCreateSubDevicesEXT)( - cl_device_id /*in_device*/, - const cl_device_partition_property_ext * /* properties */, - cl_uint /*num_entries*/, - cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/) CL_EXT_SUFFIX__VERSION_1_1; - - static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; - __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); - - cl_uint n = 0; - cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); - err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_SUB_DEVICES); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif // #if defined(USE_CL_DEVICE_FISSION) -#endif // #if defined(CL_VERSION_1_1) - }; - - /*! \brief Class interface for cl_platform_id. - * - * \note Copies of these objects are inexpensive, since they don't 'own' - * any underlying resources or data structures. - * - * \see cl_platform_id - */ - class Platform : public detail::Wrapper - { - public: - //! \brief Default constructor - initializes to NULL. - Platform() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform(const Platform& platform) : detail::Wrapper(platform) { } - - /*! \brief Constructor from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform(const cl_platform_id &platform) : detail::Wrapper(platform) { } - - /*! \brief Assignment operator from Platform. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform& operator = (const Platform& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_platform_id. - * - * This simply copies the platform ID value, which is an inexpensive operation. - */ - Platform& operator = (const cl_platform_id& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetPlatformInfo(). - cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetPlatformInfo, object_, name, param), - __GET_PLATFORM_INFO_ERR); - } - - //! \brief Wrapper for clGetPlatformInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_platform_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of devices for this platform. - * - * Wraps clGetDeviceIDs(). - */ - cl_int getDevices( - cl_device_type type, - VECTOR_CLASS* devices) const - { - cl_uint n = 0; - if (devices == NULL) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); - err = ::clGetDeviceIDs(object_, type, n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - -#if defined(USE_DX_INTEROP) - /*! \brief Get the list of available D3D10 devices. - * - * \param d3d_device_source. - * - * \param d3d_object. - * - * \param d3d_device_set. - * - * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device - * values returned in devices can be used to identify a specific OpenCL - * device. If \a devices argument is NULL, this argument is ignored. - * - * \return One of the following values: - * - CL_SUCCESS if the function is executed successfully. - * - * The application can query specific capabilities of the OpenCL device(s) - * returned by cl::getDevices. This can be used by the application to - * determine which device(s) to use. - * - * \note In the case that exceptions are enabled and a return value - * other than CL_SUCCESS is generated, then cl::Error exception is - * generated. - */ - cl_int getDevices( - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - VECTOR_CLASS* devices) const - { - typedef CL_API_ENTRY cl_int(CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( - cl_platform_id platform, - cl_d3d10_device_source_khr d3d_device_source, - void * d3d_object, - cl_d3d10_device_set_khr d3d_device_set, - cl_uint num_entries, - cl_device_id * devices, - cl_uint* num_devices); - - if (devices == NULL) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); - } - - static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; - __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); - - cl_uint n = 0; - cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - 0, - NULL, - &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - cl_device_id* ids = (cl_device_id*)alloca(n * sizeof(cl_device_id)); - err = pfn_clGetDeviceIDsFromD3D10KHR( - object_, - d3d_device_source, - d3d_object, - d3d_device_set, - n, - ids, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_DEVICE_IDS_ERR); - } - - devices->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } -#endif - - /*! \brief Gets a list of available platforms. - * - * Wraps clGetPlatformIDs(). - */ - static cl_int get( - VECTOR_CLASS* platforms) - { - cl_uint n = 0; - - if (platforms == NULL) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*)alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - platforms->assign(&ids[0], &ids[n]); - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static cl_int get( - Platform * platform) - { - cl_uint n = 0; - - if (platform == NULL) { - return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); - } - - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - cl_platform_id* ids = (cl_platform_id*)alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - *platform = ids[0]; - return CL_SUCCESS; - } - - /*! \brief Gets the first available platform, returning it by value. - * - * Wraps clGetPlatformIDs(), returning the first result. - */ - static Platform get( - cl_int * errResult = NULL) - { - Platform platform; - cl_uint n = 0; - cl_int err = ::clGetPlatformIDs(0, NULL, &n); - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - if (errResult != NULL) { - *errResult = err; - } - } - - cl_platform_id* ids = (cl_platform_id*)alloca( - n * sizeof(cl_platform_id)); - err = ::clGetPlatformIDs(n, ids, NULL); - - if (err != CL_SUCCESS) { - detail::errHandler(err, __GET_PLATFORM_IDS_ERR); - } - - if (errResult != NULL) { - *errResult = err; - } - - return ids[0]; - } - - static Platform getDefault( - cl_int *errResult = NULL) - { - return get(errResult); - } - - -#if defined(CL_VERSION_1_2) - //! \brief Wrapper for clUnloadCompiler(). - cl_int - unloadCompiler() - { - return ::clUnloadPlatformCompiler(object_); - } -#endif // #if defined(CL_VERSION_1_2) - }; // class Platform - - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - /** - * Unload the OpenCL compiler. - * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. - */ - inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int - UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - inline cl_int - UnloadCompiler() - { - return ::clUnloadCompiler(); - } -#endif // #if defined(CL_VERSION_1_1) - - /*! \brief Class interface for cl_context. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_context as the original. For details, see - * clRetainContext() and clReleaseContext(). - * - * \see cl_context - */ - class Context - : public detail::Wrapper - { - private: - static volatile int default_initialized_; - static Context default_; - static volatile cl_int default_error_; - public: - /*! \brief Destructor. - * - * This calls clReleaseContext() on the value held by this instance. - */ - ~Context() { } - - /*! \brief Constructs a context including a list of specified devices. - * - * Wraps clCreateContext(). - */ - Context( - const VECTOR_CLASS& devices, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); - for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateContext( - properties, (cl_uint)numDevices, - deviceIDs, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - Context( - const Device& device, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - - cl_device_id deviceID = device(); - - object_ = ::clCreateContext( - properties, 1, - &deviceID, - notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a context including all devices of a specified type. - * - * Wraps clCreateContextFromType(). - */ - Context( - cl_device_type type, - cl_context_properties* properties = NULL, - void (CL_CALLBACK * notifyFptr)( - const char *, - const void *, - ::size_t, - void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int error; - -#if !defined(__APPLE__) || !defined(__MACOS) - cl_context_properties prop[4] = { CL_CONTEXT_PLATFORM, 0, 0, 0 }; - if (properties == NULL) { - prop[1] = (cl_context_properties)Platform::get(&error)(); - if (error != CL_SUCCESS) { - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - return; - } - } - - properties = &prop[0]; - } -#endif - object_ = ::clCreateContextFromType( - properties, type, notifyFptr, data, &error); - - detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. - * - * \note All calls to this function return the same cl_context as the first. - */ - static Context getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while (default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - default_ = Context( - CL_DEVICE_TYPE_DEFAULT, - NULL, - NULL, - NULL, - &error); - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - //! \brief Default constructor - initializes to NULL. - Context() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This calls clRetainContext() on the parameter's cl_context. - */ - Context(const Context& context) : detail::Wrapper(context) { } - - /*! \brief Constructor from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_context - * into the new Context object. - */ - __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) { } - - /*! \brief Assignment operator from Context. - * - * This calls clRetainContext() on the parameter and clReleaseContext() on - * the previous value held by this instance. - */ - Context& operator = (const Context& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_context - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseContext() on the value previously held by this instance. - */ - Context& operator = (const cl_context& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetContextInfo(). - template - cl_int getInfo(cl_context_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetContextInfo, object_, name, param), - __GET_CONTEXT_INFO_ERR); - } - - //! \brief Wrapper for clGetContextInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_context_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Gets a list of supported image formats. - * - * Wraps clGetSupportedImageFormats(). - */ - cl_int getSupportedImageFormats( - cl_mem_flags flags, - cl_mem_object_type type, - VECTOR_CLASS* formats) const - { - cl_uint numEntries; - cl_int err = ::clGetSupportedImageFormats( - object_, - flags, - type, - 0, - NULL, - &numEntries); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - ImageFormat* value = (ImageFormat*) - alloca(numEntries * sizeof(ImageFormat)); - err = ::clGetSupportedImageFormats( - object_, - flags, - type, - numEntries, - (cl_image_format*)value, - NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); - } - - formats->assign(&value[0], &value[numEntries]); - return CL_SUCCESS; - } - }; - - inline Device Device::getDefault(cl_int * err) - { - cl_int error; - Device device; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - device = context.getInfo()[0]; - if (err != NULL) { - *err = CL_SUCCESS; - } - } - - return device; - } - - -#ifdef _WIN32 - __declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; - __declspec(selectany) Context Context::default_; - __declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; -#else - __attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; - __attribute__((weak)) Context Context::default_; - __attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; -#endif - - /*! \brief Class interface for cl_event. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_event as the original. For details, see - * clRetainEvent() and clReleaseEvent(). - * - * \see cl_event - */ - class Event : public detail::Wrapper - { - public: - /*! \brief Destructor. - * - * This calls clReleaseEvent() on the value held by this instance. - */ - ~Event() { } - - //! \brief Default constructor - initializes to NULL. - Event() : detail::Wrapper() { } - - /*! \brief Copy constructor. - * - * This calls clRetainEvent() on the parameter's cl_event. - */ - Event(const Event& event) : detail::Wrapper(event) { } - - /*! \brief Constructor from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_event - * into the new Event object. - */ - Event(const cl_event& event) : detail::Wrapper(event) { } - - /*! \brief Assignment operator from cl_event - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseEvent() on the value previously held by this instance. - */ - Event& operator = (const Event& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_event. - * - * This calls clRetainEvent() on the parameter and clReleaseEvent() on - * the previous value held by this instance. - */ - Event& operator = (const cl_event& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetEventInfo(). - template - cl_int getInfo(cl_event_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetEventInfo, object_, name, param), - __GET_EVENT_INFO_ERR); - } - - //! \brief Wrapper for clGetEventInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_event_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - //! \brief Wrapper for clGetEventProfilingInfo(). - template - cl_int getProfilingInfo(cl_profiling_info name, T* param) const - { - return detail::errHandler(detail::getInfo( - &::clGetEventProfilingInfo, object_, name, param), - __GET_EVENT_PROFILE_INFO_ERR); - } - - //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. - template typename - detail::param_traits::param_type - getProfilingInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_profiling_info, name>::param_type param; - cl_int result = getProfilingInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - /*! \brief Blocks the calling thread until this event completes. - * - * Wraps clWaitForEvents(). - */ - cl_int wait() const - { - return detail::errHandler( - ::clWaitForEvents(1, &object_), - __WAIT_FOR_EVENTS_ERR); - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a user callback function for a specific command execution status. - * - * Wraps clSetEventCallback(). - */ - cl_int setCallback( - cl_int type, - void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetEventCallback( - object_, - type, - pfn_notify, - user_data), - __SET_EVENT_CALLBACK_ERR); - } -#endif - - /*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ - static cl_int - waitForEvents(const VECTOR_CLASS& events) - { - return detail::errHandler( - ::clWaitForEvents( - (cl_uint)events.size(), (cl_event*)&events.front()), - __WAIT_FOR_EVENTS_ERR); - } - }; - -#if defined(CL_VERSION_1_1) - /*! \brief Class interface for user events (a subset of cl_event's). - * - * See Event for details about copy semantics, etc. - */ - class UserEvent : public Event - { - public: - /*! \brief Constructs a user event on a given context. - * - * Wraps clCreateUserEvent(). - */ - UserEvent( - const Context& context, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateUserEvent( - context(), - &error); - - detail::errHandler(error, __CREATE_USER_EVENT_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - UserEvent() : Event() { } - - //! \brief Copy constructor - performs shallow copy. - UserEvent(const UserEvent& event) : Event(event) { } - - //! \brief Assignment Operator - performs shallow copy. - UserEvent& operator = (const UserEvent& rhs) - { - if (this != &rhs) { - Event::operator=(rhs); - } - return *this; - } - - /*! \brief Sets the execution status of a user event object. - * - * Wraps clSetUserEventStatus(). - */ - cl_int setStatus(cl_int status) - { - return detail::errHandler( - ::clSetUserEventStatus(object_, status), - __SET_USER_EVENT_STATUS_ERR); - } - }; -#endif - - /*! \brief Blocks the calling thread until every event specified is complete. - * - * Wraps clWaitForEvents(). - */ - inline static cl_int - WaitForEvents(const VECTOR_CLASS& events) - { - return detail::errHandler( - ::clWaitForEvents( - (cl_uint)events.size(), (cl_event*)&events.front()), - __WAIT_FOR_EVENTS_ERR); - } - - /*! \brief Class interface for cl_mem. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_mem as the original. For details, see - * clRetainMemObject() and clReleaseMemObject(). - * - * \see cl_mem - */ - class Memory : public detail::Wrapper - { - public: - - /*! \brief Destructor. - * - * This calls clReleaseMemObject() on the value held by this instance. - */ - ~Memory() {} - - //! \brief Default constructor - initializes to NULL. - Memory() : detail::Wrapper() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainMemObject() on the parameter's cl_mem. - */ - Memory(const Memory& memory) : detail::Wrapper(memory) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_mem - * into the new Memory object. - */ - __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) { } - - /*! \brief Assignment operator from Memory. - * - * This calls clRetainMemObject() on the parameter and clReleaseMemObject() - * on the previous value held by this instance. - */ - Memory& operator = (const Memory& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_mem - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseMemObject() on the value previously held by this instance. - */ - Memory& operator = (const cl_mem& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetMemObjectInfo(). - template - cl_int getInfo(cl_mem_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetMemObjectInfo, object_, name, param), - __GET_MEM_OBJECT_INFO_ERR); - } - - //! \brief Wrapper for clGetMemObjectInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_mem_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_1) - /*! \brief Registers a callback function to be called when the memory object - * is no longer needed. - * - * Wraps clSetMemObjectDestructorCallback(). - * - * Repeated calls to this function, for a given cl_mem value, will append - * to the list of functions called (in reverse order) when memory object's - * resources are freed and the memory object is deleted. - * - * \note - * The registered callbacks are associated with the underlying cl_mem - * value - not the Memory class instance. - */ - cl_int setDestructorCallback( - void (CL_CALLBACK * pfn_notify)(cl_mem, void *), - void * user_data = NULL) - { - return detail::errHandler( - ::clSetMemObjectDestructorCallback( - object_, - pfn_notify, - user_data), - __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); - } -#endif - - }; - - // Pre-declare copy functions - class Buffer; - template< typename IteratorType > - cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer); - template< typename IteratorType > - cl_int copy(const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator); - - /*! \brief Class interface for Buffer Memory Objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Buffer : public Memory - { - public: - - /*! \brief Constructs a Buffer in a specified context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - */ - Buffer( - const Context& context, - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Constructs a Buffer in the default context. - * - * Wraps clCreateBuffer(). - * - * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was - * specified. Note alignment & exclusivity requirements. - * - * \see Context::getDefault() - */ - Buffer( - cl_mem_flags flags, - ::size_t size, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(err); - - object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! - * \brief Construct a Buffer from a host container via iterators. - * If useHostPtr is specified iterators must be random access. - */ - template< typename IteratorType > - Buffer( - IteratorType startIterator, - IteratorType endIterator, - bool readOnly, - bool useHostPtr = false, - cl_int* err = NULL) - { - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - cl_mem_flags flags = 0; - if (readOnly) { - flags |= CL_MEM_READ_ONLY; - } - else { - flags |= CL_MEM_READ_WRITE; - } - if (useHostPtr) { - flags |= CL_MEM_USE_HOST_PTR; - } - - ::size_t size = sizeof(DataType)*(endIterator - startIterator); - - Context context = Context::getDefault(err); - - if (useHostPtr) { - object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); - } - else { - object_ = ::clCreateBuffer(context(), flags, size, 0, &error); - } - - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - if (!useHostPtr) { - error = cl::copy(startIterator, endIterator, *this); - detail::errHandler(error, __CREATE_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - } - - //! \brief Default constructor - initializes to NULL. - Buffer() : Memory() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Buffer(const Buffer& buffer) : Memory(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) { } - - /*! \brief Assignment from Buffer - performs shallow copy. - * - * See Memory for further details. - */ - Buffer& operator = (const Buffer& rhs) - { - if (this != &rhs) { - Memory::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Buffer& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - -#if defined(CL_VERSION_1_1) - /*! \brief Creates a new buffer object from this. - * - * Wraps clCreateSubBuffer(). - */ - Buffer createSubBuffer( - cl_mem_flags flags, - cl_buffer_create_type buffer_create_type, - const void * buffer_create_info, - cl_int * err = NULL) - { - Buffer result; - cl_int error; - result.object_ = ::clCreateSubBuffer( - object_, - flags, - buffer_create_type, - buffer_create_info, - &error); - - detail::errHandler(error, __CREATE_SUBBUFFER_ERR); - if (err != NULL) { - *err = error; - } - - return result; - } -#endif - }; - -#if defined (USE_DX_INTEROP) - /*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. - * - * This is provided to facilitate interoperability with Direct3D. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class BufferD3D10 : public Buffer - { - public: - typedef CL_API_ENTRY cl_mem(CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( - cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, - cl_int* errcode_ret); - - /*! \brief Constructs a BufferD3D10, in a specified context, from a - * given ID3D10Buffer. - * - * Wraps clCreateFromD3D10BufferKHR(). - */ - BufferD3D10( - const Context& context, - cl_mem_flags flags, - ID3D10Buffer* bufobj, - cl_int * err = NULL) - { - static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; - -#if defined(CL_VERSION_1_2) - vector props = context.getInfo(); - cl_platform platform = -1; - for (int i = 0; i < props.size(); ++i) { - if (props[i] == CL_CONTEXT_PLATFORM) { - platform = props[i + 1]; - } - } - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); -#endif - - cl_int error; - object_ = pfn_clCreateFromD3D10BufferKHR( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferD3D10() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10(const BufferD3D10& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferD3D10 - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10& operator = (const BufferD3D10& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferD3D10& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - }; -#endif - - /*! \brief Class interface for GL Buffer Memory Objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class BufferGL : public Buffer - { - public: - /*! \brief Constructs a BufferGL in a specified context, from a given - * GL buffer. - * - * Wraps clCreateFromGLBuffer(). - */ - BufferGL( - const Context& context, - cl_mem_flags flags, - GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLBuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferGL() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL(const BufferGL& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferGL - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL& operator = (const BufferGL& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferGL& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_, type, gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } - }; - - /*! \brief Class interface for GL Render Buffer Memory Objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class BufferRenderGL : public Buffer - { - public: - /*! \brief Constructs a BufferRenderGL in a specified context, from a given - * GL Renderbuffer. - * - * Wraps clCreateFromGLRenderbuffer(). - */ - BufferRenderGL( - const Context& context, - cl_mem_flags flags, - GLuint bufobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLRenderbuffer( - context(), - flags, - bufobj, - &error); - - detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - BufferRenderGL() : Buffer() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL(const BufferGL& buffer) : Buffer(buffer) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Buffer(buffer) { } - - /*! \brief Assignment from BufferGL - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL& operator = (const BufferRenderGL& rhs) - { - if (this != &rhs) { - Buffer::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - BufferRenderGL& operator = (const cl_mem& rhs) - { - Buffer::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetGLObjectInfo(). - cl_int getObjectInfo( - cl_gl_object_type *type, - GLuint * gl_object_name) - { - return detail::errHandler( - ::clGetGLObjectInfo(object_, type, gl_object_name), - __GET_GL_OBJECT_INFO_ERR); - } - }; - - /*! \brief C++ base class for Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Image : public Memory - { - protected: - //! \brief Default constructor - initializes to NULL. - Image() : Memory() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image(const Image& image) : Memory(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) { } - - /*! \brief Assignment from Image - performs shallow copy. - * - * See Memory for further details. - */ - Image& operator = (const Image& rhs) - { - if (this != &rhs) { - Memory::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image& operator = (const cl_mem& rhs) - { - Memory::operator=(rhs); - return *this; - } - - public: - //! \brief Wrapper for clGetImageInfo(). - template - cl_int getImageInfo(cl_image_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetImageInfo, object_, name, param), - __GET_IMAGE_INFO_ERR); - } - - //! \brief Wrapper for clGetImageInfo() that returns by value. - template typename - detail::param_traits::param_type - getImageInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_image_info, name>::param_type param; - cl_int result = getImageInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - }; - -#if defined(CL_VERSION_1_2) - /*! \brief Class interface for 1D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Image1D : public Image - { - public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image1D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D; - desc.image_width = width; - desc.image_row_pitch = 0; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image1D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image1D(const Image1D& image1D) : Image(image1D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) { } - - /*! \brief Assignment from Image1D - performs shallow copy. - * - * See Memory for further details. - */ - Image1D& operator = (const Image1D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image1D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; - - /*! \class Image1DBuffer - * \brief Image interface for 1D buffer images. - */ - class Image1DBuffer : public Image - { - public: - Image1DBuffer( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - const Buffer &buffer, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER; - desc.image_width = width; - desc.image_row_pitch = 0; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = buffer(); - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - NULL, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DBuffer() { } - - Image1DBuffer(const Image1DBuffer& image1D) : Image(image1D) { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) { } - - Image1DBuffer& operator = (const Image1DBuffer& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image1DBuffer& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; - - /*! \class Image1DArray - * \brief Image interface for arrays of 1D images. - */ - class Image1DArray : public Image - { - public: - Image1DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t rowPitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY; - desc.image_array_size = arraySize; - desc.image_width = width; - desc.image_row_pitch = rowPitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image1DArray() { } - - Image1DArray(const Image1DArray& imageArray) : Image(imageArray) { } - - __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image1DArray& operator = (const Image1DArray& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image1DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; -#endif // #if defined(CL_VERSION_1_2) - - - /*! \brief Class interface for 2D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Image2D : public Image - { - public: - /*! \brief Constructs a 1D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image2D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t row_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE2D; - desc.image_width = width; - desc.image_height = height; - desc.image_row_pitch = row_pitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage2D( - context(), flags, &format, width, height, row_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE2D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image2D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image2D(const Image2D& image2D) : Image(image2D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) { } - - /*! \brief Assignment from Image2D - performs shallow copy. - * - * See Memory for further details. - */ - Image2D& operator = (const Image2D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; - - -#if !defined(CL_VERSION_1_2) - /*! \brief Class interface for GL 2D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. - */ - class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D - { - public: - /*! \brief Constructs an Image2DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture2D(). - */ - Image2DGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture2D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); - if (err != NULL) { - *err = error; - } - - } - - //! \brief Default constructor - initializes to NULL. - Image2DGL() : Image2D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL(const Image2DGL& image) : Image2D(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) { } - - /*! \brief Assignment from Image2DGL - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL& operator = (const Image2DGL& rhs) - { - if (this != &rhs) { - Image2D::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image2DGL& operator = (const cl_mem& rhs) - { - Image2D::operator=(rhs); - return *this; - } - }; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) - /*! \class Image2DArray - * \brief Image interface for arrays of 2D images. - */ - class Image2DArray : public Image - { - public: - Image2DArray( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t arraySize, - ::size_t width, - ::size_t height, - ::size_t rowPitch, - ::size_t slicePitch, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; - desc.image_array_size = arraySize; - desc.image_width = width; - desc.image_height = height; - desc.image_row_pitch = rowPitch; - desc.image_slice_pitch = slicePitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } - - Image2DArray() { } - - Image2DArray(const Image2DArray& imageArray) : Image(imageArray) { } - - __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) { } - - Image2DArray& operator = (const Image2DArray& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - Image2DArray& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; -#endif // #if defined(CL_VERSION_1_2) - - /*! \brief Class interface for 3D Image Memory objects. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Image3D : public Image - { - public: - /*! \brief Constructs a 3D Image in a specified context. - * - * Wraps clCreateImage(). - */ - Image3D( - const Context& context, - cl_mem_flags flags, - ImageFormat format, - ::size_t width, - ::size_t height, - ::size_t depth, - ::size_t row_pitch = 0, - ::size_t slice_pitch = 0, - void* host_ptr = NULL, - cl_int* err = NULL) - { - cl_int error; - bool useCreateImage; - -#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - // Run-time decision based on the actual platform - { - cl_uint version = detail::getContextPlatformVersion(context()); - useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above - } -#elif defined(CL_VERSION_1_2) - useCreateImage = true; -#else - useCreateImage = false; -#endif - -#if defined(CL_VERSION_1_2) - if (useCreateImage) - { - cl_image_desc desc; - desc.image_type = CL_MEM_OBJECT_IMAGE3D; - desc.image_width = width; - desc.image_height = height; - desc.image_depth = depth; - desc.image_row_pitch = row_pitch; - desc.image_slice_pitch = slice_pitch; - desc.num_mip_levels = 0; - desc.num_samples = 0; - desc.buffer = 0; - object_ = ::clCreateImage( - context(), - flags, - &format, - &desc, - host_ptr, - &error); - - detail::errHandler(error, __CREATE_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) -#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - if (!useCreateImage) - { - object_ = ::clCreateImage3D( - context(), flags, &format, width, height, depth, row_pitch, - slice_pitch, host_ptr, &error); - - detail::errHandler(error, __CREATE_IMAGE3D_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - } - - //! \brief Default constructor - initializes to NULL. - Image3D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image3D(const Image3D& image3D) : Image(image3D) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) { } - - /*! \brief Assignment from Image3D - performs shallow copy. - * - * See Memory for further details. - */ - Image3D& operator = (const Image3D& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3D& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; - -#if !defined(CL_VERSION_1_2) - /*! \brief Class interface for GL 3D Image Memory objects. - * - * This is provided to facilitate interoperability with OpenGL. - * - * See Memory for details about copy semantics, etc. - * - * \see Memory - */ - class Image3DGL : public Image3D - { - public: - /*! \brief Constructs an Image3DGL in a specified context, from a given - * GL Texture. - * - * Wraps clCreateFromGLTexture3D(). - */ - Image3DGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture3D( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); - if (err != NULL) { - *err = error; - } - } - - //! \brief Default constructor - initializes to NULL. - Image3DGL() : Image3D() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL(const Image3DGL& image) : Image3D(image) { } - - /*! \brief Constructor from cl_mem - takes ownership. - * - * See Memory for further details. - */ - __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) { } - - /*! \brief Assignment from Image3DGL - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL& operator = (const Image3DGL& rhs) - { - if (this != &rhs) { - Image3D::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment from cl_mem - performs shallow copy. - * - * See Memory for further details. - */ - Image3DGL& operator = (const cl_mem& rhs) - { - Image3D::operator=(rhs); - return *this; - } - }; -#endif // #if !defined(CL_VERSION_1_2) - -#if defined(CL_VERSION_1_2) - /*! \class ImageGL - * \brief general image interface for GL interop. - * We abstract the 2D and 3D GL images into a single instance here - * that wraps all GL sourced images on the grounds that setup information - * was performed by OpenCL anyway. - */ - class ImageGL : public Image - { - public: - ImageGL( - const Context& context, - cl_mem_flags flags, - GLenum target, - GLint miplevel, - GLuint texobj, - cl_int * err = NULL) - { - cl_int error; - object_ = ::clCreateFromGLTexture( - context(), - flags, - target, - miplevel, - texobj, - &error); - - detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); - if (err != NULL) { - *err = error; - } - } - - ImageGL() : Image() { } - - ImageGL(const ImageGL& image) : Image(image) { } - - __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) { } - - ImageGL& operator = (const ImageGL& rhs) - { - if (this != &rhs) { - Image::operator=(rhs); - } - return *this; - } - - ImageGL& operator = (const cl_mem& rhs) - { - Image::operator=(rhs); - return *this; - } - }; -#endif // #if defined(CL_VERSION_1_2) - - /*! \brief Class interface for cl_sampler. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_sampler as the original. For details, see - * clRetainSampler() and clReleaseSampler(). - * - * \see cl_sampler - */ - class Sampler : public detail::Wrapper - { - public: - /*! \brief Destructor. - * - * This calls clReleaseSampler() on the value held by this instance. - */ - ~Sampler() { } - - //! \brief Default constructor - initializes to NULL. - Sampler() { } - - /*! \brief Constructs a Sampler in a specified context. - * - * Wraps clCreateSampler(). - */ - Sampler( - const Context& context, - cl_bool normalized_coords, - cl_addressing_mode addressing_mode, - cl_filter_mode filter_mode, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateSampler( - context(), - normalized_coords, - addressing_mode, - filter_mode, - &error); - - detail::errHandler(error, __CREATE_SAMPLER_ERR); - if (err != NULL) { - *err = error; - } - } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainSampler() on the parameter's cl_sampler. - */ - Sampler(const Sampler& sampler) : detail::Wrapper(sampler) { } - - /*! \brief Constructor from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_sampler - * into the new Sampler object. - */ - Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) { } - - /*! \brief Assignment operator from Sampler. - * - * This calls clRetainSampler() on the parameter and clReleaseSampler() - * on the previous value held by this instance. - */ - Sampler& operator = (const Sampler& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_sampler - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseSampler() on the value previously held by this instance. - */ - Sampler& operator = (const cl_sampler& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - //! \brief Wrapper for clGetSamplerInfo(). - template - cl_int getInfo(cl_sampler_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetSamplerInfo, object_, name, param), - __GET_SAMPLER_INFO_ERR); - } - - //! \brief Wrapper for clGetSamplerInfo() that returns by value. - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_sampler_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - }; - - class Program; - class CommandQueue; - class Kernel; - - //! \brief Class interface for specifying NDRange values. - class NDRange - { - private: - size_t<3> sizes_; - cl_uint dimensions_; - - public: - //! \brief Default constructor - resulting range has zero dimensions. - NDRange() - : dimensions_(0) - { } - - //! \brief Constructs one-dimensional range. - NDRange(::size_t size0) - : dimensions_(1) - { - sizes_[0] = size0; - } - - //! \brief Constructs two-dimensional range. - NDRange(::size_t size0, ::size_t size1) - : dimensions_(2) - { - sizes_[0] = size0; - sizes_[1] = size1; - } - - //! \brief Constructs three-dimensional range. - NDRange(::size_t size0, ::size_t size1, ::size_t size2) - : dimensions_(3) - { - sizes_[0] = size0; - sizes_[1] = size1; - sizes_[2] = size2; - } - - /*! \brief Conversion operator to const ::size_t *. - * - * \returns a pointer to the size of the first dimension. - */ - operator const ::size_t*() const { - return (const ::size_t*) sizes_; - } - - //! \brief Queries the number of dimensions in the range. - ::size_t dimensions() const { return dimensions_; } - }; - - //! \brief A zero-dimensional range. - static const NDRange NullRange; - - //! \brief Local address wrapper for use with Kernel::setArg - struct LocalSpaceArg - { - ::size_t size_; - }; - - namespace detail { - - template - struct KernelArgumentHandler - { - static ::size_t size(const T&) { return sizeof(T); } - static T* ptr(T& value) { return &value; } - }; - - template <> - struct KernelArgumentHandler - { - static ::size_t size(const LocalSpaceArg& value) { return value.size_; } - static void* ptr(LocalSpaceArg&) { return NULL; } - }; - - } - //! \endcond - - /*! __local - * \brief Helper function for generating LocalSpaceArg objects. - * Deprecated. Replaced with Local. - */ - inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg - __local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; - inline LocalSpaceArg - __local(::size_t size) - { - LocalSpaceArg ret = { size }; - return ret; - } - - /*! Local - * \brief Helper function for generating LocalSpaceArg objects. - */ - inline LocalSpaceArg - Local(::size_t size) - { - LocalSpaceArg ret = { size }; - return ret; - } - - //class KernelFunctor; - - /*! \brief Class interface for cl_kernel. - * - * \note Copies of these objects are shallow, meaning that the copy will refer - * to the same underlying cl_kernel as the original. For details, see - * clRetainKernel() and clReleaseKernel(). - * - * \see cl_kernel - */ - class Kernel : public detail::Wrapper - { - public: - inline Kernel(const Program& program, const char* name, cl_int* err = NULL); - - /*! \brief Destructor. - * - * This calls clReleaseKernel() on the value held by this instance. - */ - ~Kernel() { } - - //! \brief Default constructor - initializes to NULL. - Kernel() { } - - /*! \brief Copy constructor - performs shallow copy. - * - * This calls clRetainKernel() on the parameter's cl_kernel. - */ - Kernel(const Kernel& kernel) : detail::Wrapper(kernel) { } - - /*! \brief Constructor from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the cl_kernel - * into the new Kernel object. - */ - __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) { } - - /*! \brief Assignment operator from Kernel. - * - * This calls clRetainKernel() on the parameter and clReleaseKernel() - * on the previous value held by this instance. - */ - Kernel& operator = (const Kernel& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - /*! \brief Assignment operator from cl_kernel - takes ownership. - * - * This effectively transfers ownership of a refcount on the rhs and calls - * clReleaseKernel() on the value previously held by this instance. - */ - Kernel& operator = (const cl_kernel& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - template - cl_int getInfo(cl_kernel_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelInfo, object_, name, param), - __GET_KERNEL_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - -#if defined(CL_VERSION_1_2) - template - cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), - __GET_KERNEL_ARG_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getArgInfo(cl_uint argIndex, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_arg_info, name>::param_type param; - cl_int result = getArgInfo(argIndex, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } -#endif // #if defined(CL_VERSION_1_2) - - template - cl_int getWorkGroupInfo( - const Device& device, cl_kernel_work_group_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetKernelWorkGroupInfo, object_, device(), name, param), - __GET_KERNEL_WORK_GROUP_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getWorkGroupInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_kernel_work_group_info, name>::param_type param; - cl_int result = getWorkGroupInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int setArg(cl_uint index, T value) - { - return detail::errHandler( - ::clSetKernelArg( - object_, - index, - detail::KernelArgumentHandler::size(value), - detail::KernelArgumentHandler::ptr(value)), - __SET_KERNEL_ARGS_ERR); - } - - cl_int setArg(cl_uint index, ::size_t size, void* argPtr) - { - return detail::errHandler( - ::clSetKernelArg(object_, index, size, argPtr), - __SET_KERNEL_ARGS_ERR); - } - }; - - /*! \class Program - * \brief Program interface that implements cl_program. - */ - class Program : public detail::Wrapper - { - public: - typedef VECTOR_CLASS > Binaries; - typedef VECTOR_CLASS > Sources; - - Program( - const STRING_CLASS& source, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - Context context = Context::getDefault(err); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const STRING_CLASS& source, - bool build, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - Context context = Context::getDefault(err); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const STRING_CLASS& source, - bool build = false, - cl_int* err = NULL) - { - cl_int error; - - const char * strings = source.c_str(); - const ::size_t length = source.size(); - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)1, &strings, &length, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - - if (error == CL_SUCCESS && build) { - - error = ::clBuildProgram( - object_, - 0, - NULL, - "", - NULL, - NULL); - - detail::errHandler(error, __BUILD_PROGRAM_ERR); - } - - if (err != NULL) { - *err = error; - } - } - - Program( - const Context& context, - const Sources& sources, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t n = (::size_t)sources.size(); - ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); - const char** strings = (const char**)alloca(n * sizeof(const char*)); - - for (::size_t i = 0; i < n; ++i) { - strings[i] = sources[(int)i].first; - lengths[i] = sources[(int)i].second; - } - - object_ = ::clCreateProgramWithSource( - context(), (cl_uint)n, strings, lengths, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); - if (err != NULL) { - *err = error; - } - } - - /** - * Construct a program object from a list of devices and a per-device list of binaries. - * \param context A valid OpenCL context in which to construct the program. - * \param devices A vector of OpenCL device objects for which the program will be created. - * \param binaries A vector of pairs of a pointer to a binary object and its length. - * \param binaryStatus An optional vector that on completion will be resized to - * match the size of binaries and filled with values to specify if each binary - * was successfully loaded. - * Set to CL_SUCCESS if the binary was successfully loaded. - * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. - * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. - * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: - * CL_INVALID_CONTEXT if context is not a valid context. - * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; - * or if any entry in binaries is NULL or has length 0. - * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. - * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. - * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const Binaries& binaries, - VECTOR_CLASS* binaryStatus = NULL, - cl_int* err = NULL) - { - cl_int error; - - const ::size_t numDevices = devices.size(); - - // Catch size mismatch early and return - if (binaries.size() != numDevices) { - error = CL_INVALID_VALUE; - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - return; - } - - ::size_t* lengths = (::size_t*) alloca(numDevices * sizeof(::size_t)); - const unsigned char** images = (const unsigned char**)alloca(numDevices * sizeof(const unsigned char**)); - - for (::size_t i = 0; i < numDevices; ++i) { - images[i] = (const unsigned char*)binaries[i].first; - lengths[i] = binaries[(int)i].second; - } - - cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); - for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - if (binaryStatus) { - binaryStatus->resize(numDevices); - } - - object_ = ::clCreateProgramWithBinary( - context(), (cl_uint)devices.size(), - deviceIDs, - lengths, images, binaryStatus != NULL - ? &binaryStatus->front() - : NULL, &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); - if (err != NULL) { - *err = error; - } - } - - -#if defined(CL_VERSION_1_2) - /** - * Create program using builtin kernels. - * \param kernelNames Semi-colon separated list of builtin kernel names - */ - Program( - const Context& context, - const VECTOR_CLASS& devices, - const STRING_CLASS& kernelNames, - cl_int* err = NULL) - { - cl_int error; - - - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); - for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - object_ = ::clCreateProgramWithBuiltInKernels( - context(), - (cl_uint)devices.size(), - deviceIDs, - kernelNames.c_str(), - &error); - - detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); - if (err != NULL) { - *err = error; - } - } -#endif // #if defined(CL_VERSION_1_2) - - Program() { } - - Program(const Program& program) : detail::Wrapper(program) { } - - __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) { } - - Program& operator = (const Program& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - Program& operator = (const cl_program& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - cl_int build( - const VECTOR_CLASS& devices, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - ::size_t numDevices = devices.size(); - cl_device_id* deviceIDs = (cl_device_id*)alloca(numDevices * sizeof(cl_device_id)); - for (::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex) { - deviceIDs[deviceIndex] = (devices[deviceIndex])(); - } - - return detail::errHandler( - ::clBuildProgram( - object_, - (cl_uint) - devices.size(), - deviceIDs, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - - cl_int build( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clBuildProgram( - object_, - 0, - NULL, - options, - notifyFptr, - data), - __BUILD_PROGRAM_ERR); - } - -#if defined(CL_VERSION_1_2) - cl_int compile( - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL) const - { - return detail::errHandler( - ::clCompileProgram( - object_, - 0, - NULL, - options, - 0, - NULL, - NULL, - notifyFptr, - data), - __COMPILE_PROGRAM_ERR); - } -#endif - - template - cl_int getInfo(cl_program_info name, T* param) const - { - return detail::errHandler( - detail::getInfo(&::clGetProgramInfo, object_, name, param), - __GET_PROGRAM_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - template - cl_int getBuildInfo( - const Device& device, cl_program_build_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetProgramBuildInfo, object_, device(), name, param), - __GET_PROGRAM_BUILD_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getBuildInfo(const Device& device, cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_program_build_info, name>::param_type param; - cl_int result = getBuildInfo(device, name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int createKernels(VECTOR_CLASS* kernels) - { - cl_uint numKernels; - cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - Kernel* value = (Kernel*)alloca(numKernels * sizeof(Kernel)); - err = ::clCreateKernelsInProgram( - object_, numKernels, (cl_kernel*)value, NULL); - if (err != CL_SUCCESS) { - return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); - } - - kernels->assign(&value[0], &value[numKernels]); - return CL_SUCCESS; - } - }; - -#if defined(CL_VERSION_1_2) - inline Program linkProgram( - Program input1, - Program input2, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int err_local = CL_SUCCESS; - - cl_program programs[2] = { input1(), input2() }; - - Context ctx = input1.getInfo(); - - cl_program prog = ::clLinkProgram( - ctx(), - 0, - NULL, - options, - 2, - programs, - notifyFptr, - data, - &err_local); - - detail::errHandler(err_local, __COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = err_local; - } - - return Program(prog); - } - - inline Program linkProgram( - VECTOR_CLASS inputPrograms, - const char* options = NULL, - void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, - void* data = NULL, - cl_int* err = NULL) - { - cl_int err_local = CL_SUCCESS; - - cl_program * programs = (cl_program*)alloca(inputPrograms.size() * sizeof(cl_program)); - - if (programs != NULL) { - for (unsigned int i = 0; i < inputPrograms.size(); i++) { - programs[i] = inputPrograms[i](); - } - } - - cl_program prog = ::clLinkProgram( - Context::getDefault()(), - 0, - NULL, - options, - (cl_uint)inputPrograms.size(), - programs, - notifyFptr, - data, - &err_local); - - detail::errHandler(err_local, __COMPILE_PROGRAM_ERR); - if (err != NULL) { - *err = err_local; - } - - return Program(prog); - } -#endif - - template<> - inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const - { - VECTOR_CLASS< ::size_t> sizes = getInfo(); - VECTOR_CLASS binaries; - for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) - { - char *ptr = NULL; - if (*s != 0) - ptr = new char[*s]; - binaries.push_back(ptr); - } - - cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); - if (err != NULL) { - *err = result; - } - return binaries; - } - - inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) - { - cl_int error; - - object_ = ::clCreateKernel(program(), name, &error); - detail::errHandler(error, __CREATE_KERNEL_ERR); - - if (err != NULL) { - *err = error; - } - - } - - /*! \class CommandQueue - * \brief CommandQueue interface for cl_command_queue. - */ - class CommandQueue : public detail::Wrapper - { - private: - static volatile int default_initialized_; - static CommandQueue default_; - static volatile cl_int default_error_; - public: - CommandQueue( - cl_command_queue_properties properties, - cl_int* err = NULL) - { - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - } - - CommandQueue( - const Context& context, - const Device& device, - cl_command_queue_properties properties = 0, - cl_int* err = NULL) - { - cl_int error; - object_ = ::clCreateCommandQueue( - context(), device(), properties, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - static CommandQueue getDefault(cl_int * err = NULL) - { - int state = detail::compare_exchange( - &default_initialized_, - __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); - - if (state & __DEFAULT_INITIALIZED) { - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - if (state & __DEFAULT_BEING_INITIALIZED) { - // Assume writes will propagate eventually... - while (default_initialized_ != __DEFAULT_INITIALIZED) { - detail::fence(); - } - - if (err != NULL) { - *err = default_error_; - } - return default_; - } - - cl_int error; - - Context context = Context::getDefault(&error); - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - - if (error != CL_SUCCESS) { - if (err != NULL) { - *err = error; - } - } - else { - Device device = context.getInfo()[0]; - - default_ = CommandQueue(context, device, 0, &error); - - detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); - if (err != NULL) { - *err = error; - } - } - - detail::fence(); - - default_error_ = error; - // Assume writes will propagate eventually... - default_initialized_ = __DEFAULT_INITIALIZED; - - detail::fence(); - - if (err != NULL) { - *err = default_error_; - } - return default_; - - } - - CommandQueue() { } - - CommandQueue(const CommandQueue& commandQueue) : detail::Wrapper(commandQueue) { } - - CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) { } - - CommandQueue& operator = (const CommandQueue& rhs) - { - if (this != &rhs) { - detail::Wrapper::operator=(rhs); - } - return *this; - } - - CommandQueue& operator = (const cl_command_queue& rhs) - { - detail::Wrapper::operator=(rhs); - return *this; - } - - template - cl_int getInfo(cl_command_queue_info name, T* param) const - { - return detail::errHandler( - detail::getInfo( - &::clGetCommandQueueInfo, object_, name, param), - __GET_COMMAND_QUEUE_INFO_ERR); - } - - template typename - detail::param_traits::param_type - getInfo(cl_int* err = NULL) const - { - typename detail::param_traits< - detail::cl_command_queue_info, name>::param_type param; - cl_int result = getInfo(name, ¶m); - if (err != NULL) { - *err = result; - } - return param; - } - - cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBuffer( - object_, buffer(), blocking, offset, size, - ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBuffer( - object_, src(), dst(), src_offset, dst_offset, size, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteBufferRect( - object_, - buffer(), - blocking, - (const ::size_t *)buffer_offset, - (const ::size_t *)host_offset, - (const ::size_t *)region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferRect( - object_, - src(), - dst(), - (const ::size_t *)src_origin, - (const ::size_t *)dst_origin, - (const ::size_t *)region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQEUE_COPY_BUFFER_RECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill a buffer object with a pattern - * of a given size. The pattern is specified a as vector. - * \tparam PatternType The datatype of the pattern field. - * The pattern type must be an accepted OpenCL data type. - */ - template - cl_int enqueueFillBuffer( - const Buffer& buffer, - PatternType pattern, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillBuffer( - object_, - buffer(), - static_cast(&pattern), - sizeof(PatternType), - offset, - size, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReadImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_READ_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueWriteImage( - object_, image(), blocking, (const ::size_t *) origin, - (const ::size_t *) region, row_pitch, slice_pitch, ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_WRITE_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImage( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *)dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA floating-point color value if - * the image channel data type is not an unnormalized signed or - * unsigned data type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_float4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA signed integer color value if - * the image channel data type is an unnormalized signed integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_int4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueue a command to fill an image object with a specified color. - * \param fillColor is the color to use to fill the image. - * This is a four component RGBA unsigned integer color value if - * the image channel data type is an unnormalized unsigned integer - * type. - */ - cl_int enqueueFillImage( - const Image& image, - cl_uint4 fillColor, - const size_t<3>& origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueFillImage( - object_, - image(), - static_cast(&fillColor), - (const ::size_t *) origin, - (const ::size_t *) region, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_FILL_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyImageToBuffer( - object_, src(), dst(), (const ::size_t *) src_origin, - (const ::size_t *) region, dst_offset, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueCopyBufferToImage( - object_, src(), dst(), src_offset, - (const ::size_t *) dst_origin, (const ::size_t *) region, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_int error; - void * result = ::clEnqueueMapBuffer( - object_, buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (cl_event*)event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - return result; - } - - void* enqueueMapImage( - const Image& buffer, - cl_bool blocking, - cl_map_flags flags, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t * row_pitch, - ::size_t * slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) const - { - cl_int error; - void * result = ::clEnqueueMapImage( - object_, buffer(), blocking, flags, - (const ::size_t *) origin, (const ::size_t *) region, - row_pitch, slice_pitch, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (cl_event*)event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); - if (err != NULL) { - *err = error; - } - return result; - } - - cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - object_, memory(), mapped_ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined(CL_VERSION_1_2) - /** - * Enqueues a marker command which waits for either a list of events to complete, - * or all previously enqueued commands to complete. - * - * Enqueues a marker command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command returns an event which can be waited on, - * i.e. this event can be waited on to insure that all events either in the event_wait_list - * or all previously enqueued commands, queued before this command to command_queue, - * have completed. - */ - cl_int enqueueMarkerWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueMarkerWithWaitList( - object_, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_MARKER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * A synchronization point that enqueues a barrier operation. - * - * Enqueues a barrier command which waits for either a list of events to complete, - * or if the list is empty it waits for all commands previously enqueued in command_queue - * to complete before it completes. This command blocks command execution, that is, any - * following commands enqueued after it do not execute until it completes. This command - * returns an event which can be waited on, i.e. this event can be waited on to insure that - * all events either in the event_wait_list or all previously enqueued commands, queued - * before this command to command_queue, have completed. - */ - cl_int enqueueBarrierWithWaitList( - const VECTOR_CLASS *events = 0, - Event *event = 0) - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueBarrierWithWaitList( - object_, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_BARRIER_WAIT_LIST_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Enqueues a command to indicate with which device a set of memory objects - * should be associated. - */ - cl_int enqueueMigrateMemObjects( - const VECTOR_CLASS &memObjects, - cl_mem_migration_flags flags, - const VECTOR_CLASS* events = NULL, - Event* event = NULL - ) - { - cl_event tmp; - - cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); - for (int i = 0; i < (int)memObjects.size(); ++i) { - localMemObjects[i] = memObjects[i](); - } - - - cl_int err = detail::errHandler( - ::clEnqueueMigrateMemObjects( - object_, - (cl_uint)memObjects.size(), - static_cast(localMemObjects), - flags, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif // #if defined(CL_VERSION_1_2) - - cl_int enqueueNDRangeKernel( - const Kernel& kernel, - const NDRange& offset, - const NDRange& global, - const NDRange& local = NullRange, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNDRangeKernel( - object_, kernel(), (cl_uint)global.dimensions(), - offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, - (const ::size_t*) global, - local.dimensions() != 0 ? (const ::size_t*) local : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NDRANGE_KERNEL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueTask( - const Kernel& kernel, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueTask( - object_, kernel(), - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_TASK_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueNativeKernel( - void (CL_CALLBACK *userFptr)(void *), - std::pair args, - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* mem_locs = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) - ? (cl_mem*)alloca(mem_objects->size() * sizeof(cl_mem)) - : NULL; - - if (mems != NULL) { - for (unsigned int i = 0; i < mem_objects->size(); i++) { - mems[i] = ((*mem_objects)[i])(); - } - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueNativeKernel( - object_, userFptr, args.first, args.second, - (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, - mems, - (mem_locs != NULL) ? (const void **)&mem_locs->front() : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_NATIVE_KERNEL); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueMarker(object_, (cl_event*)event), - __ENQUEUE_MARKER_ERR); - } - - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueWaitForEvents( - object_, - (cl_uint)events.size(), - (const cl_event*)&events.front()), - __ENQUEUE_WAIT_FOR_EVENTS_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int enqueueAcquireGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueAcquireGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *)&mem_objects->front() : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseGLObjects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueReleaseGLObjects( - object_, - (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *)&mem_objects->front() : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - -#if defined (USE_DX_INTEROP) - typedef CL_API_ENTRY cl_int(CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); - typedef CL_API_ENTRY cl_int(CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( - cl_command_queue command_queue, cl_uint num_objects, - const cl_mem* mem_objects, cl_uint num_events_in_wait_list, - const cl_event* event_wait_list, cl_event* event); - - cl_int enqueueAcquireD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); -#endif -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); -#endif - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueAcquireD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *)&mem_objects->front() : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_ACQUIRE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - cl_int enqueueReleaseD3D10Objects( - const VECTOR_CLASS* mem_objects = NULL, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) const - { - static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; -#if defined(CL_VERSION_1_2) - cl_context context = getInfo(); - cl::Device device(getInfo()); - cl_platform_id platform = device.getInfo(); - __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_2) -#if defined(CL_VERSION_1_1) - __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); -#endif // #if defined(CL_VERSION_1_1) - - cl_event tmp; - cl_int err = detail::errHandler( - pfn_clEnqueueReleaseD3D10ObjectsKHR( - object_, - (mem_objects != NULL) ? (cl_uint)mem_objects->size() : 0, - (mem_objects != NULL) ? (const cl_mem *)&mem_objects->front() : NULL, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_RELEASE_GL_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } -#endif - - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED - { - return detail::errHandler( - ::clEnqueueBarrier(object_), - __ENQUEUE_BARRIER_ERR); - } -#endif // #if defined(CL_VERSION_1_1) - - cl_int flush() const - { - return detail::errHandler(::clFlush(object_), __FLUSH_ERR); - } - - cl_int finish() const - { - return detail::errHandler(::clFinish(object_), __FINISH_ERR); - } - }; - -#ifdef _WIN32 - __declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; - __declspec(selectany) CommandQueue CommandQueue::default_; - __declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#else - __attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; - __attribute__((weak)) CommandQueue CommandQueue::default_; - __attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; -#endif - - inline cl_int enqueueReadBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); - } - - inline cl_int enqueueWriteBuffer( - const Buffer& buffer, - cl_bool blocking, - ::size_t offset, - ::size_t size, - const void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); - } - - inline void* enqueueMapBuffer( - const Buffer& buffer, - cl_bool blocking, - cl_map_flags flags, - ::size_t offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL, - cl_int* err = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - - void * result = ::clEnqueueMapBuffer( - queue(), buffer(), blocking, flags, offset, size, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (cl_event*)event, - &error); - - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (err != NULL) { - *err = error; - } - return result; - } - - inline cl_int enqueueUnmapMemObject( - const Memory& memory, - void* mapped_ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); - if (error != CL_SUCCESS) { - return error; - } - - cl_event tmp; - cl_int err = detail::errHandler( - ::clEnqueueUnmapMemObject( - queue(), memory(), mapped_ptr, - (events != NULL) ? (cl_uint)events->size() : 0, - (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, - (event != NULL) ? &tmp : NULL), - __ENQUEUE_UNMAP_MEM_OBJECT_ERR); - - if (event != NULL && err == CL_SUCCESS) - *event = tmp; - - return err; - } - - inline cl_int enqueueCopyBuffer( - const Buffer& src, - const Buffer& dst, - ::size_t src_offset, - ::size_t dst_offset, - ::size_t size, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); - } - - /** - * Blocking copy operation between iterators and a buffer. - */ - template< typename IteratorType > - inline cl_int copy(IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer) - { - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator - startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if (error != CL_SUCCESS) { - return error; - } -#if defined(_MSC_VER) - std::copy( - startIterator, - endIterator, - stdext::checked_array_iterator( - pointer, length)); -#else - std::copy(startIterator, endIterator, pointer); -#endif - Event endEvent; - error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if (error != CL_SUCCESS) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; - } - - /** - * Blocking copy operation between iterators and a buffer. - */ - template< typename IteratorType > - inline cl_int copy(const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator) - { - typedef typename std::iterator_traits::value_type DataType; - cl_int error; - - ::size_t length = endIterator - startIterator; - ::size_t byteLength = length*sizeof(DataType); - - DataType *pointer = - static_cast(enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); - // if exceptions enabled, enqueueMapBuffer will throw - if (error != CL_SUCCESS) { - return error; - } - std::copy(pointer, pointer + length, startIterator); - Event endEvent; - error = enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); - // if exceptions enabled, enqueueUnmapMemObject will throw - if (error != CL_SUCCESS) { - return error; - } - endEvent.wait(); - return CL_SUCCESS; - } - -#if defined(CL_VERSION_1_1) - inline cl_int enqueueReadBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); - } - - inline cl_int enqueueWriteBufferRect( - const Buffer& buffer, - cl_bool blocking, - const size_t<3>& buffer_offset, - const size_t<3>& host_offset, - const size_t<3>& region, - ::size_t buffer_row_pitch, - ::size_t buffer_slice_pitch, - ::size_t host_row_pitch, - ::size_t host_slice_pitch, - void *ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteBufferRect( - buffer, - blocking, - buffer_offset, - host_offset, - region, - buffer_row_pitch, - buffer_slice_pitch, - host_row_pitch, - host_slice_pitch, - ptr, - events, - event); - } - - inline cl_int enqueueCopyBufferRect( - const Buffer& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - ::size_t src_row_pitch, - ::size_t src_slice_pitch, - ::size_t dst_row_pitch, - ::size_t dst_slice_pitch, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferRect( - src, - dst, - src_origin, - dst_origin, - region, - src_row_pitch, - src_slice_pitch, - dst_row_pitch, - dst_slice_pitch, - events, - event); - } -#endif - - inline cl_int enqueueReadImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueReadImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); - } - - inline cl_int enqueueWriteImage( - const Image& image, - cl_bool blocking, - const size_t<3>& origin, - const size_t<3>& region, - ::size_t row_pitch, - ::size_t slice_pitch, - void* ptr, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueWriteImage( - image, - blocking, - origin, - region, - row_pitch, - slice_pitch, - ptr, - events, - event); - } - - inline cl_int enqueueCopyImage( - const Image& src, - const Image& dst, - const size_t<3>& src_origin, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImage( - src, - dst, - src_origin, - dst_origin, - region, - events, - event); - } - - inline cl_int enqueueCopyImageToBuffer( - const Image& src, - const Buffer& dst, - const size_t<3>& src_origin, - const size_t<3>& region, - ::size_t dst_offset, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyImageToBuffer( - src, - dst, - src_origin, - region, - dst_offset, - events, - event); - } - - inline cl_int enqueueCopyBufferToImage( - const Buffer& src, - const Image& dst, - ::size_t src_offset, - const size_t<3>& dst_origin, - const size_t<3>& region, - const VECTOR_CLASS* events = NULL, - Event* event = NULL) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.enqueueCopyBufferToImage( - src, - dst, - src_offset, - dst_origin, - region, - events, - event); - } - - - inline cl_int flush(void) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - return queue.flush(); - } - - inline cl_int finish(void) - { - cl_int error; - CommandQueue queue = CommandQueue::getDefault(&error); - - if (error != CL_SUCCESS) { - return error; - } - - - return queue.finish(); - } - - // Kernel Functor support - // New interface as of September 2011 - // Requires the C++11 std::tr1::function (note do not support TR1) - // Visual Studio 2010 and GCC 4.2 - - struct EnqueueArgs - { - CommandQueue queue_; - const NDRange offset_; - const NDRange global_; - const NDRange local_; - VECTOR_CLASS events_; - - EnqueueArgs(NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(Event e, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(CommandQueue::getDefault()), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local) - { - events_.push_back(e); - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(NullRange), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : - queue_(queue), - offset_(NullRange), - global_(global), - local_(local), - events_(events) - { - - } - - EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : - queue_(queue), - offset_(offset), - global_(global), - local_(local), - events_(events) - { - - } - }; - - namespace detail { - - class NullType {}; - - template - struct SetArg - { - static void set(Kernel kernel, T0 arg) - { - kernel.setArg(index, arg); - } - }; - - template - struct SetArg - { - static void set(Kernel, NullType) - { - } - }; - - template < - typename T0, typename T1, typename T2, typename T3, - typename T4, typename T5, typename T6, typename T7, - typename T8, typename T9, typename T10, typename T11, - typename T12, typename T13, typename T14, typename T15, - typename T16, typename T17, typename T18, typename T19, - typename T20, typename T21, typename T22, typename T23, - typename T24, typename T25, typename T26, typename T27, - typename T28, typename T29, typename T30, typename T31 - > - class KernelFunctorGlobal - { - private: - Kernel kernel_; - - public: - KernelFunctorGlobal( - Kernel kernel) : - kernel_(kernel) - {} - - KernelFunctorGlobal( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - kernel_(program, name.c_str(), err) - {} - - Event operator() ( - const EnqueueArgs& args, - T0 t0, - T1 t1 = NullType(), - T2 t2 = NullType(), - T3 t3 = NullType(), - T4 t4 = NullType(), - T5 t5 = NullType(), - T6 t6 = NullType(), - T7 t7 = NullType(), - T8 t8 = NullType(), - T9 t9 = NullType(), - T10 t10 = NullType(), - T11 t11 = NullType(), - T12 t12 = NullType(), - T13 t13 = NullType(), - T14 t14 = NullType(), - T15 t15 = NullType(), - T16 t16 = NullType(), - T17 t17 = NullType(), - T18 t18 = NullType(), - T19 t19 = NullType(), - T20 t20 = NullType(), - T21 t21 = NullType(), - T22 t22 = NullType(), - T23 t23 = NullType(), - T24 t24 = NullType(), - T25 t25 = NullType(), - T26 t26 = NullType(), - T27 t27 = NullType(), - T28 t28 = NullType(), - T29 t29 = NullType(), - T30 t30 = NullType(), - T31 t31 = NullType() - ) - { - Event event; - SetArg<0, T0>::set(kernel_, t0); - SetArg<1, T1>::set(kernel_, t1); - SetArg<2, T2>::set(kernel_, t2); - SetArg<3, T3>::set(kernel_, t3); - SetArg<4, T4>::set(kernel_, t4); - SetArg<5, T5>::set(kernel_, t5); - SetArg<6, T6>::set(kernel_, t6); - SetArg<7, T7>::set(kernel_, t7); - SetArg<8, T8>::set(kernel_, t8); - SetArg<9, T9>::set(kernel_, t9); - SetArg<10, T10>::set(kernel_, t10); - SetArg<11, T11>::set(kernel_, t11); - SetArg<12, T12>::set(kernel_, t12); - SetArg<13, T13>::set(kernel_, t13); - SetArg<14, T14>::set(kernel_, t14); - SetArg<15, T15>::set(kernel_, t15); - SetArg<16, T16>::set(kernel_, t16); - SetArg<17, T17>::set(kernel_, t17); - SetArg<18, T18>::set(kernel_, t18); - SetArg<19, T19>::set(kernel_, t19); - SetArg<20, T20>::set(kernel_, t20); - SetArg<21, T21>::set(kernel_, t21); - SetArg<22, T22>::set(kernel_, t22); - SetArg<23, T23>::set(kernel_, t23); - SetArg<24, T24>::set(kernel_, t24); - SetArg<25, T25>::set(kernel_, t25); - SetArg<26, T26>::set(kernel_, t26); - SetArg<27, T27>::set(kernel_, t27); - SetArg<28, T28>::set(kernel_, t28); - SetArg<29, T29>::set(kernel_, t29); - SetArg<30, T30>::set(kernel_, t30); - SetArg<31, T31>::set(kernel_, t31); - - args.queue_.enqueueNDRangeKernel( - kernel_, - args.offset_, - args.global_, - args.local_, - &args.events_, - &event); - - return event; - } - - }; - - //------------------------------------------------------------------------------------------------------ - - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30, - typename T31> - struct functionImplementation_ - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - T31); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30, - T31 arg31) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30, - arg31); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29, - typename T30> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - T30); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29, - T30 arg30) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29, - arg30); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28, - typename T29> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - T29); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28, - T29 arg29) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28, - arg29); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27, - typename T28> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - T28); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27, - T28 arg28) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27, - arg28); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26, - typename T27> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - T27); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26, - T27 arg27) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26, - arg27); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25, - typename T26> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - T26); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25, - T26 arg26) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25, - arg26); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24, - typename T25> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - T25); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24, - T25 arg25) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24, - arg25); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23, - typename T24> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - T24); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23, - T24 arg24) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23, - arg24); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22, - typename T23> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - T23); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22, - T23 arg23) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22, - arg23); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21, - typename T22> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - T22); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21, - T22 arg22) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21, - arg22); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20, - typename T21> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - T21); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20, - T21 arg21) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20, - arg21); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19, - typename T20> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - T20); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19, - T20 arg20) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19, - arg20); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18, - typename T19> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - T19); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18, - T19 arg19) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18, - arg19); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17, - typename T18> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - T18); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17, - T18 arg18) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17, - arg18); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16, - typename T17> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - T17); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16, - T17 arg17) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16, - arg17); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15, - typename T16> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - T16); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15, - T16 arg16) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15, - arg16); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14, - typename T15> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - T15); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14, - T15 arg15) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14, - arg15); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13, - typename T14> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - T14); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13, - T14 arg14) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13, - arg14); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12, - typename T13> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - T13); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12, - T13 arg13) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12, - arg13); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11, - typename T12> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11, - T12 arg12) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11, - arg12); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10, - typename T11> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10, - T11 arg11) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10, - arg11); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9, - typename T10> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9, - T10 arg10) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9, - arg10); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8, - typename T9> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8, - T9 arg9) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8, - arg9); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7, - typename T8> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7, - T8 arg8) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6, - typename T7> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6, - T7); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6, - T7 arg7) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5, - typename T6> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - T6, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5, - T6); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5, - T6 arg6) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4, - typename T5> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - T5, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4, - T5); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4, - T5 arg5) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4, - arg5); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3, - typename T4> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - T4, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3, - T4); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3, - T4 arg4) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3, - arg4); - } - - - }; - - template< - typename T0, - typename T1, - typename T2, - typename T3> - struct functionImplementation_ - < T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - T3, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2, - T3); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2, - T3 arg3) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2, - arg3); - } - - - }; - - template< - typename T0, - typename T1, - typename T2> - struct functionImplementation_ - < T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - T2, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1, - T2); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1, - T2 arg2) - { - return functor_( - enqueueArgs, - arg0, - arg1, - arg2); - } - - - }; - - template< - typename T0, - typename T1> - struct functionImplementation_ - < T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - T1, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0, - T1); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0, - T1 arg1) - { - return functor_( - enqueueArgs, - arg0, - arg1); - } - - - }; - - template< - typename T0> - struct functionImplementation_ - < T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> - { - typedef detail::KernelFunctorGlobal< - T0, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType, - NullType> FunctorType; - - FunctorType functor_; - - functionImplementation_(const FunctorType &functor) : - functor_(functor) - { - -#if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) - // Fail variadic expansion for dev11 - static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); -#endif - - } - - //! \brief Return type of the functor - typedef Event result_type; - - //! \brief Function signature of kernel functor with no event dependency. - typedef Event type_( - const EnqueueArgs&, - T0); - - Event operator()( - const EnqueueArgs& enqueueArgs, - T0 arg0) - { - return functor_( - enqueueArgs, - arg0); - } - - - }; - - - - - - } // namespace detail - - //---------------------------------------------------------------------------------------------- - - template < - typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, - typename T3 = detail::NullType, typename T4 = detail::NullType, - typename T5 = detail::NullType, typename T6 = detail::NullType, - typename T7 = detail::NullType, typename T8 = detail::NullType, - typename T9 = detail::NullType, typename T10 = detail::NullType, - typename T11 = detail::NullType, typename T12 = detail::NullType, - typename T13 = detail::NullType, typename T14 = detail::NullType, - typename T15 = detail::NullType, typename T16 = detail::NullType, - typename T17 = detail::NullType, typename T18 = detail::NullType, - typename T19 = detail::NullType, typename T20 = detail::NullType, - typename T21 = detail::NullType, typename T22 = detail::NullType, - typename T23 = detail::NullType, typename T24 = detail::NullType, - typename T25 = detail::NullType, typename T26 = detail::NullType, - typename T27 = detail::NullType, typename T28 = detail::NullType, - typename T29 = detail::NullType, typename T30 = detail::NullType, - typename T31 = detail::NullType - > - struct make_kernel : - public detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - > - { - public: - typedef detail::KernelFunctorGlobal< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - > FunctorType; - - make_kernel( - const Program& program, - const STRING_CLASS name, - cl_int * err = NULL) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - >( - FunctorType(program, name, err)) - {} - - make_kernel( - const Kernel kernel) : - detail::functionImplementation_< - T0, T1, T2, T3, - T4, T5, T6, T7, - T8, T9, T10, T11, - T12, T13, T14, T15, - T16, T17, T18, T19, - T20, T21, T22, T23, - T24, T25, T26, T27, - T28, T29, T30, T31 - >( - FunctorType(kernel)) - {} - }; - - - //---------------------------------------------------------------------------------------------------------------------- - -#undef __ERR_STR -#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) -#undef __GET_DEVICE_INFO_ERR -#undef __GET_PLATFORM_INFO_ERR -#undef __GET_DEVICE_IDS_ERR -#undef __GET_CONTEXT_INFO_ERR -#undef __GET_EVENT_INFO_ERR -#undef __GET_EVENT_PROFILE_INFO_ERR -#undef __GET_MEM_OBJECT_INFO_ERR -#undef __GET_IMAGE_INFO_ERR -#undef __GET_SAMPLER_INFO_ERR -#undef __GET_KERNEL_INFO_ERR -#undef __GET_KERNEL_ARG_INFO_ERR -#undef __GET_KERNEL_WORK_GROUP_INFO_ERR -#undef __GET_PROGRAM_INFO_ERR -#undef __GET_PROGRAM_BUILD_INFO_ERR -#undef __GET_COMMAND_QUEUE_INFO_ERR - -#undef __CREATE_CONTEXT_ERR -#undef __CREATE_CONTEXT_FROM_TYPE_ERR -#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR - -#undef __CREATE_BUFFER_ERR -#undef __CREATE_SUBBUFFER_ERR -#undef __CREATE_IMAGE2D_ERR -#undef __CREATE_IMAGE3D_ERR -#undef __CREATE_SAMPLER_ERR -#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR - -#undef __CREATE_USER_EVENT_ERR -#undef __SET_USER_EVENT_STATUS_ERR -#undef __SET_EVENT_CALLBACK_ERR -#undef __SET_PRINTF_CALLBACK_ERR - -#undef __WAIT_FOR_EVENTS_ERR - -#undef __CREATE_KERNEL_ERR -#undef __SET_KERNEL_ARGS_ERR -#undef __CREATE_PROGRAM_WITH_SOURCE_ERR -#undef __CREATE_PROGRAM_WITH_BINARY_ERR -#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR -#undef __BUILD_PROGRAM_ERR -#undef __CREATE_KERNELS_IN_PROGRAM_ERR - -#undef __CREATE_COMMAND_QUEUE_ERR -#undef __SET_COMMAND_QUEUE_PROPERTY_ERR -#undef __ENQUEUE_READ_BUFFER_ERR -#undef __ENQUEUE_WRITE_BUFFER_ERR -#undef __ENQUEUE_READ_BUFFER_RECT_ERR -#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR -#undef __ENQEUE_COPY_BUFFER_ERR -#undef __ENQEUE_COPY_BUFFER_RECT_ERR -#undef __ENQUEUE_READ_IMAGE_ERR -#undef __ENQUEUE_WRITE_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_ERR -#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR -#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR -#undef __ENQUEUE_MAP_BUFFER_ERR -#undef __ENQUEUE_MAP_IMAGE_ERR -#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR -#undef __ENQUEUE_NDRANGE_KERNEL_ERR -#undef __ENQUEUE_TASK_ERR -#undef __ENQUEUE_NATIVE_KERNEL - -#undef __CL_EXPLICIT_CONSTRUCTORS - -#undef __UNLOAD_COMPILER_ERR -#endif //__CL_USER_OVERRIDE_ERROR_STRINGS - -#undef __CL_FUNCTION_TYPE - - // Extensions - /** - * Deprecated APIs for 1.2 - */ -#if defined(CL_VERSION_1_1) -#undef __INIT_CL_EXT_FCN_PTR -#endif // #if defined(CL_VERSION_1_1) -#undef __CREATE_SUB_DEVICES - -#if defined(USE_CL_DEVICE_FISSION) -#undef __PARAM_NAME_DEVICE_FISSION -#endif // USE_CL_DEVICE_FISSION - -#undef __DEFAULT_NOT_INITIALIZED -#undef __DEFAULT_BEING_INITIALIZED -#undef __DEFAULT_INITIALIZED - -} // namespace cl - -#ifdef _WIN32 -#pragma pop_macro("max") -#endif // _WIN32 - -#endif // CL_HPP_ diff --git a/ocl_device_utils/ocl_device_utils.cpp b/ocl_device_utils/ocl_device_utils.cpp deleted file mode 100644 index f7a802d00..000000000 --- a/ocl_device_utils/ocl_device_utils.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "ocl_device_utils.h" - -#include -#include -#include -#include - -using namespace std; -using namespace cl; - - -bool ocl_device_utils::_hasQueried = false; -std::vector ocl_device_utils::_platformNames; -std::vector ocl_device_utils::_devicesPlatformsDevices; - -vector ocl_device_utils::getPlatforms() { - vector platforms; - try { - Platform::get(&platforms); - } - catch (Error const& err) { -#if defined(CL_PLATFORM_NOT_FOUND_KHR) - if (err.err() == CL_PLATFORM_NOT_FOUND_KHR) - cout << "No OpenCL platforms found" << endl; - else -#endif - throw err; - } - return platforms; -} - -void ocl_device_utils::print_opencl_devices() { - ocl_device_utils::QueryDevices(); - ocl_device_utils::PrintDevices(); -} - -vector ocl_device_utils::getDevices(vector const& _platforms, unsigned _platformId) { - vector devices; - try { - _platforms[_platformId].getDevices(/*CL_DEVICE_TYPE_CPU| */CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR, &devices); - } - catch (Error const& err) { - // if simply no devices found return empty vector - if (err.err() != CL_DEVICE_NOT_FOUND) - throw err; - } - return devices; -} - -string ocl_device_utils::StringnNullTerminatorFix(const string& str) { - return string(str.c_str(), strlen(str.c_str())); -} - -bool ocl_device_utils::QueryDevices() { - if (!_hasQueried) { - _hasQueried = true; - try { - // get platforms - auto platforms = getPlatforms(); - if (platforms.empty()) { - cout << "No OpenCL platforms found" << endl; - return false; - } - else { - for (auto i_pId = 0u; i_pId < platforms.size(); ++i_pId) { - string platformName = StringnNullTerminatorFix(platforms[i_pId].getInfo()); - if (std::find(_platformNames.begin(), _platformNames.end(), platformName) == _platformNames.end()) { - PrintInfo current; - _platformNames.push_back(platformName); - // new - current.PlatformName = platformName; - current.PlatformNum = i_pId; - - auto clDevs = getDevices(platforms, i_pId); - for (auto i_devId = 0u; i_devId < clDevs.size(); ++i_devId) { - OpenCLDevice curDevice; - curDevice.DeviceID = i_devId; - curDevice._CL_DEVICE_NAME = StringnNullTerminatorFix(clDevs[i_devId].getInfo()); - switch (clDevs[i_devId].getInfo()) { - case CL_DEVICE_TYPE_CPU: - curDevice._CL_DEVICE_TYPE = "CPU"; - break; - case CL_DEVICE_TYPE_GPU: - curDevice._CL_DEVICE_TYPE = "GPU"; - break; - case CL_DEVICE_TYPE_ACCELERATOR: - curDevice._CL_DEVICE_TYPE = "ACCELERATOR"; - break; - default: - curDevice._CL_DEVICE_TYPE = "DEFAULT"; - break; - } - - - curDevice._CL_DEVICE_GLOBAL_MEM_SIZE = clDevs[i_devId].getInfo(); - curDevice._CL_DEVICE_VENDOR = StringnNullTerminatorFix(clDevs[i_devId].getInfo()); - curDevice._CL_DEVICE_VERSION = StringnNullTerminatorFix(clDevs[i_devId].getInfo()); - curDevice._CL_DRIVER_VERSION = StringnNullTerminatorFix(clDevs[i_devId].getInfo()); - - current.Devices.push_back(curDevice); - } - _devicesPlatformsDevices.push_back(current); - } - } - } - } - catch (exception &ex) { - // TODO - cout << "ocl_device_utils::QueryDevices() exception: " << ex.what() << endl; - return false; - } - return true; - } - - return false; -} - -int ocl_device_utils::GetCountForPlatform(int platformID) { - for (const auto &platInfo : _devicesPlatformsDevices) - { - if (platformID == platInfo.PlatformNum) { - return platInfo.Devices.size(); - } - } - return 0; -} - -void ocl_device_utils::PrintDevices() { - int allDevsCount = 0; - for (const auto &platInfo : _devicesPlatformsDevices) { - allDevsCount += platInfo.Devices.size(); - } - cout << "Number of OpenCL devices found: " << allDevsCount << endl; - { - int devPlatformsComma = _devicesPlatformsDevices.size(); - for (const auto &platInfo : _devicesPlatformsDevices) { - cout << "\tPlatform: " << platInfo.PlatformName << " | " << "PlatformNum: " << platInfo.PlatformNum << endl; - cout << "\t\tDevices: " << endl; - // device print - int devComma = platInfo.Devices.size(); - for (const auto &dev : platInfo.Devices) { - cout << "\t\t\t#" << dev.DeviceID << " " << dev._CL_DEVICE_NAME << " | " << dev._CL_DEVICE_TYPE << endl; - } - } - } -} \ No newline at end of file diff --git a/ocl_device_utils/ocl_device_utils.h b/ocl_device_utils/ocl_device_utils.h deleted file mode 100644 index cf74aaf2b..000000000 --- a/ocl_device_utils/ocl_device_utils.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#define __CL_ENABLE_EXCEPTIONS -#define CL_USE_DEPRECATED_OPENCL_2_0_APIS - -#include "cl_ext.hpp" -#include -#include -#include "OpenCLDevice.h" - - -struct PrintInfo { - std::string PlatformName; - int PlatformNum; - std::vector Devices; -}; - -class ocl_device_utils { -public: - static bool QueryDevices(); - static void PrintDevices(); - static int GetCountForPlatform(int platformID); - static void print_opencl_devices(); - -private: - static std::vector getDevices(std::vector const& _platforms, unsigned _platformId); - static std::vector getPlatforms(); - - static bool _hasQueried; - static std::vector _platformNames; - static std::vector _devicesPlatformsDevices; - - static std::string StringnNullTerminatorFix(const std::string& str); -}; \ No newline at end of file diff --git a/ocl_device_utils/ocl_device_utils.vcxproj b/ocl_device_utils/ocl_device_utils.vcxproj deleted file mode 100644 index 4830defa1..000000000 --- a/ocl_device_utils/ocl_device_utils.vcxproj +++ /dev/null @@ -1,95 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - {5DBCE38A-C8D2-4498-A92A-9AF8D5196135} - Win32Proj - ocl_device_utils - - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - $(AMDAPPSDKROOT)\include\ - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - $(AMDAPPSDKROOT)\include\;%(AdditionalIncludeDirectories) - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/ocl_device_utils/ocl_device_utils.vcxproj.filters b/ocl_device_utils/ocl_device_utils.vcxproj.filters deleted file mode 100644 index 1c4a6cd21..000000000 --- a/ocl_device_utils/ocl_device_utils.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/ocl_device_utils/opencl.cpp b/ocl_device_utils/opencl.cpp deleted file mode 100644 index cea4c9082..000000000 --- a/ocl_device_utils/opencl.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "opencl.h" -#include -#include -#include -#include - -extern cl_platform_id gPlatform; -// extern cl_program gProgram; - -bool clInitialize(int requiredPlatform, std::vector &gpus) -{ - cl_platform_id platforms[64]; - cl_uint numPlatforms; - OCLR(clGetPlatformIDs(sizeof(platforms)/sizeof(cl_platform_id), platforms, &numPlatforms), false); - if (!numPlatforms) { - printf(" no OpenCL platforms found\n"); - return false; - } - - /*int platformIdx = -1; - if (requiredPlatform) { - for (decltype(numPlatforms) i = 0; i < numPlatforms; i++) { - char name[1024] = {0}; - OCLR(clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, sizeof(name), name, 0), false); - printf("found platform[%i] name = '%s'\n", (int)i, name); - if (strcmp(name, requiredPlatform) == 0) { - platformIdx = i; - break; - } - } - } else { - platformIdx = 0; - }*/ - - int platformIdx = requiredPlatform; - - - if (platformIdx == -1) { - printf(" platform %s not exists\n", requiredPlatform); - return false; - } - - gPlatform = platforms[platformIdx]; - - cl_uint numDevices = 0; - cl_device_id devices[64]; - clGetDeviceIDs(gPlatform, CL_DEVICE_TYPE_GPU, sizeof(devices)/sizeof(cl_device_id), devices, &numDevices); - if (numDevices) { - printf(" found %d devices\n", numDevices); - } else { - printf(" no OpenCL GPU devices found.\n"); - return false; - } - - for (decltype(numDevices) i = 0; i < numDevices; i++) { - gpus.push_back(devices[i]); - } - - return true; -} - -bool clCompileKernel(cl_context gContext, - cl_device_id gpu, - const char *binaryName, - const std::vector &sources, - const char *arguments, - cl_int *binstatus, - cl_program *gProgram) -{ - std::ifstream testfile(binaryName); - -// size_t binsizes[64]; - -// const unsigned char *binaries[64]; - - if(!testfile) { - - - printf(" compiling ...\n"); - - std::string sourceFile; - for (auto &i: sources) { - std::ifstream stream; - stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); - try { - stream.open(i); - } catch (std::system_error& e) { - fprintf(stderr, " %s\n", e.code().message().c_str()); - return false; - } - std::string str((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); - sourceFile.append(str); - } - - printf(" source: %u bytes\n", (unsigned)sourceFile.size()); - if(sourceFile.size() < 1){ - fprintf(stderr, " source files not found or empty\n"); - return false; - } - - cl_int error; - const char *sources[] = { sourceFile.c_str(), 0 }; - *gProgram = clCreateProgramWithSource(gContext, 1, sources, 0, &error); - OCLR(error, false); - - if (clBuildProgram(*gProgram, 1, &gpu, arguments, 0, 0) != CL_SUCCESS) { - size_t logSize; - clGetProgramBuildInfo(*gProgram, gpu, CL_PROGRAM_BUILD_LOG, 0, 0, &logSize); - - std::unique_ptr log(new char[logSize]); - clGetProgramBuildInfo(*gProgram, gpu, CL_PROGRAM_BUILD_LOG, logSize, log.get(), 0); - printf("%s\n", log.get()); - - return false; - } - - size_t binsize; - OCLR(clGetProgramInfo(*gProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binsize, 0), false); -// for (size_t i = 0; i < 1; i++) { - if(!binsize) { - printf(" no binary available!\n"); - return false; - } -// } - - printf(" binsize = %u bytes\n", (unsigned)binsize); -// std::unique_ptr binary(new unsigned char[binsize+1]); - -// for (size_t i = 0; i < gpus.size(); i++) - std::unique_ptr binary(new unsigned char[binsize+1]); -// binaries[i] = new unsigned char[binsizes[i]]; - -// for (auto &b: binaries) -// b = binary.get(); - OCLR(clGetProgramInfo(*gProgram, CL_PROGRAM_BINARIES, sizeof(void*), &binary, 0), false); - - { - std::ofstream bin(binaryName, std::ofstream::binary | std::ofstream::trunc); - bin.write((const char*)binary.get(), binsize); - bin.close(); - } - - OCLR(clReleaseProgram(*gProgram), false); - } - - std::ifstream bfile(binaryName, std::ifstream::binary); - if(!bfile) { - printf(" %s not found\n", binaryName); - return false; - } - - bfile.seekg(0, bfile.end); - size_t binsize = bfile.tellg(); - bfile.seekg(0, bfile.beg); - if(!binsize){ - printf(" %s empty\n", binaryName); - return false; - } - - std::vector binary(binsize+1); - bfile.read(&binary[0], binsize); - bfile.close(); - - cl_int error; -// binstatus.resize(gpus.size(), 0); -// std::vector binsizes(gpus.size(), binsize); -// std::vector binaries(gpus.size(), (const unsigned char*)&binary[0]); - const unsigned char *binaryPtr = (const unsigned char*)&binary[0]; - - *gProgram = clCreateProgramWithBinary(gContext, 1, &gpu, &binsize, &binaryPtr, binstatus, &error); - OCLR(error, false); - OCLR(clBuildProgram(*gProgram, 1, &gpu, 0, 0, 0), false); - return true; -} diff --git a/ocl_device_utils/opencl.h b/ocl_device_utils/opencl.h deleted file mode 100644 index 566d9ffa2..000000000 --- a/ocl_device_utils/opencl.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * opencl.h - * - * Created on: 01.05.2014 - * Author: mad - */ - -#ifndef OPENCL_H_ -#define OPENCL_H_ - -#pragma warning(disable: 4996) -#include -#include -#include -#include - -// extern cl_context gContext; - - - -#define OCL(error) \ - if(cl_int err = error){ \ - printf("OpenCL error: %d at %s:%d\n", err, __FILE__, __LINE__); \ - return; \ - } - -#define OCLR(error, ret) \ - if(cl_int err = error){ \ - printf("OpenCL error: %d at %s:%d\n", err, __FILE__, __LINE__); \ - return ret; \ - } - -#define OCLE(error) \ - if(cl_int err = error){ \ - printf("OpenCL error: %d at %s:%d\n", err, __FILE__, __LINE__); \ - exit(err); \ - } - - - - - -template -class clBuffer { -public: - - clBuffer() { - - Size = 0; - HostData = 0; - DeviceData = 0; - - } - - ~clBuffer() { - - if(HostData) - delete [] HostData; - - if(DeviceData) - clReleaseMemObject(DeviceData); - - } - - void init(cl_context gContext, int size, cl_mem_flags flags = 0) { - - Size = size; - - if(!(flags & CL_MEM_HOST_NO_ACCESS)){ - HostData = new T[Size]; - memset(HostData, 0, Size*sizeof(T)); - }else - HostData = 0; - - //printf("clCreateBuffer: size = %d, %d bytes\n", Size, Size*sizeof(T)); - - cl_int error; - if (flags & CL_MEM_HOST_NO_ACCESS) - flags = CL_MEM_READ_WRITE; - DeviceData = clCreateBuffer(gContext, flags, Size*sizeof(T), 0, &error); - OCL(error); - - } - - void copyToDevice(cl_command_queue cq, bool blocking = true) { - - OCL(clEnqueueWriteBuffer(cq, DeviceData, blocking, 0, Size*sizeof(T), HostData, 0, 0, 0)); - - } - - void copyToHost(cl_command_queue cq, bool blocking = true, unsigned size = 0) { - - if(size == 0) - size = Size; - - OCL(clEnqueueReadBuffer(cq, DeviceData, blocking, 0, size*sizeof(T), HostData, 0, 0, 0)); - - } - - T& get(int index) { - return HostData[index]; - } - - T& operator[](int index) { - return HostData[index]; - } - -public: - - int Size; - T* HostData; - cl_mem DeviceData; - - -}; - - -bool clInitialize(int requiredPlatform, std::vector &gpus); -bool clCompileKernel(cl_context gContext, - cl_device_id gpu, - const char *binaryName, - const std::vector &sources, - const char *arguments, - cl_int *binstatus, - cl_program *gProgram); - - - - - -#endif /* OPENCL_H_ */ diff --git a/ocl_silentarmy/ocl_silentarmy.cpp b/ocl_silentarmy/ocl_silentarmy.cpp deleted file mode 100644 index d67a3fa76..000000000 --- a/ocl_silentarmy/ocl_silentarmy.cpp +++ /dev/null @@ -1,536 +0,0 @@ -#include "ocl_silentarmy.hpp" - -//#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -//#include -//#include -#include - - -#include "opencl.h" - -#include - -#include "sa_blake.h" - -typedef uint8_t uchar; -typedef uint32_t uint; -typedef uint64_t ulong; -#include "param.h" - -#define MIN(A, B) (((A) < (B)) ? (A) : (B)) -#define MAX(A, B) (((A) > (B)) ? (A) : (B)) - -#define WN PARAM_N -#define WK PARAM_K - -#define COLLISION_BIT_LENGTH (WN / (WK+1)) -#define COLLISION_BYTE_LENGTH ((COLLISION_BIT_LENGTH+7)/8) -#define FINAL_FULL_WIDTH (2*COLLISION_BYTE_LENGTH+sizeof(uint32_t)*(1 << (WK))) - -#define NDIGITS (WK+1) -#define DIGITBITS (WN/(NDIGITS)) -#define PROOFSIZE (1u<= '0' && c <= '9') return c - '0'; - else if (c >= 'a' && c <= 'f') return 10 + c - 'a'; - else if (c >= 'A' && c <= 'F') return 10 + c - 'A'; - printf("Invalid hex char at offset %zd: ...%c...\n", off, c); - return 0; -} - -unsigned nr_compute_units(const char *gpu) -{ - if (!strcmp(gpu, "rx480")) return 36; - fprintf(stderr, "Unknown GPU: %s\n", gpu); - return 0; -} - -static void compress(uint8_t *out, uint32_t *inputs, uint32_t n) -{ - uint32_t byte_pos = 0; - int32_t bits_left = PREFIX + 1; - uint8_t x = 0; - uint8_t x_bits_used = 0; - uint8_t *pOut = out; - while (byte_pos < n) - { - if (bits_left >= 8 - x_bits_used) - { - x |= inputs[byte_pos] >> (bits_left - 8 + x_bits_used); - bits_left -= 8 - x_bits_used; - x_bits_used = 8; - } - else if (bits_left > 0) - { - uint32_t mask = ~(-1 << (8 - x_bits_used)); - mask = ((~mask) >> bits_left) & mask; - x |= (inputs[byte_pos] << (8 - x_bits_used - bits_left)) & mask; - x_bits_used += bits_left; - bits_left = 0; - } - else if (bits_left <= 0) - { - assert(!bits_left); - byte_pos++; - bits_left = PREFIX + 1; - } - if (x_bits_used == 8) - { - *pOut++ = x; - x = x_bits_used = 0; - } - } -} - -void get_program_build_log(cl_program program, cl_device_id device) -{ - cl_int status; - char val[2 * 1024 * 1024]; - size_t ret = 0; - status = clGetProgramBuildInfo(program, device, - CL_PROGRAM_BUILD_LOG, - sizeof(val), // size_t param_value_size - &val, // void *param_value - &ret); // size_t *param_value_size_ret - if (status != CL_SUCCESS) - printf("clGetProgramBuildInfo (%d)\n", status); - fprintf(stderr, "%s\n", val); -} - -size_t select_work_size_blake(void) -{ - size_t work_size = - 64 * /* thread per wavefront */ - BLAKE_WPS * /* wavefront per simd */ - 4 * /* simd per compute unit */ - nr_compute_units("rx480"); - // Make the work group size a multiple of the nr of wavefronts, while - // dividing the number of inputs. This results in the worksize being a - // power of 2. - while (NR_INPUTS % work_size) - work_size += 64; - //debug("Blake: work size %zd\n", work_size); - return work_size; -} - -static void init_ht(cl_command_queue queue, cl_kernel k_init_ht, cl_mem buf_ht) -{ - size_t global_ws = NR_ROWS; - size_t local_ws = 64; - cl_int status; -#if 0 - uint32_t pat = -1; - status = clEnqueueFillBuffer(queue, buf_ht, &pat, sizeof(pat), 0, - NR_ROWS * NR_SLOTS * SLOT_LEN, - 0, // cl_uint num_events_in_wait_list - NULL, // cl_event *event_wait_list - NULL); // cl_event *event - if (status != CL_SUCCESS) - fatal("clEnqueueFillBuffer (%d)\n", status); -#endif - status = clSetKernelArg(k_init_ht, 0, sizeof(buf_ht), &buf_ht); - if (status != CL_SUCCESS) - printf("clSetKernelArg (%d)\n", status); - check_clEnqueueNDRangeKernel(queue, k_init_ht, - 1, // cl_uint work_dim - NULL, // size_t *global_work_offset - &global_ws, // size_t *global_work_size - &local_ws, // size_t *local_work_size - 0, // cl_uint num_events_in_wait_list - NULL, // cl_event *event_wait_list - NULL); // cl_event *event -} - - -/* -** Sort a pair of binary blobs (a, b) which are consecutive in memory and -** occupy a total of 2*len 32-bit words. -** -** a points to the pair -** len number of 32-bit words in each pair -*/ -void sort_pair(uint32_t *a, uint32_t len) -{ - uint32_t *b = a + len; - uint32_t tmp, need_sorting = 0; - for (uint32_t i = 0; i < len; i++) - if (need_sorting || a[i] > b[i]) - { - need_sorting = 1; - tmp = a[i]; - a[i] = b[i]; - b[i] = tmp; - } - else if (a[i] < b[i]) - return; -} -static uint32_t verify_sol(sols_t *sols, unsigned sol_i) -{ - uint32_t *inputs = sols->values[sol_i]; - uint32_t seen_len = (1 << (PREFIX + 1)) / 8; - uint8_t seen[(1 << (PREFIX + 1)) / 8]; - uint32_t i; - uint8_t tmp; - // look for duplicate inputs - memset(seen, 0, seen_len); - for (i = 0; i < (1 << PARAM_K); i++) - { - tmp = seen[inputs[i] / 8]; - seen[inputs[i] / 8] |= 1 << (inputs[i] & 7); - if (tmp == seen[inputs[i] / 8]) - { - // at least one input value is a duplicate - sols->valid[sol_i] = 0; - return 0; - } - } - // the valid flag is already set by the GPU, but set it again because - // I plan to change the GPU code to not set it - sols->valid[sol_i] = 1; - // sort the pairs in place - for (uint32_t level = 0; level < PARAM_K; level++) - for (i = 0; i < (1 << PARAM_K); i += (2 << level)) - sort_pair(&inputs[i], 1 << level); - return 1; -} - - - -ocl_silentarmy::ocl_silentarmy(int platf_id, int dev_id) { - platform_id = platf_id; - device_id = dev_id; - // TODO - threadsNum = 8192; - wokrsize = 128; // 256; -} - -std::string ocl_silentarmy::getdevinfo() { - /*TODO get name*/ - return "GPU_ID(" + std::to_string(device_id)+ ")"; -} - -// STATICS START -int ocl_silentarmy::getcount() { /*TODO*/ - return 0; -} - -void ocl_silentarmy::getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version) { /*TODO*/ } - -void ocl_silentarmy::start(ocl_silentarmy& device_context) { - /*TODO*/ - device_context.is_init_success = false; - device_context.oclc = new OclContext(); - - std::vector allGpus; - if (!clInitialize(device_context.platform_id, allGpus)) { - return; - } - - // this is kinda stupid but it works - std::vector gpus; - for (unsigned i = 0; i < allGpus.size(); ++i) { - if (i == device_context.device_id) { - printf("Using device %d as GPU %d\n", i, (int)gpus.size()); - device_context.oclc->_dev_id = allGpus[i]; - gpus.push_back(allGpus[i]); - } - } - - if (!gpus.size()){ - printf("Device id %d not found\n", device_context.device_id); - return; - } - - // context create - for (unsigned i = 0; i < gpus.size(); i++) { - cl_context_properties props[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)device_context.oclc->platform_id, 0 }; - cl_int error; - device_context.oclc->_context = clCreateContext(NULL, 1, &gpus[i], 0, 0, &error); - //OCLR(error, false); - if (cl_int err = error) { - printf("OpenCL error: %d at %s:%d\n", err, __FILE__, __LINE__); - return; - } - } - - std::vector binstatus; - binstatus.resize(gpus.size()); - - for (size_t i = 0; i < gpus.size(); i++) { - char kernelName[64]; - sprintf(kernelName, "silentarmy_gpu%u.bin", (unsigned)i); - if (!clCompileKernel(device_context.oclc->_context, - gpus[i], - kernelName, - { "zcash/gpu/kernel.cl" }, - "", - &binstatus[i], - &device_context.oclc->_program)) { - return; - } - } - - for (unsigned i = 0; i < gpus.size(); ++i) { - if (binstatus[i] == CL_SUCCESS) { - if (!device_context.oclc->init(gpus[i], device_context.threadsNum, device_context.wokrsize)) { - printf("Init failed"); - return; - } - } - else { - printf("GPU %d: failed to load kernel\n", i); - return; - } - } - - device_context.is_init_success = true; -} - -void ocl_silentarmy::stop(ocl_silentarmy& device_context) { - if (device_context.oclc != nullptr) delete device_context.oclc; -} - -void ocl_silentarmy::solve(const char *tequihash_header, - unsigned int tequihash_header_len, - const char* nonce, - unsigned int nonce_len, - std::function cancelf, - std::function&, size_t, const unsigned char*)> solutionf, - std::function hashdonef, - ocl_silentarmy& device_context) { - - unsigned char context[140]; - memset(context, 0, 140); - memcpy(context, tequihash_header, tequihash_header_len); - memcpy(context + tequihash_header_len, nonce, nonce_len); - - OclContext *miner = device_context.oclc; - clFlush(miner->queue); - - blake2b_state_t initialCtx; - zcash_blake2b_init(&initialCtx, ZCASH_HASH_LEN, PARAM_N, PARAM_K); - zcash_blake2b_update(&initialCtx, (const uint8_t*)context, 128, 0); - - cl_mem buf_blake_st; - buf_blake_st = check_clCreateBuffer(miner->_context, CL_MEM_READ_ONLY | - CL_MEM_COPY_HOST_PTR, sizeof(blake2b_state_s), &initialCtx); - - - for (unsigned round = 0; round < PARAM_K; round++) - { - if (round < 2) - init_ht(miner->queue, miner->k_init_ht, miner->buf_ht[round % 2]); - if (!round) - { - check_clSetKernelArg(miner->k_rounds[round], 0, &buf_blake_st); - check_clSetKernelArg(miner->k_rounds[round], 1, &miner->buf_ht[round % 2]); - miner->global_ws = select_work_size_blake(); - } - else - { - check_clSetKernelArg(miner->k_rounds[round], 0, &miner->buf_ht[(round - 1) % 2]); - check_clSetKernelArg(miner->k_rounds[round], 1, &miner->buf_ht[round % 2]); - miner->global_ws = NR_ROWS; - } - check_clSetKernelArg(miner->k_rounds[round], 2, &miner->buf_dbg); - if (round == PARAM_K - 1) - check_clSetKernelArg(miner->k_rounds[round], 3, &miner->buf_sols); - check_clEnqueueNDRangeKernel(miner->queue, miner->k_rounds[round], 1, NULL, - &miner->global_ws, &miner->local_work_size, 0, NULL, NULL); - // cancel function - if (cancelf()) return; - } - check_clSetKernelArg(miner->k_sols, 0, &miner->buf_ht[0]); - check_clSetKernelArg(miner->k_sols, 1, &miner->buf_ht[1]); - check_clSetKernelArg(miner->k_sols, 2, &miner->buf_sols); - miner->global_ws = NR_ROWS; - check_clEnqueueNDRangeKernel(miner->queue, miner->k_sols, 1, NULL, - &miner->global_ws, &miner->local_work_size, 0, NULL, NULL); - - check_clEnqueueReadBuffer(miner->queue, miner->buf_sols, - CL_TRUE, // cl_bool blocking_read - 0, // size_t offset - sizeof(*miner->sols), // size_t size - miner->sols, // void *ptr - 0, // cl_uint num_events_in_wait_list - NULL, // cl_event *event_wait_list - NULL); // cl_event *event - - if (miner->sols->nr > MAX_SOLS) - miner->sols->nr = MAX_SOLS; - - clReleaseMemObject(buf_blake_st); - - for (unsigned sol_i = 0; sol_i < miner->sols->nr; sol_i++) { - verify_sol(miner->sols, sol_i); - } - - uint8_t proof[COMPRESSED_PROOFSIZE * 2]; - for (uint32_t i = 0; i < miner->sols->nr; i++) { - if (miner->sols->valid[i]) { - compress(proof, (uint32_t *)(miner->sols->values[i]), 1 << PARAM_K); - solutionf(std::vector(0), 1344, proof); - } - } - hashdonef(); -} - -// STATICS END - diff --git a/ocl_silentarmy/ocl_silentarmy.hpp b/ocl_silentarmy/ocl_silentarmy.hpp deleted file mode 100644 index 4740ac8b5..000000000 --- a/ocl_silentarmy/ocl_silentarmy.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#ifdef _LIB -#define DLL_OCL_SILENTARMY __declspec(dllexport) -#else -#define DLL_OCL_SILENTARMY -#endif - -// remove after -#include -#include -#include -#include - -struct OclContext; - - - -struct DLL_OCL_SILENTARMY ocl_silentarmy -{ - //int threadsperblock; - int blocks; - int device_id; - int platform_id; - - OclContext* oclc; - // threads - unsigned threadsNum; // TMP - unsigned wokrsize; - - bool is_init_success = false; - - ocl_silentarmy(int platf_id, int dev_id); - - std::string getdevinfo(); - - static int getcount(); - - static void getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version); - - static void start(ocl_silentarmy& device_context); - - static void stop(ocl_silentarmy& device_context); - - static void solve(const char *tequihash_header, - unsigned int tequihash_header_len, - const char* nonce, - unsigned int nonce_len, - std::function cancelf, - std::function&, size_t, const unsigned char*)> solutionf, - std::function hashdonef, - ocl_silentarmy& device_context); - - std::string getname() { return "OCL_SILENTARMY"; } - -private: - std::string m_gpu_name; - std::string m_version; -}; \ No newline at end of file diff --git a/ocl_silentarmy/ocl_silentarmy.vcxproj b/ocl_silentarmy/ocl_silentarmy.vcxproj deleted file mode 100644 index 1aae0f6ca..000000000 --- a/ocl_silentarmy/ocl_silentarmy.vcxproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - - - - {AB01E715-795A-4089-8DF0-AE6EBDC1AB48} - Win32Proj - ocl_silentarmy - - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - - - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - - - - - - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - ..\ocl_device_utils;$(AMDAPPSDKROOT)\include\;%(AdditionalIncludeDirectories) - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\ocl_device_utils;$(AMDAPPSDKROOT)\include\;%(AdditionalIncludeDirectories) - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/ocl_silentarmy/ocl_silentarmy.vcxproj.filters b/ocl_silentarmy/ocl_silentarmy.vcxproj.filters deleted file mode 100644 index 9659f2c07..000000000 --- a/ocl_silentarmy/ocl_silentarmy.vcxproj.filters +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - {34381c66-ca5c-4daa-aa30-58dcf33e2d66} - - - {c7687099-e206-4d36-8836-f7032bffc7da} - - - - - zcash\gpu - - - zcash\gpu - - - \ No newline at end of file diff --git a/ocl_silentarmy/param.h b/ocl_silentarmy/param.h deleted file mode 100644 index 51ef42ea9..000000000 --- a/ocl_silentarmy/param.h +++ /dev/null @@ -1,66 +0,0 @@ -#define PARAM_N 200 -#define PARAM_K 9 -#define PREFIX (PARAM_N / (PARAM_K + 1)) -#define NR_INPUTS (1 << PREFIX) -// Approximate log base 2 of number of elements in hash tables -#define APX_NR_ELMS_LOG (PREFIX + 1) -// Number of rows and slots is affected by this. 20 offers the best performance -// but occasionally misses ~1% of solutions. -#define NR_ROWS_LOG 20 - -// Make hash tables OVERHEAD times larger than necessary to store the average -// number of elements per row. The ideal value is as small as possible to -// reduce memory usage, but not too small or else elements are dropped from the -// hash tables. -// -// The actual number of elements per row is closer to the theoretical average -// (less variance) when NR_ROWS_LOG is small. So accordingly OVERHEAD can be -// smaller. -// -// Even (as opposed to odd) values of OVERHEAD sometimes significantly decrease -// performance as they cause VRAM channel conflicts. -#if NR_ROWS_LOG == 16 -#define OVERHEAD 3 -#elif NR_ROWS_LOG == 18 -#define OVERHEAD 5 -#elif NR_ROWS_LOG == 19 -#define OVERHEAD 9 -#elif NR_ROWS_LOG == 20 -#define OVERHEAD 13 -#endif - -#define NR_ROWS (1 << NR_ROWS_LOG) -#define NR_SLOTS ((1 << (APX_NR_ELMS_LOG - NR_ROWS_LOG)) * OVERHEAD) -// Length of 1 element (slot) in bytes -#define SLOT_LEN 32 -// Total size of hash table -#define HT_SIZE (NR_ROWS * NR_SLOTS * SLOT_LEN) -// Length of Zcash block header and nonce -#define ZCASH_BLOCK_HEADER_LEN 140 -#define ZCASH_NONCE_LEN 32 -// Number of bytes Zcash needs out of Blake -#define ZCASH_HASH_LEN 50 -// Number of wavefronts per SIMD for the Blake kernel. -// Blake is ALU-bound (beside the atomic counter being incremented) so we need -// at least 2 wavefronts per SIMD to hide the 2-clock latency of integer -// instructions. 10 is the max supported by the hw. -#define BLAKE_WPS 10 -#define MAX_SOLS 2000 - -// Optional features -#undef ENABLE_DEBUG - -/* -** Return the offset of Xi in bytes from the beginning of the slot. -*/ -#define xi_offset_for_round(round) (8 + ((round) / 2) * 4) - -// An (uncompressed) solution stores (1 << PARAM_K) 32-bit values -#define SOL_SIZE ((1 << PARAM_K) * 4) -typedef struct sols_s -{ - uint nr; - uint likely_invalids; - uchar valid[MAX_SOLS]; - uint values[MAX_SOLS][(1 << PARAM_K)]; -} sols_t; diff --git a/ocl_silentarmy/sa_blake.cpp b/ocl_silentarmy/sa_blake.cpp deleted file mode 100644 index c10800de8..000000000 --- a/ocl_silentarmy/sa_blake.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include "sa_blake.h" - -static const uint32_t blake2b_block_len = 128; -static const uint32_t blake2b_rounds = 12; -static const uint64_t blake2b_iv[8] = -{ - 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL, -}; -static const uint8_t blake2b_sigma[12][16] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, -}; - -/* -** Init the state according to Zcash parameters. -*/ -void zcash_blake2b_init(blake2b_state_t *st, uint8_t hash_len, - uint32_t n, uint32_t k) -{ - assert(n > k); - assert(hash_len <= 64); - st->h[0] = blake2b_iv[0] ^ (0x01010000 | hash_len); - for (uint32_t i = 1; i <= 5; i++) - st->h[i] = blake2b_iv[i]; - st->h[6] = blake2b_iv[6] ^ *(uint64_t *)"ZcashPoW"; - st->h[7] = blake2b_iv[7] ^ (((uint64_t)k << 32) | n); - st->bytes = 0; -} - -static uint64_t rotr64(uint64_t a, uint8_t bits) -{ - return (a >> bits) | (a << (64 - bits)); -} - -static void mix(uint64_t *va, uint64_t *vb, uint64_t *vc, uint64_t *vd, - uint64_t x, uint64_t y) -{ - *va = (*va + *vb + x); - *vd = rotr64(*vd ^ *va, 32); - *vc = (*vc + *vd); - *vb = rotr64(*vb ^ *vc, 24); - *va = (*va + *vb + y); - *vd = rotr64(*vd ^ *va, 16); - *vc = (*vc + *vd); - *vb = rotr64(*vb ^ *vc, 63); -} - -/* -** Process either a full message block or the final partial block. -** Note that v[13] is not XOR'd because st->bytes is assumed to never overflow. -** -** _msg pointer to message (must be zero-padded to 128 bytes if final block) -** msg_len must be 128 (<= 128 allowed only for final partial block) -** is_final indicate if this is the final block -*/ -void zcash_blake2b_update(blake2b_state_t *st, const uint8_t *_msg, - uint32_t msg_len, uint32_t is_final) -{ - const uint64_t *m = (const uint64_t *)_msg; - uint64_t v[16]; - assert(msg_len <= 128); - assert(st->bytes <= UINT64_MAX - msg_len); - memcpy(v + 0, st->h, 8 * sizeof (*v)); - memcpy(v + 8, blake2b_iv, 8 * sizeof (*v)); - v[12] ^= (st->bytes += msg_len); - v[14] ^= is_final ? -1 : 0; - for (uint32_t round = 0; round < blake2b_rounds; round++) - { - const uint8_t *s = blake2b_sigma[round]; - mix(v + 0, v + 4, v + 8, v + 12, m[s[0]], m[s[1]]); - mix(v + 1, v + 5, v + 9, v + 13, m[s[2]], m[s[3]]); - mix(v + 2, v + 6, v + 10, v + 14, m[s[4]], m[s[5]]); - mix(v + 3, v + 7, v + 11, v + 15, m[s[6]], m[s[7]]); - mix(v + 0, v + 5, v + 10, v + 15, m[s[8]], m[s[9]]); - mix(v + 1, v + 6, v + 11, v + 12, m[s[10]], m[s[11]]); - mix(v + 2, v + 7, v + 8, v + 13, m[s[12]], m[s[13]]); - mix(v + 3, v + 4, v + 9, v + 14, m[s[14]], m[s[15]]); - } - for (uint32_t i = 0; i < 8; i++) - st->h[i] ^= v[i] ^ v[i + 8]; -} - -void zcash_blake2b_final(blake2b_state_t *st, uint8_t *out, uint8_t outlen) -{ - assert(outlen <= 64); - memcpy(out, st->h, outlen); -} diff --git a/ocl_silentarmy/sa_blake.h b/ocl_silentarmy/sa_blake.h deleted file mode 100644 index 40270a95e..000000000 --- a/ocl_silentarmy/sa_blake.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -typedef struct blake2b_state_s -{ - uint64_t h[8]; - uint64_t bytes; -} blake2b_state_t; -void zcash_blake2b_init(blake2b_state_t *st, uint8_t hash_len, - uint32_t n, uint32_t k); -void zcash_blake2b_update(blake2b_state_t *st, const uint8_t *_msg, - uint32_t msg_len, uint32_t is_final); -void zcash_blake2b_final(blake2b_state_t *st, uint8_t *out, uint8_t outlen); diff --git a/ocl_silentarmy/zcash/gpu/input.cl b/ocl_silentarmy/zcash/gpu/input.cl deleted file mode 100644 index f5112c816..000000000 --- a/ocl_silentarmy/zcash/gpu/input.cl +++ /dev/null @@ -1,704 +0,0 @@ -#include "param.h" - -/* -** Assuming NR_ROWS_LOG == 16, the hash table slots have this layout (length in -** bytes in parens): -** -** round 0, table 0: cnt(4) i(4) pad(0) Xi(23.0) pad(1) -** round 1, table 1: cnt(4) i(4) pad(0.5) Xi(20.5) pad(3) -** round 2, table 0: cnt(4) i(4) i(4) pad(0) Xi(18.0) pad(2) -** round 3, table 1: cnt(4) i(4) i(4) pad(0.5) Xi(15.5) pad(4) -** round 4, table 0: cnt(4) i(4) i(4) i(4) pad(0) Xi(13.0) pad(3) -** round 5, table 1: cnt(4) i(4) i(4) i(4) pad(0.5) Xi(10.5) pad(5) -** round 6, table 0: cnt(4) i(4) i(4) i(4) i(4) pad(0) Xi( 8.0) pad(4) -** round 7, table 1: cnt(4) i(4) i(4) i(4) i(4) pad(0.5) Xi( 5.5) pad(6) -** round 8, table 0: cnt(4) i(4) i(4) i(4) i(4) i(4) pad(0) Xi( 3.0) pad(5) -** -** If the first byte of Xi is 0xAB then: -** - on even rounds, 'A' is part of the colliding PREFIX, 'B' is part of Xi -** - on odd rounds, 'A' and 'B' are both part of the colliding PREFIX, but -** 'A' is considered redundant padding as it was used to compute the row # -** -** - cnt is an atomic counter keeping track of the number of used slots. -** it is used in the first slot only; subsequent slots replace it with -** 4 padding bytes -** - i encodes either the 21-bit input value (round 0) or a reference to two -** inputs from the previous round -** -** Formula for Xi length and pad length above: -** > for i in range(9): -** > xi=(200-20*i-NR_ROWS_LOG)/8.; ci=8+4*((i)/2); print xi,32-ci-xi -** -** Note that the fractional .5-byte/4-bit padding following Xi for odd rounds -** is the 4 most significant bits of the last byte of Xi. -*/ - -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - -/* -** Reset counters in hash table. -*/ -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * NR_SLOTS * SLOT_LEN) = 0; -} - -/* -** If xi0,xi1,xi2,xi3 are stored consecutively in little endian then they -** represent (hex notation, group of 5 hex digits are a group of PREFIX bits): -** aa aa ab bb bb cc cc cd dd... [round 0] -** -------------------- -** ...ab bb bb cc cc cd dd... [odd round] -** -------------- -** ...cc cc cd dd... [next even round] -** ----- -** Bytes underlined are going to be stored in the slot. Preceding bytes -** (and possibly part of the underlined bytes, depending on NR_ROWS_LOG) are -** used to compute the row number. -** -** Round 0: xi0,xi1,xi2,xi3 is a 25-byte Xi (xi3: only the low byte matter) -** Round 1: xi0,xi1,xi2 is a 23-byte Xi (incl. the colliding PREFIX nibble) -** TODO: update lines below with padding nibbles -** Round 2: xi0,xi1,xi2 is a 20-byte Xi (xi2: only the low 4 bytes matter) -** Round 3: xi0,xi1,xi2 is a 17.5-byte Xi (xi2: only the low 1.5 bytes matter) -** Round 4: xi0,xi1 is a 15-byte Xi (xi1: only the low 7 bytes matter) -** Round 5: xi0,xi1 is a 12.5-byte Xi (xi1: only the low 4.5 bytes matter) -** Round 6: xi0,xi1 is a 10-byte Xi (xi1: only the low 2 bytes matter) -** Round 7: xi0 is a 7.5-byte Xi (xi0: only the low 7.5 bytes matter) -** Round 8: xi0 is a 5-byte Xi (xi0: only the low 5 bytes matter) -** -** Return 0 if successfully stored, or 1 if the row overflowed. -*/ -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; -#if NR_ROWS_LOG == 16 - if (!(round % 2)) - row = (xi0 & 0xffff); - else - // if we have in hex: "ab cd ef..." (little endian xi0) then this - // formula computes the row as 0xdebc. it skips the 'a' nibble as it - // is part of the PREFIX. The Xi will be stored starting with "ef..."; - // 'e' will be considered padding and 'f' is part of the current PREFIX - row = ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -#elif NR_ROWS_LOG == 18 - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xc00000) >> 6); - else - row = ((xi0 & 0xc0000) >> 2) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -#elif NR_ROWS_LOG == 19 - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xe00000) >> 5); - else - row = ((xi0 & 0xe0000) >> 1) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -#elif NR_ROWS_LOG == 20 - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xf00000) >> 4); - else - row = ((xi0 & 0xf0000) >> 0) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); -#else -#error "unsupported NR_ROWS_LOG" -#endif - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * NR_SLOTS * SLOT_LEN; - cnt = atomic_inc((__global uint *)p); - if (cnt >= NR_SLOTS) - return 1; - p += cnt * SLOT_LEN + xi_offset_for_round(round); - // store "i" (always 4 bytes before Xi) - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - // store 24 bytes - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - // store 20 bytes - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - // store 16 bytes - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - // store 12 bytes - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - // store 8 bytes - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - // store 4 bytes - *(__global uint *)(p + 0) = xi0; - } - return 0; -} - -#define mix(va, vb, vc, vd, x, y) \ - va = (va + vb + x); \ - vd = rotate((vd ^ va), (ulong)64 - 32); \ - vc = (vc + vd); \ - vb = rotate((vb ^ vc), (ulong)64 - 24); \ - va = (va + vb + y); \ - vd = rotate((vd ^ va), (ulong)64 - 16); \ - vc = (vc + vd); \ - vb = rotate((vb ^ vc), (ulong)64 - 63); - -/* -** Execute round 0 (blake). -** -** Note: making the work group size less than or equal to the wavefront size -** allows the OpenCL compiler to remove the barrier() calls, see "2.2 Local -** Memory (LDS) Optimization 2-10" in: -** http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/opencl-optimization-guide/ -*/ -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = NR_INPUTS / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - // shift "i" to occupy the high 32 bits of the second ulong word in the - // message block - ulong word1 = (ulong)input << 32; - // init vector v - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - // mix in length of data - v[12] ^= ZCASH_BLOCK_HEADER_LEN + 4 /* length of "i" */; - // last block - v[14] ^= -1; - - // round 1 - mix(v[0], v[4], v[8], v[12], 0, word1); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 2 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], word1, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 3 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, word1); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 4 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, word1); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 5 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, word1); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 6 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], word1, 0); - // round 7 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], word1, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 8 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, word1); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 9 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], word1, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 10 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], word1, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 11 - mix(v[0], v[4], v[8], v[12], 0, word1); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], 0, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - // round 12 - mix(v[0], v[4], v[8], v[12], 0, 0); - mix(v[1], v[5], v[9], v[13], 0, 0); - mix(v[2], v[6], v[10], v[14], 0, 0); - mix(v[3], v[7], v[11], v[15], 0, 0); - mix(v[0], v[5], v[10], v[15], word1, 0); - mix(v[1], v[6], v[11], v[12], 0, 0); - mix(v[2], v[7], v[8], v[13], 0, 0); - mix(v[3], v[4], v[9], v[14], 0, 0); - - // compress v into the blake state; this produces the 50-byte hash - // (two Xi values) - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - // store the two Xi values in the hash table -#if ZCASH_HASH_LEN == 50 - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); -#else -#error "unsupported ZCASH_HASH_LEN" -#endif - - input++; - } -#ifdef ENABLE_DEBUG - debug[tid * 2] = 0; - debug[tid * 2 + 1] = dropped; -#endif -} - -#if NR_ROWS_LOG <= 16 && NR_SLOTS <= (1 << 8) - -#define ENCODE_INPUTS(row, slot0, slot1) \ - ((row << 16) | ((slot1 & 0xff) << 8) | (slot0 & 0xff)) -#define DECODE_ROW(REF) (REF >> 16) -#define DECODE_SLOT1(REF) ((REF >> 8) & 0xff) -#define DECODE_SLOT0(REF) (REF & 0xff) - -#elif NR_ROWS_LOG == 18 && NR_SLOTS <= (1 << 7) - -#define ENCODE_INPUTS(row, slot0, slot1) \ - ((row << 14) | ((slot1 & 0x7f) << 7) | (slot0 & 0x7f)) -#define DECODE_ROW(REF) (REF >> 14) -#define DECODE_SLOT1(REF) ((REF >> 7) & 0x7f) -#define DECODE_SLOT0(REF) (REF & 0x7f) - -#elif NR_ROWS_LOG == 19 && NR_SLOTS <= (1 << 6) - -#define ENCODE_INPUTS(row, slot0, slot1) \ - ((row << 13) | ((slot1 & 0x3f) << 6) | (slot0 & 0x3f)) /* 1 spare bit */ -#define DECODE_ROW(REF) (REF >> 13) -#define DECODE_SLOT1(REF) ((REF >> 6) & 0x3f) -#define DECODE_SLOT0(REF) (REF & 0x3f) - -#elif NR_ROWS_LOG == 20 && NR_SLOTS <= (1 << 6) - -#define ENCODE_INPUTS(row, slot0, slot1) \ - ((row << 12) | ((slot1 & 0x3f) << 6) | (slot0 & 0x3f)) -#define DECODE_ROW(REF) (REF >> 12) -#define DECODE_SLOT1(REF) ((REF >> 6) & 0x3f) -#define DECODE_SLOT0(REF) (REF & 0x3f) - -#else -#error "unsupported NR_ROWS_LOG" -#endif - -/* -** XOR a pair of Xi values computed at "round - 1" and store the result in the -** hash table being built for "round". Note that when building the table for -** even rounds we need to skip 1 padding byte present in the "round - 1" table -** (the "0xAB" byte mentioned in the description at the top of this file.) But -** also note we can't load data directly past this byte because this would -** cause an unaligned memory access which is undefined per the OpenCL spec. -** -** Return 0 if successfully stored, or 1 if the row overflowed. -*/ -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; -#if NR_ROWS_LOG >= 16 && NR_ROWS_LOG <= 20 - // Note: for NR_ROWS_LOG == 20, for odd rounds, we could optimize by not - // storing the byte containing bits from the previous PREFIX block for - if (round == 1 || round == 2) - { - // xor 24 bytes - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - if (round == 2) - { - // skip padding byte - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8) | (xi2 << (64 - 8)); - xi2 = (xi2 >> 8); - } - } - else if (round == 3) - { - // xor 20 bytes - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - // xor 16 bytes - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - if (round == 4) - { - // skip padding byte - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 6) - { - // xor 12 bytes - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - if (round == 6) - { - // skip padding byte - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 7 || round == 8) - { - // xor 8 bytes - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - if (round == 8) - { - // skip padding byte - xi0 = (xi0 >> 8); - } - } - // invalid solutions (which start happenning in round 5) have duplicate - // inputs and xor to zero, so discard them - if (!xi0 && !xi1) - return 0; -#else -#error "unsupported NR_ROWS_LOG" -#endif - return ht_store(round, ht_dst, ENCODE_INPUTS(row, slot_a, slot_b), - xi0, xi1, xi2, 0); -} - -/* -** Execute one Equihash round. Read from ht_src, XOR colliding pairs of Xi, -** store them in ht_dst. -*/ -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[NR_SLOTS]; - uchar mask; - uint i, j; - // NR_SLOTS is already oversized (by a factor of OVERHEAD), but we want to - // make it even larger - ushort collisions[NR_SLOTS * 3]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - // read first words of Xi from the previous (round - 1) hash table - xi_offset = xi_offset_for_round(round - 1); - // the mask is also computed to read data from the previous round -#if NR_ROWS_LOG == 16 - mask = ((!(round % 2)) ? 0x0f : 0xf0); -#elif NR_ROWS_LOG == 18 - mask = ((!(round % 2)) ? 0x03 : 0x30); -#elif NR_ROWS_LOG == 19 - mask = ((!(round % 2)) ? 0x01 : 0x10); -#elif NR_ROWS_LOG == 20 - mask = 0; /* we can vastly simplify the code below */ -#else -#error "unsupported NR_ROWS_LOG" -#endif - p = (ht_src + tid * NR_SLOTS * SLOT_LEN); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)NR_SLOTS); // handle possible overflow in prev. round - p += xi_offset; - for (i = 0; i < cnt; i++, p += SLOT_LEN) - first_words[i] = *(__global uchar *)p; - // find collisions - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - // collision! - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else -#if NR_SLOTS <= (1 << 8) - // note: this assumes slots can be encoded in 8 bits - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); -#else -#error "unsupported NR_SLOTS" -#endif - } - // XOR colliding pairs of Xi - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * NR_SLOTS * SLOT_LEN + i * SLOT_LEN + xi_offset); - b = (__global ulong *) - (ht_src + tid * NR_SLOTS * SLOT_LEN + j * SLOT_LEN + xi_offset); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - if (round < 8) - // reset the counter in preparation of the next round - *(__global uint *)(ht_src + tid * NR_SLOTS * SLOT_LEN) = 0; -#ifdef ENABLE_DEBUG - debug[tid * 2] = dropped_coll; - debug[tid * 2 + 1] = dropped_stor; -#endif -} - -/* -** This defines kernel_round1, kernel_round2, ..., kernel_round7. -*/ -#define KERNEL_ROUND(N) \ -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) \ -void kernel_round ## N(__global char *ht_src, __global char *ht_dst, \ - __global uint *debug) \ -{ \ - equihash_round(N, ht_src, ht_dst, debug); \ -} -KERNEL_ROUND(1) -KERNEL_ROUND(2) -KERNEL_ROUND(3) -KERNEL_ROUND(4) -KERNEL_ROUND(5) -KERNEL_ROUND(6) -KERNEL_ROUND(7) - -// kernel_round8 takes an extra argument, "sols" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round8(__global char *ht_src, __global char *ht_dst, - __global uint *debug, __global sols_t *sols) -{ - uint tid = get_global_id(0); - equihash_round(8, ht_src, ht_dst, debug); - if (!tid) - sols->nr = sols->likely_invalids = 0; -} - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * NR_SLOTS * SLOT_LEN + - slot * SLOT_LEN + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = xi_offset_for_round(round); - do - { - ins[j] = expand_ref(ht, xi_offset, - DECODE_ROW(ins[i]), DECODE_SLOT1(ins[i])); - ins[j - 1] = expand_ref(ht, xi_offset, - DECODE_ROW(ins[i]), DECODE_SLOT0(ins[i])); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - -/* -** Verify if a potential solution is in fact valid. -*/ -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= MAX_SOLS) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = PARAM_K - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - -/* -** Scan the hash tables to find Equihash solutions. -*/ -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (PARAM_K - 1) % 2; // table filled at last round - uint cnt; - uint xi_offset = xi_offset_for_round(PARAM_K - 1); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - // it's ok for the collisions array to be so small, as if it fills up - // the potential solutions are likely invalid (many duplicate inputs) - ulong collisions[5]; - uint coll; -#if NR_ROWS_LOG >= 16 && NR_ROWS_LOG <= 20 - // in the final hash table, we are looking for a match on both the bits - // part of the previous PREFIX colliding bits, and the last PREFIX bits. - uint mask = 0xffffff; -#else -#error "unsupported NR_ROWS_LOG" -#endif - a = htabs[ht_i] + tid * NR_SLOTS * SLOT_LEN; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)NR_SLOTS); // handle possible overflow in last round - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += SLOT_LEN) - for (j = i + 1, b = a + SLOT_LEN; j < cnt; j++, b += SLOT_LEN) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalids); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/ocl_silentarmy/zcash/gpu/kernel.cl b/ocl_silentarmy/zcash/gpu/kernel.cl deleted file mode 100644 index 0fdc74d83..000000000 --- a/ocl_silentarmy/zcash/gpu/kernel.cl +++ /dev/null @@ -1,555 +0,0 @@ -# 1 "input.cl" -# 1 "" -# 1 "" -# 1 "/usr/include/stdc-predef.h" 1 3 4 -# 1 "" 2 -# 1 "input.cl" -# 1 "param.h" 1 -# 60 "param.h" -typedef struct sols_s -{ - uint nr; - uint likely_invalids; - uchar valid[2000]; - uint values[2000][(1 << 9)]; -} sols_t; -# 2 "input.cl" 2 -# 36 "input.cl" -__constant ulong blake_iv[] = -{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -}; - - - - -__kernel -void kernel_init_ht(__global char *ht) -{ - uint tid = get_global_id(0); - *(__global uint *)(ht + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32) = 0; -} -# 80 "input.cl" -uint ht_store(uint round, __global char *ht, uint i, - ulong xi0, ulong xi1, ulong xi2, ulong xi3) -{ - uint row; - __global char *p; - uint cnt; -# 111 "input.cl" - if (!(round % 2)) - row = (xi0 & 0xffff) | ((xi0 & 0xf00000) >> 4); - else - row = ((xi0 & 0xf0000) >> 0) | - ((xi0 & 0xf00) << 4) | ((xi0 & 0xf00000) >> 12) | - ((xi0 & 0xf) << 4) | ((xi0 & 0xf000) >> 12); - - - - xi0 = (xi0 >> 16) | (xi1 << (64 - 16)); - xi1 = (xi1 >> 16) | (xi2 << (64 - 16)); - xi2 = (xi2 >> 16) | (xi3 << (64 - 16)); - p = ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32; - cnt = atomic_inc((__global uint *)p); - if (cnt >= ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)) - return 1; - p += cnt * 32 + (8 + ((round) / 2) * 4); - - *(__global uint *)(p - 4) = i; - if (round == 0 || round == 1) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global ulong *)(p + 16) = xi2; - } - else if (round == 2) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - *(__global uint *)(p + 16) = xi2; - } - else if (round == 3 || round == 4) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global ulong *)(p + 8) = xi1; - - } - else if (round == 5) - { - - *(__global ulong *)(p + 0) = xi0; - *(__global uint *)(p + 8) = xi1; - } - else if (round == 6 || round == 7) - { - - *(__global ulong *)(p + 0) = xi0; - } - else if (round == 8) - { - - *(__global uint *)(p + 0) = xi0; - } - return 0; -} -# 188 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round0(__global ulong *blake_state, __global char *ht, - __global uint *debug) -{ - uint tid = get_global_id(0); - ulong v[16]; - uint inputs_per_thread = (1 << (200 / (9 + 1))) / get_global_size(0); - uint input = tid * inputs_per_thread; - uint input_end = (tid + 1) * inputs_per_thread; - uint dropped = 0; - while (input < input_end) - { - - - ulong word1 = (ulong)input << 32; - - v[0] = blake_state[0]; - v[1] = blake_state[1]; - v[2] = blake_state[2]; - v[3] = blake_state[3]; - v[4] = blake_state[4]; - v[5] = blake_state[5]; - v[6] = blake_state[6]; - v[7] = blake_state[7]; - v[8] = blake_iv[0]; - v[9] = blake_iv[1]; - v[10] = blake_iv[2]; - v[11] = blake_iv[3]; - v[12] = blake_iv[4]; - v[13] = blake_iv[5]; - v[14] = blake_iv[6]; - v[15] = blake_iv[7]; - - v[12] ^= 140 + 4 ; - - v[14] ^= -1; - - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + word1); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + word1); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + word1); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + word1); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + word1); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + word1); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 32); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 24); v[0] = (v[0] + v[4] + 0); v[12] = rotate((v[12] ^ v[0]), (ulong)64 - 16); v[8] = (v[8] + v[12]); v[4] = rotate((v[4] ^ v[8]), (ulong)64 - 63);; - v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 32); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 24); v[1] = (v[1] + v[5] + 0); v[13] = rotate((v[13] ^ v[1]), (ulong)64 - 16); v[9] = (v[9] + v[13]); v[5] = rotate((v[5] ^ v[9]), (ulong)64 - 63);; - v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 32); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 24); v[2] = (v[2] + v[6] + 0); v[14] = rotate((v[14] ^ v[2]), (ulong)64 - 16); v[10] = (v[10] + v[14]); v[6] = rotate((v[6] ^ v[10]), (ulong)64 - 63);; - v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 32); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 24); v[3] = (v[3] + v[7] + 0); v[15] = rotate((v[15] ^ v[3]), (ulong)64 - 16); v[11] = (v[11] + v[15]); v[7] = rotate((v[7] ^ v[11]), (ulong)64 - 63);; - v[0] = (v[0] + v[5] + word1); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 32); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 24); v[0] = (v[0] + v[5] + 0); v[15] = rotate((v[15] ^ v[0]), (ulong)64 - 16); v[10] = (v[10] + v[15]); v[5] = rotate((v[5] ^ v[10]), (ulong)64 - 63);; - v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 32); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 24); v[1] = (v[1] + v[6] + 0); v[12] = rotate((v[12] ^ v[1]), (ulong)64 - 16); v[11] = (v[11] + v[12]); v[6] = rotate((v[6] ^ v[11]), (ulong)64 - 63);; - v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 32); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 24); v[2] = (v[2] + v[7] + 0); v[13] = rotate((v[13] ^ v[2]), (ulong)64 - 16); v[8] = (v[8] + v[13]); v[7] = rotate((v[7] ^ v[8]), (ulong)64 - 63);; - v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 32); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 24); v[3] = (v[3] + v[4] + 0); v[14] = rotate((v[14] ^ v[3]), (ulong)64 - 16); v[9] = (v[9] + v[14]); v[4] = rotate((v[4] ^ v[9]), (ulong)64 - 63);; - - - - ulong h[7]; - h[0] = blake_state[0] ^ v[0] ^ v[8]; - h[1] = blake_state[1] ^ v[1] ^ v[9]; - h[2] = blake_state[2] ^ v[2] ^ v[10]; - h[3] = blake_state[3] ^ v[3] ^ v[11]; - h[4] = blake_state[4] ^ v[4] ^ v[12]; - h[5] = blake_state[5] ^ v[5] ^ v[13]; - h[6] = (blake_state[6] ^ v[6] ^ v[14]) & 0xffff; - - - - dropped += ht_store(0, ht, input * 2, - h[0], - h[1], - h[2], - h[3]); - dropped += ht_store(0, ht, input * 2 + 1, - (h[3] >> 8) | (h[4] << (64 - 8)), - (h[4] >> 8) | (h[5] << (64 - 8)), - (h[5] >> 8) | (h[6] << (64 - 8)), - (h[6] >> 8)); - - - - - input++; - } - - - - -} -# 415 "input.cl" -uint xor_and_store(uint round, __global char *ht_dst, uint row, - uint slot_a, uint slot_b, __global ulong *a, __global ulong *b) -{ - ulong xi0, xi1, xi2; - - - - if (round == 1 || round == 2) - { - - xi0 = *(a++) ^ *(b++); - xi1 = *(a++) ^ *(b++); - xi2 = *a ^ *b; - if (round == 2) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8) | (xi2 << (64 - 8)); - xi2 = (xi2 >> 8); - } - } - else if (round == 3) - { - - xi0 = *a++ ^ *b++; - xi1 = *a++ ^ *b++; - xi2 = *(__global uint *)a ^ *(__global uint *)b; - } - else if (round == 4 || round == 5) - { - - xi0 = *a++ ^ *b++; - xi1 = *a ^ *b; - xi2 = 0; - if (round == 4) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 6) - { - - xi0 = *a++ ^ *b++; - xi1 = *(__global uint *)a ^ *(__global uint *)b; - xi2 = 0; - if (round == 6) - { - - xi0 = (xi0 >> 8) | (xi1 << (64 - 8)); - xi1 = (xi1 >> 8); - } - } - else if (round == 7 || round == 8) - { - - xi0 = *a ^ *b; - xi1 = 0; - xi2 = 0; - if (round == 8) - { - - xi0 = (xi0 >> 8); - } - } - - - if (!xi0 && !xi1) - return 0; - - - - return ht_store(round, ht_dst, ((row << 12) | ((slot_b & 0x3f) << 6) | (slot_a & 0x3f)), - xi0, xi1, xi2, 0); -} - - - - - -void equihash_round(uint round, __global char *ht_src, __global char *ht_dst, - __global uint *debug) -{ - uint tid = get_global_id(0); - uint tlid = get_local_id(0); - __global char *p; - uint cnt; - uchar first_words[((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)]; - uchar mask; - uint i, j; - - - ushort collisions[((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 3]; - uint nr_coll = 0; - uint n; - uint dropped_coll, dropped_stor; - __global ulong *a, *b; - uint xi_offset; - - xi_offset = (8 + ((round - 1) / 2) * 4); -# 524 "input.cl" - mask = 0; - - - - p = (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32); - cnt = *(__global uint *)p; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)); - p += xi_offset; - for (i = 0; i < cnt; i++, p += 32) - first_words[i] = *(__global uchar *)p; - - nr_coll = 0; - dropped_coll = 0; - for (i = 0; i < cnt; i++) - for (j = i + 1; j < cnt; j++) - if ((first_words[i] & mask) == - (first_words[j] & mask)) - { - - if (nr_coll >= sizeof (collisions) / sizeof (*collisions)) - dropped_coll++; - else - - - collisions[nr_coll++] = - ((ushort)j << 8) | ((ushort)i & 0xff); - - - - } - - dropped_stor = 0; - for (n = 0; n < nr_coll; n++) - { - i = collisions[n] & 0xff; - j = collisions[n] >> 8; - a = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + i * 32 + xi_offset); - b = (__global ulong *) - (ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + j * 32 + xi_offset); - dropped_stor += xor_and_store(round, ht_dst, tid, i, j, a, b); - } - if (round < 8) - - *(__global uint *)(ht_src + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32) = 0; - - - - -} -# 585 "input.cl" -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round1(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(1, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round2(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(2, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round3(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(3, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round4(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(4, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round5(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(5, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round6(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(6, ht_src, ht_dst, debug); } -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) void kernel_round7(__global char *ht_src, __global char *ht_dst, __global uint *debug) { equihash_round(7, ht_src, ht_dst, debug); } - - -__kernel __attribute__((reqd_work_group_size(64, 1, 1))) -void kernel_round8(__global char *ht_src, __global char *ht_dst, - __global uint *debug, __global sols_t *sols) -{ - uint tid = get_global_id(0); - equihash_round(8, ht_src, ht_dst, debug); - if (!tid) - sols->nr = sols->likely_invalids = 0; -} - -uint expand_ref(__global char *ht, uint xi_offset, uint row, uint slot) -{ - return *(__global uint *)(ht + row * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32 + - slot * 32 + xi_offset - 4); -} - -void expand_refs(__global uint *ins, uint nr_inputs, __global char **htabs, - uint round) -{ - __global char *ht = htabs[round % 2]; - uint i = nr_inputs - 1; - uint j = nr_inputs * 2 - 1; - uint xi_offset = (8 + ((round) / 2) * 4); - do - { - ins[j] = expand_ref(ht, xi_offset, - (ins[i] >> 12), ((ins[i] >> 6) & 0x3f)); - ins[j - 1] = expand_ref(ht, xi_offset, - (ins[i] >> 12), (ins[i] & 0x3f)); - if (!i) - break ; - i--; - j -= 2; - } - while (1); -} - - - - -void potential_sol(__global char **htabs, __global sols_t *sols, - uint ref0, uint ref1) -{ - uint sol_i; - uint nr_values; - sol_i = atomic_inc(&sols->nr); - if (sol_i >= 2000) - return ; - sols->valid[sol_i] = 0; - nr_values = 0; - sols->values[sol_i][nr_values++] = ref0; - sols->values[sol_i][nr_values++] = ref1; - uint round = 9 - 1; - do - { - round--; - expand_refs(&(sols->values[sol_i][0]), nr_values, htabs, round); - nr_values *= 2; - } - while (round > 0); - sols->valid[sol_i] = 1; -} - - - - -__kernel -void kernel_sols(__global char *ht0, __global char *ht1, __global sols_t *sols) -{ - uint tid = get_global_id(0); - __global char *htabs[2] = { ht0, ht1 }; - uint ht_i = (9 - 1) % 2; - uint cnt; - uint xi_offset = (8 + ((9 - 1) / 2) * 4); - uint i, j; - __global char *a, *b; - uint ref_i, ref_j; - - - ulong collisions[5]; - uint coll; - - - - uint mask = 0xffffff; - - - - a = htabs[ht_i] + tid * ((1 << (((200 / (9 + 1)) + 1) - 20)) * 9) * 32; - cnt = *(__global uint *)a; - cnt = min(cnt, (uint)((1 << (((200 / (9 + 1)) + 1) - 20)) * 9)); - coll = 0; - a += xi_offset; - for (i = 0; i < cnt; i++, a += 32) - for (j = i + 1, b = a + 32; j < cnt; j++, b += 32) - if (((*(__global uint *)a) & mask) == - ((*(__global uint *)b) & mask)) - { - ref_i = *(__global uint *)(a - 4); - ref_j = *(__global uint *)(b - 4); - if (coll < sizeof (collisions) / sizeof (*collisions)) - collisions[coll++] = ((ulong)ref_i << 32) | ref_j; - else - atomic_inc(&sols->likely_invalids); - } - if (!coll) - return ; - for (i = 0; i < coll; i++) - potential_sol(htabs, sols, collisions[i] >> 32, - collisions[i] & 0xffffffff); -} diff --git a/ocl_xpm/ocl_xmp.cpp b/ocl_xpm/ocl_xmp.cpp deleted file mode 100644 index d0a96a2a8..000000000 --- a/ocl_xpm/ocl_xmp.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "ocl_xmp.hpp" - - - -// miner instance -#include "opencl.h" -#include - -#include - -// is this really needed? -//#include "uint256.h" - -// hardcoded defines, looks like not working -// hardcoded defines fix this -#define RESTBITS 4 -#define XINTREE -#define UNROLL -#define __OPENCL_HOST__ -#include "zcash/gpu/common.h" - -struct MinerInstance { - cl_context _context; - cl_program _program; - - cl_command_queue queue; - clBuffer blake2bState; - clBuffer heap0; - clBuffer heap1; - clBuffer nslots; - clBuffer sols; - clBuffer numSols; - cl_kernel _digitHKernel; - cl_kernel _digitOKernel; - cl_kernel _digitEKernel; - cl_kernel _digitKKernel; - cl_kernel _digitKernels[9]; - - //hide_xmp_hack::uint256 nonce; // TODO IS THIS NEEDED???? - - bool init(cl_context context, cl_program program, cl_device_id dev, unsigned threadsNum, unsigned threadsPerBlock); -}; - -cl_context gContext = 0; -cl_program gProgram = 0; -cl_platform_id gPlatform = 0; - - -bool MinerInstance::init(cl_context context, - cl_program program, - cl_device_id dev, - unsigned int threadsNum, - unsigned int threadsPerBlock) -{ - cl_int error; - - _context = context; - _program = program; - queue = clCreateCommandQueue(context, dev, 0, &error); - - blake2bState.init(context, 1, CL_MEM_READ_WRITE); - heap0.init(context, sizeof(digit0) / sizeof(uint32_t), CL_MEM_HOST_NO_ACCESS); - heap1.init(context, sizeof(digit1) / sizeof(uint32_t), CL_MEM_HOST_NO_ACCESS); - nslots.init(context, 2, CL_MEM_READ_WRITE); - sols.init(context, MAXSOLS, CL_MEM_READ_WRITE); - numSols.init(context, 1, CL_MEM_READ_WRITE); - - _digitHKernel = clCreateKernel(program, "digitH", &error); - _digitOKernel = clCreateKernel(program, "digitOdd", &error); - _digitEKernel = clCreateKernel(program, "digitEven", &error); - _digitKKernel = clCreateKernel(program, "digitK", &error); - OCLR(clSetKernelArg(_digitHKernel, 0, sizeof(cl_mem), &blake2bState.DeviceData), 1); - OCLR(clSetKernelArg(_digitHKernel, 1, sizeof(cl_mem), &heap0.DeviceData), 1); - OCLR(clSetKernelArg(_digitHKernel, 2, sizeof(cl_mem), &nslots.DeviceData), 1); - - OCLR(clSetKernelArg(_digitOKernel, 1, sizeof(cl_mem), &heap0.DeviceData), 1); - OCLR(clSetKernelArg(_digitOKernel, 2, sizeof(cl_mem), &heap1.DeviceData), 1); - OCLR(clSetKernelArg(_digitOKernel, 3, sizeof(cl_mem), &nslots.DeviceData), 1); - OCLR(clSetKernelArg(_digitEKernel, 1, sizeof(cl_mem), &heap0.DeviceData), 1); - OCLR(clSetKernelArg(_digitEKernel, 2, sizeof(cl_mem), &heap1.DeviceData), 1); - OCLR(clSetKernelArg(_digitEKernel, 3, sizeof(cl_mem), &nslots.DeviceData), 1); - - for (unsigned i = 1; i <= 8; i++) { - char kernelName[32]; - sprintf(kernelName, "digit_%u", i); - _digitKernels[i] = clCreateKernel(program, kernelName, &error); - OCLR(clSetKernelArg(_digitKernels[i], 0, sizeof(cl_mem), &heap0.DeviceData), 1); - OCLR(clSetKernelArg(_digitKernels[i], 1, sizeof(cl_mem), &heap1.DeviceData), 1); - OCLR(clSetKernelArg(_digitKernels[i], 2, sizeof(cl_mem), &nslots.DeviceData), 1); - } - - OCLR(clSetKernelArg(_digitKKernel, 0, sizeof(cl_mem), &heap0.DeviceData), 1); - OCLR(clSetKernelArg(_digitKKernel, 1, sizeof(cl_mem), &heap1.DeviceData), 1); - OCLR(clSetKernelArg(_digitKKernel, 2, sizeof(cl_mem), &nslots.DeviceData), 1); - OCLR(clSetKernelArg(_digitKKernel, 3, sizeof(cl_mem), &sols.DeviceData), 1); - OCLR(clSetKernelArg(_digitKKernel, 4, sizeof(cl_mem), &numSols.DeviceData), 1); - - return true; -} - -//////////////////////////// -////statics non class START - -static void setheader(blake2b_state *ctx, const char *header, const uint32_t headerlen) -{ - uint32_t le_N = WN; - uint32_t le_K = WK; - char personal[] = "ZcashPoW01230123"; - memcpy(personal + 8, &le_N, 4); - memcpy(personal + 12, &le_K, 4); - blake2b_param P[1]; - P->digest_length = HASHOUT; - P->key_length = 0; - P->fanout = 1; - P->depth = 1; - P->leaf_length = 0; - P->node_offset = 0; - P->node_depth = 0; - P->inner_length = 0; - memset(P->reserved, 0, sizeof(P->reserved)); - memset(P->salt, 0, sizeof(P->salt)); - memcpy(P->personal, (const uint8_t *)personal, 16); - blake2b_init_param(ctx, P); - blake2b_update(ctx, (const uint8_t*)header, headerlen); -} - -static void setnonce(blake2b_state *ctx, const uint8_t *nonce) -{ - blake2b_update(ctx, nonce, 32); -} - -static int inline digit(cl_command_queue clQueue, cl_kernel kernel, size_t nthreads, size_t threadsPerBlock) -{ - size_t globalSize[] = { nthreads, 1, 1 }; - size_t localSize[] = { threadsPerBlock, 1 }; - OCLR(clEnqueueNDRangeKernel(clQueue, kernel, 1, 0, globalSize, localSize, 0, 0, 0), 1); - return 0; -} - - -////statics non class END -//////////////////////////// - -ocl_xmp::ocl_xmp(int platf_id, int dev_id) { /*TODO*/ - platform_id = platf_id; - device_id = dev_id; - // TODO - threadsNum = 8192; - wokrsize = 128; // 256; - //threadsperblock = 128; -} - -std::string ocl_xmp::getdevinfo() { /*TODO*/ - return "GPU_ID(" + std::to_string(device_id) + ")"; -} - -// STATICS START -int ocl_xmp::getcount() { /*TODO*/ - return 0; -} - -void ocl_xmp::getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version) { /*TODO*/ } - -void ocl_xmp::start(ocl_xmp& device_context) { - /*TODO*/ - device_context.is_init_success = false; - cl_context gContext[64] = { 0 }; - cl_program gProgram[64] = { 0 }; - - - std::vector allGpus; - if (!clInitialize(device_context.platform_id, allGpus)) { - return; - } - - // this is kinda stupid but it works - std::vector gpus; - for (unsigned i = 0; i < allGpus.size(); ++i) { - if (i == device_context.device_id) { - printf("Using device %d as GPU %d\n", i, (int)gpus.size()); - gpus.push_back(allGpus[i]); - } - } - - if (!gpus.size()){ - printf("Device id %d not found\n", device_context.device_id); - return; - } - - // context create - for (unsigned i = 0; i < gpus.size(); i++) { - cl_context_properties props[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)gPlatform, 0 }; - cl_int error; - gContext[i] = clCreateContext(props, 1, &gpus[i], 0, 0, &error); - //OCLR(error, false); - if (cl_int err = error) { - printf("OpenCL error: %d at %s:%d\n", err, __FILE__, __LINE__); - return; - } - } - - std::vector binstatus; - binstatus.resize(gpus.size()); - - for (size_t i = 0; i < gpus.size(); i++) { - char kernelName[64]; - sprintf(kernelName, "equiw200k9_gpu%u.bin", (unsigned)i); - if (!clCompileKernel(gContext[i], - gpus[i], - kernelName, - { "zcash/gpu/equihash.cl" }, - "-I./zcash/gpu -DXINTREE -DWN=200 -DWK=9 -DRESTBITS=4 -DUNROLL", - &binstatus[i], - &gProgram[i])) { - return; - } - } - - for (unsigned i = 0; i < gpus.size(); ++i) { - if (binstatus[i] == CL_SUCCESS) { - device_context.context = new MinerInstance(); - if (!device_context.context->init(gContext[i], gProgram[i], gpus[i], device_context.threadsNum, device_context.wokrsize)) { - printf("Init failed"); - return; - } - } - else { - printf("GPU %d: failed to load kernel\n", i); - return; - } - } - - device_context.is_init_success = true; -} - -void ocl_xmp::stop(ocl_xmp& device_context) { /*TODO*/ } - -void ocl_xmp::solve(const char *tequihash_header, - unsigned int tequihash_header_len, - const char* nonce, - unsigned int nonce_len, - std::function cancelf, - std::function&, size_t, const unsigned char*)> solutionf, - std::function hashdonef, - ocl_xmp& device_context) { - if (device_context.is_init_success == false) { - printf("fail OCL\n"); - //cancelf(); - return; - } - - // move to context or somewhere or leave? - blake2b_state initialCtx; - setheader(&initialCtx, tequihash_header, tequihash_header_len); - - MinerInstance *miner = device_context.context; - clFlush(miner->queue); - - /*hide_xmp_hack::uint256 nNonce = hide_xmp_hack::uint256(nonce); - miner->nonce = nNonce;*/ - *miner->blake2bState.HostData = initialCtx; - setnonce(miner->blake2bState.HostData, (const uint8_t*)nonce); - memset(miner->nslots.HostData, 0, 2 * sizeof(bsizes)); - *miner->numSols.HostData = 0; - miner->blake2bState.copyToDevice(miner->queue, false); - miner->nslots.copyToDevice(miner->queue, false); - miner->numSols.copyToDevice(miner->queue, false); - - digit(miner->queue, miner->_digitHKernel, device_context.threadsNum, device_context.wokrsize); -#if BUCKBITS == 16 && RESTBITS == 4 && defined XINTREE && defined(UNROLL) - for (unsigned i = 1; i <= 8; i++) - digit(miner->queue, miner->_digitKernels[i], device_context.threadsNum, device_context.wokrsize); -#else - size_t globalSize[] = { _threadsNum, 1, 1 }; - size_t localSize[] = { _threadsPerBlocksNum, 1 }; - for (unsigned r = 1; r < WK; r++) { - if (r & 1) { - OCL(clSetKernelArg(miner->_digitOKernel, 0, sizeof(cl_uint), &r)); - OCL(clEnqueueNDRangeKernel(miner->queue, miner->_digitOKernel, 1, 0, globalSize, localSize, 0, 0, 0)); - } - else { - OCL(clSetKernelArg(miner->_digitEKernel, 0, sizeof(cl_uint), &r)); - OCL(clEnqueueNDRangeKernel(miner->queue, miner->_digitEKernel, 1, 0, globalSize, localSize, 0, 0, 0)); - } - } -#endif - digit(miner->queue, miner->_digitKKernel, device_context.threadsNum, device_context.wokrsize); - - // get solutions - miner->sols.copyToHost(miner->queue, true); - miner->numSols.copyToHost(miner->queue, true); - for (unsigned s = 0; s < miner->numSols.HostData[0]; s++) - { - std::vector index_vector(PROOFSIZE); - for (u32 i = 0; i < PROOFSIZE; i++) { - index_vector[i] = miner->sols[s][i]; - } - - solutionf(index_vector, DIGITBITS, nullptr); - if (cancelf()) return; - } - hashdonef(); -} - -// STATICS END \ No newline at end of file diff --git a/ocl_xpm/ocl_xmp.hpp b/ocl_xpm/ocl_xmp.hpp deleted file mode 100644 index 3e0d4054a..000000000 --- a/ocl_xpm/ocl_xmp.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#ifdef _LIB -#define DLL_OCL_XMP __declspec(dllexport) -#else -#define DLL_OCL_XMP -#endif - -// remove after -#include -#include -#include -#include - -struct MinerInstance; - -struct DLL_OCL_XMP ocl_xmp -{ - //int threadsperblock; - int blocks; - int device_id; - int platform_id; - - MinerInstance* context; - // threads - unsigned threadsNum; // TMP - unsigned wokrsize; - - bool is_init_success = false; - - ocl_xmp(int platf_id, int dev_id); - - std::string getdevinfo(); - - static int getcount(); - - static void getinfo(int platf_id, int d_id, std::string& gpu_name, int& sm_count, std::string& version); - - static void start(ocl_xmp& device_context); - - static void stop(ocl_xmp& device_context); - - static void solve(const char *tequihash_header, - unsigned int tequihash_header_len, - const char* nonce, - unsigned int nonce_len, - std::function cancelf, - std::function&, size_t, const unsigned char*)> solutionf, - std::function hashdonef, - ocl_xmp& device_context); - - std::string getname() { return "OCL_XMP"; } - -private: - std::string m_gpu_name; - std::string m_version; -}; \ No newline at end of file diff --git a/ocl_xpm/ocl_xpm.vcxproj b/ocl_xpm/ocl_xpm.vcxproj deleted file mode 100644 index 7c2c299c5..000000000 --- a/ocl_xpm/ocl_xpm.vcxproj +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - - {5EC9EDEB-8E49-4126-9161-1560683CBC71} - Win32Proj - ocl_xpm - - - - StaticLibrary - true - v120 - MultiByte - - - StaticLibrary - false - v120 - true - MultiByte - - - - - - - - - - - - - true - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;OCL_XPM_EXPORTS;%(PreprocessorDefinitions) - - - ..\ocl_device_utils;..\cpu_tromp;..\3rdparty\include;$(AMDAPPSDKROOT)\include\ - - - Windows - true - OpenCL.lib;%(AdditionalDependencies) - ..\3rdparty\libs\win64;$(AMDAPPSDKROOT)\lib\x86_64\ - - - - - Level3 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;OCL_XPM_EXPORTS;%(PreprocessorDefinitions) - - - ..\ocl_device_utils;..\3rdparty\include;$(AMDAPPSDKROOT)\include\;%(AdditionalIncludeDirectories) - - - Windows - true - true - true - OpenCL.lib;%(AdditionalDependencies) - ..\3rdparty\libs\win64;$(AMDAPPSDKROOT)\lib\x86_64\ - - - - - - \ No newline at end of file diff --git a/ocl_xpm/ocl_xpm.vcxproj.filters b/ocl_xpm/ocl_xpm.vcxproj.filters deleted file mode 100644 index ae440bef8..000000000 --- a/ocl_xpm/ocl_xpm.vcxproj.filters +++ /dev/null @@ -1,26 +0,0 @@ - - - - - {69f1aa4c-1be3-4265-a93c-b58266bad10b} - - - {a95c2e64-90c0-48d9-9287-46723392025d} - - - - - - zcash\gpu - - - - - - - - - zcash\gpu - - - \ No newline at end of file diff --git a/ocl_xpm/zcash/gpu/blake2bcl.h b/ocl_xpm/zcash/gpu/blake2bcl.h deleted file mode 100644 index 13cad965c..000000000 --- a/ocl_xpm/zcash/gpu/blake2bcl.h +++ /dev/null @@ -1,150 +0,0 @@ -// Blake2-B CUDA Implementation -// tpruvot@github July 2016 -// permission granted to use under MIT license -// modified for use in Zcash by John Tromp September 2016 - -/** - * uint2 direct ops by c++ operator definitions - */ - -// static __device__ __forceinline__ uint2 operator^ (uint2 a, uint2 b) { -// return make_uint2(a.x ^ b.x, a.y ^ b.y); -// } - -// uint2 ROR/ROL methods -uint2 ROR2(const uint2 a, const int offset) { - uint2 result; - if (!offset) - result = a; - else if (offset < 32) { - result.y = ((a.y >> offset) | (a.x << (32 - offset))); - result.x = ((a.x >> offset) | (a.y << (32 - offset))); - } else if (offset == 32) { - result.y = a.x; - result.x = a.y; - } else { - result.y = ((a.x >> (offset - 32)) | (a.y << (64 - offset))); - result.x = ((a.y >> (offset - 32)) | (a.x << (64 - offset))); - } - return result; -} - -uint2 SWAPUINT2(uint2 value) { - uint2 result; - result.x = value.y; - result.y = value.x; - return result; -// return make_uint2(value.y, value.x); -} - -#define ROR24(u) ROR2(u,24) -#define ROR16(u) ROR2(u,16) - -__constant int8_t blake2b_sigma[12][16] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , - { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , - { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , - { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , - { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , - { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , - { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , - { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , - { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } , - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , - { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } -}; - -void G(const int32_t r, const int32_t i, uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d, uint64_t const m[16]) { - *a += *b + m[ blake2b_sigma[r][2*i] ]; - ((uint2*)d)[0] = SWAPUINT2( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR24( ((uint2*)b)[0] ^ ((uint2*)c)[0] ); - *a += *b + m[ blake2b_sigma[r][2*i+1] ]; - ((uint2*)d)[0] = ROR16( ((uint2*)d)[0] ^ ((uint2*)a)[0] ); - *c += *d; - ((uint2*)b)[0] = ROR2( ((uint2*)b)[0] ^ ((uint2*)c)[0], 63U); -} - -#define ROUND(r) \ - G(r, 0, &v[0], &v[4], &v[ 8], &v[12], m); \ - G(r, 1, &v[1], &v[5], &v[ 9], &v[13], m); \ - G(r, 2, &v[2], &v[6], &v[10], &v[14], m); \ - G(r, 3, &v[3], &v[7], &v[11], &v[15], m); \ - G(r, 4, &v[0], &v[5], &v[10], &v[15], m); \ - G(r, 5, &v[1], &v[6], &v[11], &v[12], m); \ - G(r, 6, &v[2], &v[7], &v[ 8], &v[13], m); \ - G(r, 7, &v[3], &v[4], &v[ 9], &v[14], m); - -void blake2b_gpu_hash(blake2b_state *state, uint32_t idx, uint8_t *hash, uint32_t outlen) { - const uint32_t leb = idx; - *(uint32_t*)(state->buf + state->buflen) = leb; - state->buflen += 4; - state->counter += state->buflen; - for (unsigned i = 0; i < BLAKE2B_BLOCKBYTES - state->buflen; i++) - state->buf[i+state->buflen] = 0; - - uint64_t *d_data = (uint64_t *)state->buf; - uint64_t m[16]; - - m[0] = d_data[0]; - m[1] = d_data[1]; - m[2] = d_data[2]; - m[3] = d_data[3]; - m[4] = d_data[4]; - m[5] = d_data[5]; - m[6] = d_data[6]; - m[7] = d_data[7]; - m[8] = d_data[8]; - m[9] = d_data[9]; - m[10] = d_data[10]; - m[11] = d_data[11]; - m[12] = d_data[12]; - m[13] = d_data[13]; - m[14] = d_data[14]; - m[15] = d_data[15]; - - uint64_t v[16]; - - v[0] = state->h[0]; - v[1] = state->h[1]; - v[2] = state->h[2]; - v[3] = state->h[3]; - v[4] = state->h[4]; - v[5] = state->h[5]; - v[6] = state->h[6]; - v[7] = state->h[7]; - v[8] = 0x6a09e667f3bcc908; - v[9] = 0xbb67ae8584caa73b; - v[10] = 0x3c6ef372fe94f82b; - v[11] = 0xa54ff53a5f1d36f1; - v[12] = 0x510e527fade682d1 ^ state->counter; - v[13] = 0x9b05688c2b3e6c1f; - v[14] = 0x1f83d9abfb41bd6b ^ 0xffffffffffffffff; - v[15] = 0x5be0cd19137e2179; - - ROUND( 0 ); - ROUND( 1 ); - ROUND( 2 ); - ROUND( 3 ); - ROUND( 4 ); - ROUND( 5 ); - ROUND( 6 ); - ROUND( 7 ); - ROUND( 8 ); - ROUND( 9 ); - ROUND( 10 ); - ROUND( 11 ); - - state->h[0] ^= v[0] ^ v[ 8]; - state->h[1] ^= v[1] ^ v[ 9]; - state->h[2] ^= v[2] ^ v[10]; - state->h[3] ^= v[3] ^ v[11]; - state->h[4] ^= v[4] ^ v[12]; - state->h[5] ^= v[5] ^ v[13]; - state->h[6] ^= v[6] ^ v[14]; - state->h[7] ^= v[7] ^ v[15]; - - for (unsigned i = 0; i < outlen; i++) - hash[i] = ((uint8_t*)state->h)[i]; -} diff --git a/ocl_xpm/zcash/gpu/common.h b/ocl_xpm/zcash/gpu/common.h deleted file mode 100644 index 8c7727406..000000000 --- a/ocl_xpm/zcash/gpu/common.h +++ /dev/null @@ -1,159 +0,0 @@ -#if defined(__OPENCL_HOST__) -#define __global -//#include "blake2/blake2.h" -//#include "equi.h" -#include "../cpu_tromp/equi.h" - -#else -typedef char int8_t; -typedef uchar uint8_t; -typedef short int16_t; -typedef ushort uint16_t; -typedef int int32_t; -typedef uint uint32_t; -typedef long int64_t; -typedef ulong uint64_t; - -#if defined(_MSC_VER) -#define ALIGN(x) __declspec(align(x)) -#else -#define ALIGN(x) __attribute__ ((__aligned__(x))) -#endif - -enum blake2b_constant -{ - BLAKE2B_BLOCKBYTES = 128, - BLAKE2B_OUTBYTES = 64, - BLAKE2B_KEYBYTES = 64, - BLAKE2B_SALTBYTES = 16, - BLAKE2B_PERSONALBYTES = 16 -}; - -#pragma pack(push, 1) -ALIGN( 64 ) typedef struct __blake2b_state { - uint64_t h[8]; - uint8_t buf[BLAKE2B_BLOCKBYTES]; - uint16_t counter; - uint8_t buflen; - uint8_t lastblock; -} blake2b_state; -#pragma pack(pop) -#endif - -#define COLLISION_BIT_LENGTH (WN / (WK+1)) -#define COLLISION_BYTE_LENGTH ((COLLISION_BIT_LENGTH+7)/8) -#define FINAL_FULL_WIDTH (2*COLLISION_BYTE_LENGTH+sizeof(uint32_t)*(1 << (WK))) - - -#define NDIGITS (WK+1) -#define DIGITBITS (WN/(NDIGITS)) -//#define PROOFSIZE (1u< 64 -#error cant use XBITMAP with more than 64 slots -#endif - uint64_t xhashmap[NRESTS]; - uint64_t xmap; -#else - xslot nxhashslots[NRESTS]; - xslot xhashslots[NRESTS][XFULL]; - xslot *xx; - uint32_t n0; - uint32_t n1; -#endif - uint32_t s0; -} collisiondata; - - -typedef struct equi { - blake2b_state blake_ctx; - htalloc hta; - __global bsizes *nslots; - __global proof *sols; - uint32_t nsols; - uint32_t nthreads; -} equi; diff --git a/ocl_xpm/zcash/gpu/equihash.cl b/ocl_xpm/zcash/gpu/equihash.cl deleted file mode 100644 index 213a8e4d6..000000000 --- a/ocl_xpm/zcash/gpu/equihash.cl +++ /dev/null @@ -1,1038 +0,0 @@ -#include "common.h" - -#include "blake2bcl.h" - -#define tree0_ptr(heap, r) ((__global bucket0 *)(heap + r)) -#define tree1_ptr(heap, r) ((__global bucket1 *)(heap + r)) - -uint32_t tree_bucket(tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS) & SLOTMASK; -} - -uint32_t tree_slotid1(tree t) -{ - const uint32_t slotMask = ((1u<> (BUCKBITS+SLOTBITS)) & SLOTMASK; -} - -uint32_t tree_xhash(tree t) -{ - return t >> (2*SLOTBITS + BUCKBITS); -} - -uint32_t tree_getindex(const tree t) -{ - const uint32_t bucketMask = ((1u<> BUCKBITS); -} - -void tree_setindex(tree *t, uint32_t idx) -{ - const uint32_t bucketMask = ((1u<> SLOTBITS); - (*t) |= ((idx & slotMask) << BUCKBITS); -} - -void tree_setxhash(tree *t, uint32_t xhash) -{ - const uint32_t xhashMask = ((1u << RESTBITS)-1); - (*t) &= ~(xhashMask << (2*SLOTBITS + BUCKBITS)); - (*t) |= (xhash << (2*SLOTBITS + BUCKBITS)); -} - -tree tree_create3(uint32_t bucketId, uint32_t s0, uint32_t s1) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)); -} - -tree tree_create4(uint32_t bucketId, uint32_t s0, uint32_t s1, uint32_t xhash) -{ - return bucketId | (s0 << BUCKBITS) | (s1 << (BUCKBITS+SLOTBITS)) | (xhash << (2*SLOTBITS+BUCKBITS));; -} - -// size (in bytes) of hash in round 0 <= r < WK -uint32_t hashsize(const uint32_t r) -{ -#ifdef XINTREE - const uint32_t hashbits = WN - (r+1) * DIGITBITS; -#else - const uint32_t hashbits = WN - (r+1) * DIGITBITS + RESTBITS; -#endif - return (hashbits + 7) / 8; -} - -uint32_t hashwords(uint32_t bytes) -{ - return (bytes + 3) / 4; -} - -htlayout htlayout_create_2(uint32_t r) -{ - htlayout R; - R.prevhashunits = 0; - R.dunits = 0; - - uint32_t nexthashbytes = hashsize(r); - R.nexthashunits = hashwords(nexthashbytes); - - R.prevbo = 0; - R.nextbo = R.nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3 - if (r) { - uint32_t prevhashbytes = hashsize(r-1); - R.prevhashunits = hashwords(prevhashbytes); - R.prevbo = R.prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3 - R.dunits = R.prevhashunits - R.nexthashunits; - } - - return R; -} - -uint32_t htlayout_getxhash0(uint32_t prevbo, __global const slot0 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] >> 4; -#elif WN == 200 && RESTBITS == 8 - return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return (pslot->hash->bytes[prevbo] & 0x3) << 4 | pslot->hash->bytes[prevbo+1] >> 4; -#else -#error non implemented -#endif -} - -uint32_t htlayout_getxhash1(uint32_t prevbo, __global const slot1 *pslot) -{ -#ifdef XINTREE - return tree_xhash(pslot->attr); -#elif WN == 200 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 8 - return pslot->hash->bytes[prevbo]; -#elif WN == 144 && RESTBITS == 4 - return pslot->hash->bytes[prevbo] & 0xf; -#elif WN == 200 && RESTBITS == 6 - return pslot->hash->bytes[prevbo] & 0x3f; -#else -#error non implemented -#endif -} - -bool htlayout_equal(uint32_t prevhashunits, __global const hashunit *hash0, __global const hashunit *hash1) -{ - return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word; -} - -void collisiondata_clear(collisiondata *data) -{ -#ifdef XBITMAP - // memset(xhashmap, 0, NRESTS * sizeof(u64)); - for (unsigned i = 0; i < NRESTS; i++) - data->xhashmap[i] = 0; -#else - // memset(nxhashslots, 0, NRESTS * sizeof(xslot)); - for (unsigned i = 0; i < NRESTS; i++) - data->nxhashslots[i] = 0; -#endif -} - -bool collisiondata_addslot(collisiondata *data, uint32_t s1, uint32_t xh) -{ -#ifdef XBITMAP - data->xmap = data->xhashmap[xh]; - data->xhashmap[xh] |= (uint64_t)1 << s1; - data->s0 = ~0; - return true; -#else - data->n1 = (uint32_t)data->nxhashslots[xh]++; - if (data->n1 >= XFULL) - return false; - data->xx = data->xhashslots[xh]; - data->xx[data->n1] = s1; - data->n0 = 0; - return true; -#endif -} - -bool collisiondata_nextcollision(collisiondata *data) -{ -#ifdef XBITMAP - return data->xmap != 0; -#else - return data->n0 < data->n1; -#endif -} - -uint64_t __ffsll(uint64_t x) -{ - return x ? (64 - clz(x & -x)) : 0; -} - -uint32_t collisiondata_slot(collisiondata *data) { -#ifdef XBITMAP - const uint32_t ffs = __ffsll(xmap); - data->s0 += ffs; - data->xmap >>= ffs; - return data->s0; -#else - return (uint32_t)data->xx[data->n0++]; -#endif -} - -uint32_t equi_getnslots(__global bsizes *nslots, const uint32_t r, const uint32_t bid) -{ - __global uint32_t *nslot = &nslots[r&1][bid]; - const uint32_t n = min(*nslot, NSLOTS); - *nslot = 0; - return n; -} - -void equi_orderindices(__global uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - -void local_orderindices(uint32_t *indices, uint32_t size) -{ - if (indices[0] > indices[size]) { - for (uint32_t i = 0; i < size; i++) { - const uint32_t tmp = indices[i]; - indices[i] = indices[size+i]; - indices[size+i] = tmp; - } - } -} - - -void equi_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - equi_orderindices(indices, size); -} - -void equi_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - equi_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - equi_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - equi_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - equi_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - equi_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - equi_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - equi_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void equi_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - __global uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - equi_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - equi_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - equi_orderindices(indices, size); -} - -void local_listindices1(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 0; - indices[0] = tree_getindex((*buck)[tree_slotid0(t)].attr); - indices[size] = tree_getindex((*buck)[tree_slotid1(t)].attr); - local_orderindices(indices, size); -} - -void local_listindices2(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 0)[tree_bucket(t)]; - const uint32_t size = 1 << 1; - local_listindices1(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices1(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices3(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 2; - local_listindices2(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices2(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices4(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 1)[tree_bucket(t)]; - const uint32_t size = 1 << 3; - local_listindices3(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices3(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices5(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 4; - local_listindices4(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices4(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices6(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 2)[tree_bucket(t)]; - const uint32_t size = 1 << 5; - local_listindices5(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices5(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices7(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 6; - local_listindices6(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices6(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices8(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket1 *buck = &tree1_ptr(heap1, 3)[tree_bucket(t)]; - const uint32_t size = 1 << 7; - local_listindices7(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices7(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -void local_listindices9(__global uint32_t *heap0, - __global uint32_t *heap1, - const tree t, - uint32_t *indices) -{ - const __global bucket0 *buck = &tree0_ptr(heap0, 4)[tree_bucket(t)]; - const uint32_t size = 1 << 8; - local_listindices8(heap0, heap1, (*buck)[tree_slotid0(t)].attr, indices); - local_listindices8(heap0, heap1, (*buck)[tree_slotid1(t)].attr, indices+size); - local_orderindices(indices, size); -} - -// proper dupe test is a little costly on GPU, so allow false negatives -bool equi_probdupe(uint32_t *prf) { - unsigned short susp[PROOFSIZE]; - for (unsigned i = 0; i < PROOFSIZE; i++) - susp[i] = 0xFFFF; - - for (unsigned i = 0; i < PROOFSIZE; i++) { - uint32_t bin = prf[i] & (PROOFSIZE-1); - unsigned short msb = prf[i] >> WK; - if (msb == susp[bin]) - return true; - susp[bin] = msb; - } - - return false; -} - -void equi_candidate(__global uint32_t *heap0, - __global uint32_t *heap1, - __global proof *sols, - __global uint32_t *nsols, - const tree t) -{ - proof prf; -#if WK==9 - local_listindices9(heap0, heap1, t, (uint32_t*)&prf); -#elif WK==5 - local_listindices5(heap0, heap1, t, (uint32_t*)&prf); -#else -#error not implemented -#endif - if (equi_probdupe(prf)) - return; - uint32_t soli = atomic_inc(nsols); - if (soli < MAXSOLS) -#if WK==9 - equi_listindices9(heap0, heap1, t, sols[soli]); -#elif WK==5 - equi_listindices5(heap0, heap1, t, sols[soli]); -#else -#error not implemented -#endif -} - - -__kernel void digitH(__global blake2b_state *blake2bState, - __global const uint32_t *heap0, - __global bsizes *nslots) -{ - uint8_t hash[HASHOUT]; - blake2b_state state; - // equi::htlayout htl(eq, 0); - htlayout htl = htlayout_create_2(0); - const uint32_t hashbytes = hashsize(0); - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - for (uint32_t block = id; block < NBLOCKS; block += get_global_size(0)) { - state = *blake2bState; - blake2b_gpu_hash(&state, block, hash, HASHOUT); - for (uint32_t i = 0; i < HASHESPERBLAKE; i++) { - const uint8_t *ph = hash + i * WN/8; -#if BUCKBITS == 16 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 8) | ph[1]; -#ifdef XINTREE - const uint32_t xhash = ph[2] >> 4; -#endif -#elif BUCKBITS == 14 && RESTBITS == 6 - const uint32_t bucketid = ((uint32_t)ph[0] << 6) | ph[1] >> 2; -#elif BUCKBITS == 12 && RESTBITS == 8 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; -#elif BUCKBITS == 20 && RESTBITS == 4 - const uint32_t bucketid = ((((uint32_t)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4; -#ifdef XINTREE - const uint32_t xhash = ph[2] & 0xf; -#endif -#elif BUCKBITS == 12 && RESTBITS == 4 - const uint32_t bucketid = ((uint32_t)ph[0] << 4) | ph[1] >> 4; - const uint32_t xhash = ph[1] & 0xf; -#else -#error not implemented -#endif - const uint32_t slot = atomic_inc(&nslots[0][bucketid]); - if (slot >= NSLOTS) - continue; - tree leaf; - tree_setindex(&leaf, block*HASHESPERBLAKE+i); -#ifdef XINTREE - tree_setxhash(&leaf, xhash); -#endif - __global slot0 *s = &tree0_ptr(heap0, 0)[bucketid][slot]; - s->attr = leaf; - - // memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes); - for (unsigned i = 0; i < hashbytes; i++) - ((__global uint8_t*)s->hash->bytes+htl.nextbo)[i] = ((uint8_t*)(ph+WN/8-hashbytes))[i]; - } - } -} - -__kernel void digitOdd(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?! - __global slot0 *buck = tree0_ptr(heap0, (r-1)/2)[bucketid]; // optimize by updating previous buck?! - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); // optimize by putting bucketsize with block?! - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?! - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (xhash = bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; - xhash &= 0xf; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 2 - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 6; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot1 *xs = &htl.hta.trees1[r/2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i = htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -__kernel void digitEven(const uint32_t r, - __global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - // equi::htlayout htl(eq, r); -// htlayout htl = htlayout_create(eq, r); - htlayout htl = htlayout_create_2(r); - collisiondata cd; - - // const uint32_t id = blockIdx.x * blockDim.x + threadIdx.x; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - // cd.clear(); - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - __global slot1 *buck = tree1_ptr(heap1, (r-1)/2)[bucketid]; // OPTIMIZE BY UPDATING PREVIOUS - uint32_t bsize = equi_getnslots(nslots, r-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; -#if WN == 200 && BUCKBITS == 16 && RESTBITS == 4 && defined(XINTREE) - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4 - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4) - | (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4; -#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; -#elif WN == 200 && BUCKBITS == 14 && RESTBITS == 6 - xorbucketid = ((uint32_t)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 6) - | (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 2; -#else -#error not implemented -#endif - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; -#ifdef XINTREE - tree xort = tree_create4(bucketid, s0, s1, xhash); -#else - tree xort = tree_create3(bucketid, s0, s1); -#endif -// __global slot0 *xs = &htl.hta.trees0[r/2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, r/2)[xorbucketid][xorslot]; - xs->attr = xort; - for (uint32_t i=htl.dunits; i < htl.prevhashunits; i++) - xs->hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word; - } - } - } -} - - -#ifdef UNROLL - -__kernel void digit_1(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) -{ - htlayout htl = htlayout_create_2(1); - collisiondata cd; - const uint32_t id = get_global_id(0); - - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 0, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[0][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 0)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - xs->hash[4].word = pslot0->hash[5].word ^ pslot1->hash[5].word; - } - } - } -} -__kernel void digit_2(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(2); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[0][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 0)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); - // __global slot0 *xs = &htl.hta.trees0[1][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[4].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_3(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(3); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[1][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 2, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[1][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 1)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - xs->hash[3].word = pslot0->hash[4].word ^ pslot1->hash[4].word; - } - } - } -} -__kernel void digit_4(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(4); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[1][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 1)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 3, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[2][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[2].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[3].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_5(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(5); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[2][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 4, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[2][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 2)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - xs->hash[2].word = pslot0->hash[3].word ^ pslot1->hash[3].word; - } - } - } -} -__kernel void digit_6(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(6); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[2][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 5, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[3][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - xs->hash[1].word = pslot0->hash[2].word ^ pslot1->hash[2].word; - } - } - } -} -__kernel void digit_7(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(7); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot0 *buck = htl.hta.trees0[3][bucketid]; - __global slot0 *buck = tree0_ptr(heap0, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 6, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) & 0xf) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1])) << 4 - | (xhash = bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - xhash &= 0xf; - const uint32_t xorslot = atomic_inc(&nslots[1][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot1 *xs = &htl.hta.trees1[3][xorbucketid][xorslot]; - __global slot1 *xs = &tree1_ptr(heap1, 3)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[0].word ^ pslot1->hash[0].word; - xs->hash[1].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -__kernel void digit_8(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots) { - htlayout htl = htlayout_create_2(8); - collisiondata cd; - const uint32_t id = get_global_id(0); - for (uint32_t bucketid=id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); -// __global slot1 *buck = htl.hta.trees1[3][bucketid]; - __global slot1 *buck = tree1_ptr(heap1, 3)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, 7, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash1(htl.prevbo, pslot1))) - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot1 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) - continue; - uint32_t xorbucketid; - uint32_t xhash; - __global const uint8_t *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes; - xorbucketid = ((uint32_t)(bytes0[htl.prevbo] ^ bytes1[htl.prevbo]) << 8) - | (bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]); - xhash = (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4; - const uint32_t xorslot = atomic_inc(&nslots[0][xorbucketid]); - if (xorslot >= NSLOTS) - continue; - tree xort = tree_create4(bucketid, s0, s1, xhash); -// __global slot0 *xs = &htl.hta.trees0[4][xorbucketid][xorslot]; - __global slot0 *xs = &tree0_ptr(heap0, 4)[xorbucketid][xorslot]; - xs->attr = xort; - xs->hash[0].word = pslot0->hash[1].word ^ pslot1->hash[1].word; - } - } - } -} -#endif //UNROLL - -__kernel void digitK(__global uint32_t *heap0, - __global uint32_t *heap1, - __global bsizes *nslots, - __global proof *sols, - __global uint32_t *nsols) { - collisiondata cd; - htlayout htl = htlayout_create_2(WK); - const uint32_t id = get_global_id(0); - for (uint32_t bucketid = id; bucketid < NBUCKETS; bucketid += get_global_size(0)) { - collisiondata_clear(&cd); - __global slot0 *buck = tree0_ptr(heap0, (WK-1)/2)[bucketid]; - uint32_t bsize = equi_getnslots(nslots, WK-1, bucketid); - for (uint32_t s1 = 0; s1 < bsize; s1++) { - __global const slot0 *pslot1 = buck + s1; - if (!collisiondata_addslot(&cd, s1, htlayout_getxhash0(htl.prevbo, pslot1))) // assume WK odd - continue; - for (; collisiondata_nextcollision(&cd); ) { - const uint32_t s0 = collisiondata_slot(&cd); - __global const slot0 *pslot0 = buck + s0; - if (htlayout_equal(htl.prevhashunits, pslot0->hash, pslot1->hash)) { - tree xort = tree_create3(bucketid, s0, s1); - equi_candidate(heap0, heap1, sols, nsols, xort); - } - } - } - } -} From 1392ee88455c3bd0e079ff061a0acc9c9dec61d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 11:00:06 +0100 Subject: [PATCH 06/15] increase max instances from 8 to 16, clear opencl help --- nheqminer/main.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index 49f572d8f..aec7996a1 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -93,15 +93,15 @@ void print_help() std::cout << "\t-ct [tpb]\tNumber of threads per block" << std::endl; std::cout << "Example: -cd 0 2 -cb 12 16 -ct 64 128" << std::endl; std::cout << std::endl; - std::cout << "OpenCL settings" << std::endl; - std::cout << "\t-oi\t\tOpenCL info" << std::endl; - std::cout << "\t-ov [ver]\tSet OpenCL solver (0 = silentarmy, 1 = xmp)" << std::endl; - std::cout << "\t-op [platf]\tSet OpenCL platform to selecd platform devices (-od)" << std::endl; - std::cout << "\t-od [devices]\tEnable OpenCL mining on spec. devices (specify plafrom number first -op)" << std::endl; - std::cout << "\t-ot [threads]\tSet number of threads per device" << std::endl; - //std::cout << "\t-cb [blocks]\tNumber of blocks" << std::endl; - //std::cout << "\t-ct [tpb]\tNumber of threads per block" << std::endl; - std::cout << "Example: -op 2 -od 0 2" << std::endl; //-cb 12 16 -ct 64 128" << std::endl; + //std::cout << "OpenCL settings" << std::endl; + //std::cout << "\t-oi\t\tOpenCL info" << std::endl; + //std::cout << "\t-ov [ver]\tSet OpenCL solver (0 = silentarmy, 1 = xmp)" << std::endl; + //std::cout << "\t-op [platf]\tSet OpenCL platform to selecd platform devices (-od)" << std::endl; + //std::cout << "\t-od [devices]\tEnable OpenCL mining on spec. devices (specify plafrom number first -op)" << std::endl; + //std::cout << "\t-ot [threads]\tSet number of threads per device" << std::endl; + ////std::cout << "\t-cb [blocks]\tNumber of blocks" << std::endl; + ////std::cout << "\t-ct [tpb]\tNumber of threads per block" << std::endl; + //std::cout << "Example: -op 2 -od 0 2" << std::endl; //-cb 12 16 -ct 64 128" << std::endl; std::cout << std::endl; } @@ -127,13 +127,14 @@ void print_opencl_info() { #endif } +#define MAX_INSTANCES 8 * 2 -int cuda_enabled[8] = { 0 }; -int cuda_blocks[8] = { 0 }; -int cuda_tpb[8] = { 0 }; +int cuda_enabled[MAX_INSTANCES] = { 0 }; +int cuda_blocks[MAX_INSTANCES] = { 0 }; +int cuda_tpb[MAX_INSTANCES] = { 0 }; -int opencl_enabled[8] = { 0 }; -int opencl_threads[8] = { 0 }; +int opencl_enabled[MAX_INSTANCES] = { 0 }; +int opencl_threads[MAX_INSTANCES] = { 0 }; // todo: opencl local and global worksize From d02d57e4e1dcc62ddb5e533d17b698595a2bed49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 11:59:31 +0100 Subject: [PATCH 07/15] remove AMD Linux cmake, add cuda_djezo cmake, make build on Linux, make c++11 compliant --- .../CMakeLists.txt | 118 ++++++++++-------- nheqminer/AvailableSolvers.h | 5 +- nheqminer/MinerFactory.cpp | 34 +++-- nheqminer/MinerFactory.h | 3 +- nheqminer/libstratum/ZcashStratum.cpp | 10 +- nheqminer/main.cpp | 111 ++++++++-------- nheqminer/nheqminer.vcxproj | 2 +- 7 files changed, 160 insertions(+), 123 deletions(-) rename Linux_cmake/{nheqminer_AMD => nheqminer_cuda_djezo}/CMakeLists.txt (64%) diff --git a/Linux_cmake/nheqminer_AMD/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt similarity index 64% rename from Linux_cmake/nheqminer_AMD/CMakeLists.txt rename to Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt index 40c1dabb2..4a29b420d 100644 --- a/Linux_cmake/nheqminer_AMD/CMakeLists.txt +++ b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt @@ -1,8 +1,7 @@ -project(nheqminer_AMD) +project(nheqminer_cuda_djezo) cmake_minimum_required(VERSION 2.8) -#aux_source_directory(. SRC_LIST) -#add_executable(${PROJECT_NAME} ${SRC_LIST}) +option(ENABLE_CUDA "Enable the cuda build" ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") @@ -20,9 +19,35 @@ include_directories(${nheqminer_SOURCE_DIR}) add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) + +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) + +add_definitions(-DHIST) +#add_definitions(-DXINTREE) +#add_definitions(-DUNROLL) + +list(APPEND CUDA_NVCC_FLAGS_RELEASE -O3) + + +FIND_PACKAGE(CUDA REQUIRED) +if(COMPUTE AND (COMPUTE GREATER 0)) + LIST(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_${COMPUTE},code=sm_${COMPUTE}) +else(COMPUTE AND (COMPUTE GREATER 0)) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; -gencode arch=compute_61,code=sm_61 ) +endif(COMPUTE AND (COMPUTE GREATER 0)) + +include_directories(${CUDA_INCLUDE_DIRS}) + find_package(Threads REQUIRED COMPONENTS) find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) +if(CUDA_FOUND) +message("CUDA FOUND") +else() +message("CUDA NOT FOUND") +endif() + if (Boost_FOUND) # From the offical documentation: # Add include directories to the build. [...] If the SYSTEM option is given, @@ -45,8 +70,7 @@ endif () ## Add solvers here #add_definitions(-DUSE_CPU_XENONCAT) #add_definitions(-DUSE_CPU_TROMP) -add_definitions(-DUSE_OCL_XMP) -add_definitions(-DUSE_OCL_SILENTARMY) +add_definitions(-DUSE_CUDA_DJEZO) #add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) #set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx1.o" ) @@ -55,11 +79,6 @@ add_definitions(-DUSE_OCL_SILENTARMY) #set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx2.o" ) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../ocl_device_utils/) - -# OCL INC DIR -include_directories(${OPENCL_INCLUDE_DIRECTORY}) - set(SOURCE_FILES # sources @@ -113,51 +132,52 @@ set(SOURCE_FILES ../../nheqminer/zcash/Zcash.h ../../nheqminer/SolverStub.h # just a stub - ## cpu tromp - #../../cpu_tromp/blake2/blake2bx.cpp - #../../cpu_tromp/cpu_tromp.cpp - #../../cpu_tromp/blake2/blake2-config.h - #../../cpu_tromp/blake2/blake2-impl.h - #../../cpu_tromp/blake2/blake2-round.h - #../../cpu_tromp/blake2/blake2.h - #../../cpu_tromp/blake2/blake2b-load-sse2.h - #../../cpu_tromp/blake2/blake2b-load-sse41.h - #../../cpu_tromp/blake2/blake2b-round.h - #../../cpu_tromp/cpu_tromp.hpp - #../../cpu_tromp/equi.h - #../../cpu_tromp/equi_miner.h -# - ## cpu xenocat - #../../cpu_xenoncat/cpu_xenoncat.hpp - #../../cpu_xenoncat/xenoncat.cpp -# - # AMD ocl_device_utils - ../../ocl_device_utils/cl_ext.hpp - ../../ocl_device_utils/ocl_device_utils.h - ../../ocl_device_utils/ocl_device_utils.cpp - ../../ocl_device_utils/OpenCLDevice.h - ../../ocl_device_utils/opencl.h - ../../ocl_device_utils/opencl.cpp - # AMD ocl_xpm - ../../ocl_xpm/ocl_xmp.hpp - ../../ocl_xpm/ocl_xmp.cpp - ../../ocl_xpm/zcash/gpu/common.h + ../../nheqminer/AvailableSolvers.h + ../../nheqminer/ISolver.h + ../../nheqminer/Solver.h + ../../nheqminer/MinerFactory.h + ../../nheqminer/MinerFactory.cpp + +# # cpu tromp +# ../../cpu_tromp/blake2/blake2bx.cpp +# ../../cpu_tromp/cpu_tromp.cpp +# ../../cpu_tromp/blake2/blake2-config.h +# ../../cpu_tromp/blake2/blake2-impl.h +# ../../cpu_tromp/blake2/blake2-round.h +# ../../cpu_tromp/blake2/blake2.h +# ../../cpu_tromp/blake2/blake2b-load-sse2.h +# ../../cpu_tromp/blake2/blake2b-load-sse41.h +# ../../cpu_tromp/blake2/blake2b-round.h +# ../../cpu_tromp/cpu_tromp.hpp +# ../../cpu_tromp/equi.h +# ../../cpu_tromp/equi_miner.h + +# # cpu xenocat +# ../../cpu_xenoncat/cpu_xenoncat.hpp +# ../../cpu_xenoncat/xenoncat.cpp + +# # cuda tromp +# ../../cuda_tromp/cuda_tromp.hpp +# ../../cuda_tromp/cuda_tromp.cpp +# ../../cuda_tromp/eqcuda.hpp +# ../../cuda_tromp/equi_miner.cu ../../cpu_tromp/blake2/blake2bx.cpp - # AMD ocl_silentarmy - ../../ocl_silentarmy/ocl_silentarmy.hpp - ../../ocl_silentarmy/param.h - ../../ocl_silentarmy/sa_blake.h - ../../ocl_silentarmy/ocl_silentarmy.cpp - ../../ocl_silentarmy/sa_blake.cpp + + # cuda djezo + ../../cuda_djezo/cuda_djezo.cpp + ../../cuda_djezo/cuda_djezo.hpp + ../../cuda_djezo/equi_miner.cu + ../../cuda_djezo/eqcuda.hpp + ) #add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(LIBS ${LIBS} ${Boost_LIBRARIES} ${OPENCL_LIBRARY}) +set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES} "cuda") #message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") #message("-- LIBS: ${LIBS}") -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +#add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) +CUDA_ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCE_FILES}) +target_link_libraries(${PROJECT_NAME} ${LIBS} ${CUDA_LIBRARIES} ) diff --git a/nheqminer/AvailableSolvers.h b/nheqminer/AvailableSolvers.h index 07bf23108..a071ae3b5 100644 --- a/nheqminer/AvailableSolvers.h +++ b/nheqminer/AvailableSolvers.h @@ -16,9 +16,12 @@ CREATE_SOLVER_STUB(cpu_xenoncat, "cpu_xenoncat_STUB") #endif #ifdef USE_CUDA_TROMP #include "../cuda_tromp/cuda_tromp.hpp" -#include "../cuda_djezo/cuda_djezo.hpp" #else CREATE_SOLVER_STUB(cuda_tromp, "cuda_tromp_STUB") +#endif +#ifdef USE_CUDA_DJEZO +#include "../cuda_djezo/cuda_djezo.hpp" +#else CREATE_SOLVER_STUB(cuda_djezo, "cuda_djezo_STUB") #endif // OpenCL solvers are fropped replace with new OS solvers diff --git a/nheqminer/MinerFactory.cpp b/nheqminer/MinerFactory.cpp index dd6a06bee..7a0102e4c 100644 --- a/nheqminer/MinerFactory.cpp +++ b/nheqminer/MinerFactory.cpp @@ -5,8 +5,11 @@ extern int use_avx; extern int use_avx2; + + MinerFactory::~MinerFactory() { + ClearAllSolvers(); } std::vector MinerFactory::GenerateSolvers(int cpu_threads, int cuda_count, int* cuda_en, int* cuda_b, int* cuda_t, @@ -44,37 +47,42 @@ std::vector MinerFactory::GenerateSolvers(int cpu_threads, int cuda_c } void MinerFactory::ClearAllSolvers() { + for (ISolver * ds : _solvers) { + if (ds != nullptr) { + delete ds; + } + } _solvers.clear(); } ISolver * MinerFactory::GenCPUSolver(int use_opt) { if (_use_xenoncat) { - _solvers.push_back(std::make_unique(use_opt)); - return _solvers.back().get(); + _solvers.push_back(new CPUSolverXenoncat(use_opt)); + return _solvers.back(); } else { - _solvers.push_back(std::make_unique(use_opt)); - return _solvers.back().get(); + _solvers.push_back(new CPUSolverTromp(use_opt)); + return _solvers.back(); } } ISolver * MinerFactory::GenCUDASolver(int dev_id, int blocks, int threadsperblock) { if (_use_cuda_djezo) { - _solvers.push_back(std::make_unique(dev_id, blocks, threadsperblock)); - return _solvers.back().get(); + _solvers.push_back(new CUDASolverDjezo(dev_id, blocks, threadsperblock)); + return _solvers.back(); } else { - _solvers.push_back(std::make_unique(dev_id, blocks, threadsperblock)); - return _solvers.back().get(); + _solvers.push_back(new CUDASolverTromp(dev_id, blocks, threadsperblock)); + return _solvers.back(); } } ISolver * MinerFactory::GenOPENCLSolver(int platf_id, int dev_id) { if (_use_silentarmy) { - _solvers.push_back(std::make_unique(platf_id, dev_id)); - return _solvers.back().get(); + _solvers.push_back(new OPENCLSolverSilentarmy(platf_id, dev_id)); + return _solvers.back(); } else { - _solvers.push_back(std::make_unique(platf_id, dev_id)); - return _solvers.back().get(); + _solvers.push_back(new OPENCLSolverXMP(platf_id, dev_id)); + return _solvers.back(); } -} \ No newline at end of file +} diff --git a/nheqminer/MinerFactory.h b/nheqminer/MinerFactory.h index 4a72e8075..94c63a0d7 100644 --- a/nheqminer/MinerFactory.h +++ b/nheqminer/MinerFactory.h @@ -1,7 +1,6 @@ #pragma once #include -#include class MinerFactory { @@ -17,7 +16,7 @@ class MinerFactory void ClearAllSolvers(); private: - std::vector> _solvers; + std::vector _solvers; bool _use_xenoncat = true; bool _use_cuda_djezo = true; diff --git a/nheqminer/libstratum/ZcashStratum.cpp b/nheqminer/libstratum/ZcashStratum.cpp index 1106d02b5..7eac71999 100644 --- a/nheqminer/libstratum/ZcashStratum.cpp +++ b/nheqminer/libstratum/ZcashStratum.cpp @@ -684,9 +684,13 @@ void Solvers_doBenchmark(int hashes, const std::vector &solvers) { // bind benchmark threads for (int i = 0; i < solvers.size(); ++i) { bthreads[i] = std::thread(boost::bind(&benchmark_thread, i, solvers[i])); - } - // TODO get back to this sleep - Sleep(1000); + } +#ifdef WIN32 + // TODO get back to this sleep + Sleep(1000); +#else + sleep(1); +#endif BOOST_LOG_TRIVIAL(info) << "Benchmark starting... this may take several minutes, please wait..."; diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index aec7996a1..78591189d 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -116,7 +116,11 @@ void print_cuda_info() { std::string gpuname, version; int smcount; - cuda_tromp::getinfo(0, i, gpuname, smcount, version); +#ifdef USE_CUDA_DJEZO + cuda_djezo::getinfo(0, i, gpuname, smcount, version); +#elif USE_CUDA_TROMP + cuda_tromp::getinfo(0, i, gpuname, smcount, version); +#endif std::cout << "\t#" << i << " " << gpuname << " | SM version: " << version << " | SM count: " << smcount << std::endl; } } @@ -233,9 +237,8 @@ int main(int argc, char* argv[]) std::cout << "\t==================== www.nicehash.com ====================" << std::endl; std::cout << "\t\tEquihash CPU&GPU Miner for NiceHash v" STANDALONE_MINER_VERSION << std::endl; std::cout << "\tThanks to Zcash developers for providing base of the code." << std::endl; - std::cout << "\t Special thanks to tromp, xenoncat, mbevand, djeZo, "<< std::endl; - std::cout << "\t and eXtremal-ik7 for providing " << std::endl; - std::cout << "\t optimized CPU, CUDA and AMD equihash solvers." << std::endl; + std::cout << "\t Special thanks to tromp, xenoncat and djeZo for providing "<< std::endl; + std::cout << "\t optimized CPU and CUDA equihash solvers." << std::endl; std::cout << "\t==================== www.nicehash.com ====================" << std::endl; std::cout << std::endl; @@ -272,7 +275,7 @@ int main(int argc, char* argv[]) use_old_cuda = atoi(argv[++i]); break; case 'd': - while (cuda_device_count < 8 && i + 1 < argc) + while (cuda_device_count < MAX_INSTANCES && i + 1 < argc) { try { @@ -287,7 +290,7 @@ int main(int argc, char* argv[]) } break; case 'b': - while (cuda_bc < 8 && i + 1 < argc) + while (cuda_bc < MAX_INSTANCES && i + 1 < argc) { try { @@ -302,7 +305,7 @@ int main(int argc, char* argv[]) } break; case 't': - while (cuda_tbpc < 8 && i + 1 < argc) + while (cuda_tbpc < MAX_INSTANCES && i + 1 < argc) { try { @@ -319,53 +322,53 @@ int main(int argc, char* argv[]) } break; } - case 'o': - { - switch (argv[i][2]) - { - case 'i': - print_opencl_info(); - return 0; - case 'v': - use_old_xmp = atoi(argv[++i]); - break; - case 'p': - opencl_platform = std::stol(argv[++i]); - break; - case 'd': - while (opencl_device_count < 8 && i + 1 < argc) - { - try - { - opencl_enabled[opencl_device_count] = std::stol(argv[++i]); - ++opencl_device_count; - } - catch (...) - { - --i; - break; - } - } - break; - case 't': - while (opencl_t < 8 && i + 1 < argc) - { - try - { - opencl_threads[opencl_t] = std::stol(argv[++i]); - ++opencl_t; - } - catch (...) - { - --i; - break; - } - } - break; - // TODO extra parameters for OpenCL - } - break; - } + //case 'o': + //{ + // switch (argv[i][2]) + // { + // case 'i': + // print_opencl_info(); + // return 0; + // case 'v': + // use_old_xmp = atoi(argv[++i]); + // break; + // case 'p': + // opencl_platform = std::stol(argv[++i]); + // break; + // case 'd': + // while (opencl_device_count < 8 && i + 1 < argc) + // { + // try + // { + // opencl_enabled[opencl_device_count] = std::stol(argv[++i]); + // ++opencl_device_count; + // } + // catch (...) + // { + // --i; + // break; + // } + // } + // break; + // case 't': + // while (opencl_t < 8 && i + 1 < argc) + // { + // try + // { + // opencl_threads[opencl_t] = std::stol(argv[++i]); + // ++opencl_t; + // } + // catch (...) + // { + // --i; + // break; + // } + // } + // break; + // // TODO extra parameters for OpenCL + // } + // break; + //} case 'l': location = argv[++i]; break; diff --git a/nheqminer/nheqminer.vcxproj b/nheqminer/nheqminer.vcxproj index 8aeb77e1e..bca0ab4be 100644 --- a/nheqminer/nheqminer.vcxproj +++ b/nheqminer/nheqminer.vcxproj @@ -84,7 +84,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;USE_CPU_TROMP;USE_CPU_XENONCAT;USE_CUDA_TROMP;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;USE_CPU_TROMP;USE_CPU_XENONCAT;USE_CUDA_TROMP;USE_CUDA_DJEZO;%(PreprocessorDefinitions) NotSet -D_WIN32_WINNT=0x0601 %(AdditionalOptions) 4068;4996;4503;4267;4180;4290;4244;4800;4334;4251 From 2935db7bad6e97516fd73d9d10ebeccbd0ee07f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 12:09:45 +0100 Subject: [PATCH 08/15] make cuda djezo static boost build --- .../nheqminer_cuda_djezo/CMakeLists.txt | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt index 4a29b420d..44f995eb4 100644 --- a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt +++ b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt @@ -17,7 +17,34 @@ endif() # Common include_directories(${nheqminer_SOURCE_DIR}) -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) +#add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) +# BOOST +#find_package(Threads REQUIRED COMPONENTS) +# compile boost staticaly +set(Boost_USE_STATIC_LIBS ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +#set(BUILD_SHARED_LIBRARIES OFF) +#set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") +find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) + +if (Boost_FOUND) + # From the offical documentation: + # Add include directories to the build. [...] If the SYSTEM option is given, + # the compiler will be told the directories are meant as system include + # directories on some platforms (signalling this setting might achieve effects + # such as the compiler skipping warnings [...])." + include_directories (SYSTEM ${Boost_INCLUDE_DIR}) + + # From the offical documentation: + # "Specify directories in which the linker will look for libraries. [...] Note + # that this command is rarely necessary. Library locations returned by + # find_package() and find_library() are absolute paths. Pass these absolute + # library file paths directly to the target_link_libraries() command. CMake + # will ensure the linker finds them." + link_directories (${Boost_LIBRARY_DIRS}) +else() + message("Boost_FOUND NOT FOUND") +endif () #set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) @@ -172,7 +199,7 @@ set(SOURCE_FILES ) #add_executable(${PROJECT_NAME} ${SRC_LIST}) -set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES} "cuda") +set(LIBS ${LIBS} ${Boost_LIBRARIES} "cuda") #message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") #message("-- LIBS: ${LIBS}") @@ -180,4 +207,4 @@ set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES} "cuda") #add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) CUDA_ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CUDA_LIBRARIES} ) +target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${LIBS} ${CUDA_LIBRARIES} ) From 24ea27c1ed9206f34e46f91ca16e15eec8c16d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 12:10:25 +0100 Subject: [PATCH 09/15] change version --- nheqminer/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nheqminer/version.h b/nheqminer/version.h index 21ecceb84..f30425f52 100644 --- a/nheqminer/version.h +++ b/nheqminer/version.h @@ -34,7 +34,7 @@ static const int BIP0031_VERSION = 60000; //! "mempool" command, enhanced "getdata" behavior starts with this version static const int MEMPOOL_GD_VERSION = 60002; -#define STANDALONE_MINER_VERSION "0.5a" +#define STANDALONE_MINER_VERSION "0.5b" // uncomment to use with ZCash address //#define ZCASH_POOL From 8eb99a7be09e12145e8ef384aa558f5459aba666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 13:06:41 +0100 Subject: [PATCH 10/15] fix VS build --- nheqminer/nheqminer.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nheqminer/nheqminer.vcxproj b/nheqminer/nheqminer.vcxproj index bca0ab4be..f37bb361f 100644 --- a/nheqminer/nheqminer.vcxproj +++ b/nheqminer/nheqminer.vcxproj @@ -96,8 +96,8 @@ true true true - cuda_djezo.lib;cuda_tromp.lib;cuda_tromp_75.lib;cpu_xenoncat.lib;cpu_tromp_SSE2.lib;cpu_tromp_AVX.lib;ocl_device_utils.lib;ocl_xpm.lib;ocl_silentarmy.lib;OpenCL.lib - .\trompequihash\pthreads\x64;..\3rdparty\libs\win64;$(AMDAPPSDKROOT)\lib\x86_64\;%(AdditionalLibraryDirectories) + cuda_djezo.lib;cuda_tromp.lib;cuda_tromp_75.lib;cpu_xenoncat.lib;cpu_tromp_SSE2.lib;cpu_tromp_AVX.lib + .\trompequihash\pthreads\x64;..\3rdparty\libs\win64;%(AdditionalLibraryDirectories) From d56e5e8e26a9e694f142abf26c9fe9f1ab889d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 14:07:33 +0100 Subject: [PATCH 11/15] readme update --- .../nheqminer_cuda_djezo/CMakeLists.txt | 26 +-------- .../nheqminer_cuda_tromp/CMakeLists.txt | 55 ++++++++++++------- README.md | 27 ++++----- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt index 44f995eb4..2c9e761c9 100644 --- a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt +++ b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt @@ -47,15 +47,13 @@ else() endif () #set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) - -set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-D_FORCE_INLINES;--disable-warnings;--ptxas-options=-v;-Xptxas=-dlcm=ca;-Xptxas=-dscm=cs; -O3) add_definitions(-DHIST) #add_definitions(-DXINTREE) #add_definitions(-DUNROLL) -list(APPEND CUDA_NVCC_FLAGS_RELEASE -O3) - FIND_PACKAGE(CUDA REQUIRED) if(COMPUTE AND (COMPUTE GREATER 0)) @@ -66,7 +64,6 @@ endif(COMPUTE AND (COMPUTE GREATER 0)) include_directories(${CUDA_INCLUDE_DIRS}) -find_package(Threads REQUIRED COMPONENTS) find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) if(CUDA_FOUND) @@ -75,25 +72,6 @@ else() message("CUDA NOT FOUND") endif() -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - ## Add solvers here #add_definitions(-DUSE_CPU_XENONCAT) #add_definitions(-DUSE_CPU_TROMP) diff --git a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt index 1853b22de..11378b5e6 100644 --- a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt +++ b/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt @@ -17,7 +17,34 @@ endif() # Common include_directories(${nheqminer_SOURCE_DIR}) -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) +#add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) +# BOOST +#find_package(Threads REQUIRED COMPONENTS) +# compile boost staticaly +set(Boost_USE_STATIC_LIBS ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +#set(BUILD_SHARED_LIBRARIES OFF) +#set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") +find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) + +if (Boost_FOUND) + # From the offical documentation: + # Add include directories to the build. [...] If the SYSTEM option is given, + # the compiler will be told the directories are meant as system include + # directories on some platforms (signalling this setting might achieve effects + # such as the compiler skipping warnings [...])." + include_directories (SYSTEM ${Boost_INCLUDE_DIR}) + + # From the offical documentation: + # "Specify directories in which the linker will look for libraries. [...] Note + # that this command is rarely necessary. Library locations returned by + # find_package() and find_library() are absolute paths. Pass these absolute + # library file paths directly to the target_link_libraries() command. CMake + # will ensure the linker finds them." + link_directories (${Boost_LIBRARY_DIRS}) +else() + message("Boost_FOUND NOT FOUND") +endif () #set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) @@ -48,25 +75,6 @@ else() message("CUDA NOT FOUND") endif() -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - ## Add solvers here #add_definitions(-DUSE_CPU_XENONCAT) #add_definitions(-DUSE_CPU_TROMP) @@ -132,6 +140,13 @@ set(SOURCE_FILES ../../nheqminer/zcash/Zcash.h ../../nheqminer/SolverStub.h # just a stub + + ../../nheqminer/AvailableSolvers.h + ../../nheqminer/ISolver.h + ../../nheqminer/Solver.h + ../../nheqminer/MinerFactory.h + ../../nheqminer/MinerFactory.cpp + # # cpu tromp # ../../cpu_tromp/blake2/blake2bx.cpp # ../../cpu_tromp/cpu_tromp.cpp diff --git a/README.md b/README.md index b86402af9..5343f4e47 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,26 @@ Windows builds made by us are available here: https://github.com/nicehash/nheqminer/releases Download and install: -- [AMD APP SDK](http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/) (if not needed remove **USE_OCL_XMP** from **nheqminer** Preprocessor definitions under Properties > C/C++ > Preprocessor) -- [CUDA SDK](https://developer.nvidia.com/cuda-downloads) (if not needed remove **USE_CUDA_TROMP** from **nheqminer** Preprocessor definitions under Properties > C/C++ > Preprocessor) +- [CUDA SDK](https://developer.nvidia.com/cuda-downloads) (if not needed remove **USE_CUDA_TROMP** and **USE_CUDA_DJEZO** from **nheqminer** Preprocessor definitions under Properties > C/C++ > Preprocessor) - Visual Studio 2013 Community: https://www.visualstudio.com/en-us/news/releasenotes/vs2013-community-vs -- Visual Studio Update 5 installed +- [Visual Studio Update 5](https://www.microsoft.com/en-us/download/details.aspx?id=48129) installed - 64 bit version only Open **nheqminer.sln** under **nheqminer/nheqminer.sln** and build. You will have to build ReleaseSSE2 cpu_tromp project first, then Release7.5 cuda_tromp project, then select Release and build all. +### Enabled solvers: + - USE_CPU_TROMP + - USE_CPU_XENONCAT + - USE_CUDA_TROMP + - USE_CUDA_DJEZO + +If you don't wan't to build with all solvlers you can go to **nheqminer Properties > C/C++ > Preprocessor > Preprocessor Definitions** and remove the solver you don't need. ## Linux Work in progress. -Working solvers CPU_TROMP, CPU_XENONCAT, CUDA_TROMP, OCL_XMP, OCL_SILENTARMY +Working solvers CPU_TROMP, CPU_XENONCAT, CUDA_TROMP, CUDA_DJEZO ## Linux (Ubuntu 14.04 / 16.04) Build CPU_XENONCAT: @@ -51,19 +57,6 @@ Working solvers CPU_TROMP, CPU_XENONCAT, CUDA_TROMP, OCL_XMP, OCL_SILENTARMY - `cd nheqminer/Linux_cmake/nheqminer_cuda_tromp && cmake . && make -j $(nproc)` - or specify your compute version for example 50 like so `cd nheqminer/Linux_cmake/nheqminer_cuda_tromp && cmake COMPUTE=50 . && make` -## Linux (16.04) Build OCL_XMP, OCL_SILENTARMY: - - - Open terminal and run the following commands: - - [AMD APP SDK](http://developer.amd.com/tools-and-sdks/opencl-zone/amd-accelerated-parallel-processing-app-sdk/) - - and make sure you have the [AMD drivers](http://support.amd.com/en-us/download) installed - - install them to the default paths - - `sudo apt-get install mesa-common-dev` - - `sudo apt-get install cmake build-essential libboost-all-dev` - - `git clone -b Linux https://github.com/nicehash/nheqminer.git` - - `cd nheqminer/Linux_cmake/nheqminer_AMD && cmake . -DOPENCL_LIBRARY=/usr/lib/x86_64-linux-gnu/libOpenCL.so -DOPENCL_INCLUDE_DIRECTORY=/opt/AMDAPPSDK-3.0/include && make -j $(nproc)` - - `cp ../../3rdparty/amd_bins_linux/* -r .` - - `cp ../../3rdparty/amd_silentarmy_kernels/* -r .` - # Run instructions: From af3a5c48ac658e072765b17b5d8b4f70461dd9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 21:26:59 +0100 Subject: [PATCH 12/15] fix Linux build, one cmake file (TODO make shared lib all in one build) --- CMakeLists.txt | 198 +++++++++ .../nheqminer_cuda_tromp/CMakeLists.txt | 58 ++- blake2/blake2-config.h | 72 ++++ blake2/blake2-impl.h | 136 ++++++ blake2/blake2-round.h | 85 ++++ blake2/blake2.h | 156 +++++++ blake2/blake2b-load-sse2.h | 68 +++ blake2/blake2b-load-sse41.h | 402 ++++++++++++++++++ blake2/blake2b-round.h | 170 ++++++++ blake2/blake2bx.cpp | 346 +++++++++++++++ cpu_tromp/CMakeLists.txt | 19 + cpu_tromp/equi.h | 2 + cpu_xenoncat/CMakeLists.txt | 17 + cpu_xenoncat/Linux/asm/t2.bin | Bin 140 -> 0 bytes cpu_xenoncat/Linux/blake2b/asm/assemble.sh | 2 - .../Linux/blake2b/asm/data_blake2b.asm | 36 -- .../Linux/blake2b/asm/macro_blake2b_avx1.asm | 349 --------------- .../Linux/blake2b/asm/macro_blake2b_avx2.asm | 350 --------------- .../Linux/blake2b/asm/proc_blake2_avx1.asm | 39 -- .../Linux/blake2b/asm/proc_blake2_avx2.asm | 49 --- .../blake2b/asm/proc_prepmidstate_avx1.asm | 212 --------- .../blake2b/asm/proc_prepmidstate_avx2.asm | 166 -------- .../Linux/blake2b/asm/zcblake2_avx1.asm | 11 - .../Linux/blake2b/asm/zcblake2_avx2.asm | 11 - cpu_xenoncat/Linux/blake2b/example_avx1.c | 51 --- cpu_xenoncat/Linux/blake2b/example_avx2.c | 53 --- cpu_xenoncat/Linux/demo/input.bin | Bin 140 -> 0 bytes cpu_xenoncat/Linux/demo/quickbench.c | 78 ---- cpu_xenoncat/Linux/demo/solver.c | 128 ------ .../{Linux/asm => asm_linux}/assemble.sh | 0 .../{Linux/asm => asm_linux}/data_blake2b.asm | 0 .../asm => asm_linux}/equihash_avx1.asm | 2 - .../asm => asm_linux}/equihash_avx2.asm | 2 - cpu_xenoncat/{Linux/asm => asm_linux}/fasm | Bin .../asm => asm_linux}/macro_blake2b_avx1.asm | 0 .../asm => asm_linux}/macro_blake2b_avx2.asm | 0 .../{Linux/asm => asm_linux}/macro_eh.asm | 0 .../{Linux/asm => asm_linux}/params.inc | 0 .../asm => asm_linux}/proc_ehprepare_avx1.asm | 0 .../asm => asm_linux}/proc_ehprepare_avx2.asm | 0 .../asm => asm_linux}/proc_ehsolver_avx1.asm | 0 .../asm => asm_linux}/proc_ehsolver_avx2.asm | 0 .../{Linux/asm => asm_linux}/struct.inc | 0 .../{Linux/asm => asm_linux}/struct_eh.inc | 0 cuda_djezo/CMakeLists.txt | 43 ++ cuda_djezo/blake2b.cu | 336 +++++++++++++++ cuda_djezo/equi_miner.cu | 2 +- cuda_tromp/CMakeLists.txt | 57 +++ nheqminer/MinerFactory.cpp | 8 +- nheqminer/main.cpp | 8 +- 50 files changed, 2147 insertions(+), 1575 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 blake2/blake2-config.h create mode 100644 blake2/blake2-impl.h create mode 100644 blake2/blake2-round.h create mode 100644 blake2/blake2.h create mode 100644 blake2/blake2b-load-sse2.h create mode 100644 blake2/blake2b-load-sse41.h create mode 100644 blake2/blake2b-round.h create mode 100644 blake2/blake2bx.cpp create mode 100644 cpu_tromp/CMakeLists.txt create mode 100644 cpu_xenoncat/CMakeLists.txt delete mode 100644 cpu_xenoncat/Linux/asm/t2.bin delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/assemble.sh delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/data_blake2b.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/macro_blake2b_avx1.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/macro_blake2b_avx2.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/proc_blake2_avx1.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/proc_blake2_avx2.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/proc_prepmidstate_avx1.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/proc_prepmidstate_avx2.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/zcblake2_avx1.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/asm/zcblake2_avx2.asm delete mode 100644 cpu_xenoncat/Linux/blake2b/example_avx1.c delete mode 100644 cpu_xenoncat/Linux/blake2b/example_avx2.c delete mode 100644 cpu_xenoncat/Linux/demo/input.bin delete mode 100644 cpu_xenoncat/Linux/demo/quickbench.c delete mode 100644 cpu_xenoncat/Linux/demo/solver.c rename cpu_xenoncat/{Linux/asm => asm_linux}/assemble.sh (100%) mode change 100755 => 100644 rename cpu_xenoncat/{Linux/asm => asm_linux}/data_blake2b.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/equihash_avx1.asm (85%) rename cpu_xenoncat/{Linux/asm => asm_linux}/equihash_avx2.asm (85%) rename cpu_xenoncat/{Linux/asm => asm_linux}/fasm (100%) mode change 100755 => 100644 rename cpu_xenoncat/{Linux/asm => asm_linux}/macro_blake2b_avx1.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/macro_blake2b_avx2.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/macro_eh.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/params.inc (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/proc_ehprepare_avx1.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/proc_ehprepare_avx2.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/proc_ehsolver_avx1.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/proc_ehsolver_avx2.asm (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/struct.inc (100%) rename cpu_xenoncat/{Linux/asm => asm_linux}/struct_eh.inc (100%) create mode 100644 cuda_djezo/CMakeLists.txt create mode 100644 cuda_djezo/blake2b.cu create mode 100644 cuda_tromp/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..f9066756a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,198 @@ +project(nheqminer) +cmake_minimum_required(VERSION 3.5) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # -Wall + +## Enable solvers here +#### older slower +option(USE_CPU_TROMP "USE CPU_TROMP" OFF) +option(USE_CUDA_TROMP "USE CUDA_TROMP" OFF) +#### faster +option(USE_CPU_XENONCAT "USE CPU_XENONCAT" ON) +option(USE_CUDA_DJEZO "USE CUDA_DJEZO" ON) + +## Add solvers here +if (USE_CPU_TROMP) + add_definitions(-DUSE_CPU_TROMP) + message("-- USE_CPU_TROMP DEFINED") +endif() +if (USE_CPU_XENONCAT) + add_definitions(-DUSE_CPU_XENONCAT) + message("-- USE_CPU_XENONCAT DEFINED") +endif() +if (USE_CUDA_TROMP) + add_definitions(-DUSE_CUDA_TROMP) + message("-- USE_CUDA_TROMP DEFINED") +endif() +if (USE_CUDA_DJEZO) + add_definitions(-DUSE_CUDA_DJEZO) + message("-- USE_CUDA_DJEZO DEFINED") +endif() + + +######## +# LINUX +if(CMAKE_COMPILER_IS_GNUCXX) +# # use native cpu features +# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -fPIC") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -fPIC") + +# # optimizations +# add_definitions(-O3) + + # use + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -msse2") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -msse2") + # optimizations + add_definitions(-O2) +endif() + +# Common +include_directories(${nheqminer_SOURCE_DIR}/nheqminer) + +# BOOST +#find_package(Threads REQUIRED COMPONENTS) +# compile boost staticaly +set(Boost_USE_STATIC_LIBS ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +#set(BUILD_SHARED_LIBRARIES OFF) +#set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") +find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) + +if (Boost_FOUND) + # From the offical documentation: + # Add include directories to the build. [...] If the SYSTEM option is given, + # the compiler will be told the directories are meant as system include + # directories on some platforms (signalling this setting might achieve effects + # such as the compiler skipping warnings [...])." + include_directories (SYSTEM ${Boost_INCLUDE_DIR}) + + # From the offical documentation: + # "Specify directories in which the linker will look for libraries. [...] Note + # that this command is rarely necessary. Library locations returned by + # find_package() and find_library() are absolute paths. Pass these absolute + # library file paths directly to the target_link_libraries() command. CMake + # will ensure the linker finds them." + link_directories (${Boost_LIBRARY_DIRS}) +else() + message("Boost_FOUND NOT FOUND") +endif () + +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../) + +set(SOURCE_FILES + # sources + nheqminer/amount.cpp + nheqminer/api.cpp + nheqminer/arith_uint256.cpp + nheqminer/crypto/sha256.cpp + nheqminer/json/json_spirit_reader.cpp + nheqminer/json/json_spirit_value.cpp + nheqminer/json/json_spirit_writer.cpp + nheqminer/libstratum/ZcashStratum.cpp + nheqminer/main.cpp + nheqminer/primitives/block.cpp + nheqminer/speed.cpp + nheqminer/uint256.cpp + nheqminer/utilstrencodings.cpp + # headers + nheqminer/amount.h + nheqminer/api.hpp + nheqminer/arith_uint256.h + nheqminer/crypto/sha256.h + nheqminer/hash.h + nheqminer/json/json_spirit.h + nheqminer/json/json_spirit_error_position.h + nheqminer/json/json_spirit_reader.h + nheqminer/json/json_spirit_reader_template.h + nheqminer/json/json_spirit_stream_reader.h + nheqminer/json/json_spirit_utils.h + nheqminer/json/json_spirit_value.h + nheqminer/json/json_spirit_writer.h + nheqminer/json/json_spirit_writer_template.h + nheqminer/libstratum/StratumClient.cpp + nheqminer/libstratum/StratumClient.h + nheqminer/libstratum/ZcashStratum.cpp + nheqminer/libstratum/ZcashStratum.h + nheqminer/primitives/block.h + nheqminer/primitives/transaction.h + nheqminer/script/script.h + nheqminer/serialize.h + nheqminer/speed.hpp + nheqminer/streams.h + nheqminer/support/allocators/zeroafterfree.h + nheqminer/tinyformat.h + nheqminer/uint252.h + nheqminer/uint256.h + nheqminer/utilstrencodings.h + nheqminer/version.h + nheqminer/zcash/JoinSplit.hpp + nheqminer/zcash/NoteEncryption.hpp + nheqminer/zcash/Proof.hpp + nheqminer/zcash/Zcash.h + nheqminer/SolverStub.h # just a stub + + nheqminer/AvailableSolvers.h + nheqminer/ISolver.h + nheqminer/Solver.h + nheqminer/MinerFactory.h + nheqminer/MinerFactory.cpp + + # make same path on windows + #blake shared + # src + blake2/blake2bx.cpp + # headers + blake2/blake2.h + blake2/blake2b-load-sse2.h + blake2/blake2b-load-sse41.h + blake2/blake2b-round.h + blake2/blake2-config.h + blake2/blake2-impl.h + blake2/blake2-round.h + ) + +#set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES}) +set(LIBS ${LIBS} ${Boost_LIBRARIES}) + +message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") +message("-- LIBS: ${LIBS}") + +if (USE_CPU_TROMP) + add_subdirectory(cpu_tromp) +endif() +if (USE_CPU_XENONCAT) + add_subdirectory(cpu_xenoncat) +endif() +if (USE_CUDA_TROMP) + add_subdirectory(cuda_tromp) +endif() +if (USE_CUDA_DJEZO) + add_subdirectory(cuda_djezo) +endif() + +#add_subdirectory(cpu_xenoncat) + +ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCE_FILES}) + +#target_link_libraries(${PROJECT_NAME} ${LIBS} ${CUDA_LIBRARIES} ) +target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${LIBS} ) + +# link libs +if (USE_CPU_TROMP) + target_link_libraries(${PROJECT_NAME} cpu_tromp) +endif() +if (USE_CPU_XENONCAT) + add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) + set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../nheqminer/cpu_xenoncat/asm_linux/equihash_avx1.o" ) + add_library ( xenoncat_avx2 SHARED IMPORTED GLOBAL ) + set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../nheqminer/cpu_xenoncat/asm_linux/equihash_avx2.o" ) + target_link_libraries(${PROJECT_NAME} cpu_xenoncat xenoncat_avx1 xenoncat_avx2) +endif() +if (USE_CUDA_TROMP) + target_link_libraries(${PROJECT_NAME} cuda_tromp) +endif() +if (USE_CUDA_DJEZO) + target_link_libraries(${PROJECT_NAME} cuda_djezo) +endif() + diff --git a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt index 11378b5e6..69dbe66af 100644 --- a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt +++ b/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt @@ -17,34 +17,7 @@ endif() # Common include_directories(${nheqminer_SOURCE_DIR}) -#add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) -# BOOST -#find_package(Threads REQUIRED COMPONENTS) -# compile boost staticaly -set(Boost_USE_STATIC_LIBS ON) -set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") -#set(BUILD_SHARED_LIBRARIES OFF) -#set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () +add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) #set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) @@ -75,6 +48,25 @@ else() message("CUDA NOT FOUND") endif() +if (Boost_FOUND) + # From the offical documentation: + # Add include directories to the build. [...] If the SYSTEM option is given, + # the compiler will be told the directories are meant as system include + # directories on some platforms (signalling this setting might achieve effects + # such as the compiler skipping warnings [...])." + include_directories (SYSTEM ${Boost_INCLUDE_DIR}) + + # From the offical documentation: + # "Specify directories in which the linker will look for libraries. [...] Note + # that this command is rarely necessary. Library locations returned by + # find_package() and find_library() are absolute paths. Pass these absolute + # library file paths directly to the target_link_libraries() command. CMake + # will ensure the linker finds them." + link_directories (${Boost_LIBRARY_DIRS}) +else() + message("Boost_FOUND NOT FOUND") +endif () + ## Add solvers here #add_definitions(-DUSE_CPU_XENONCAT) #add_definitions(-DUSE_CPU_TROMP) @@ -141,11 +133,11 @@ set(SOURCE_FILES ../../nheqminer/SolverStub.h # just a stub - ../../nheqminer/AvailableSolvers.h - ../../nheqminer/ISolver.h - ../../nheqminer/Solver.h - ../../nheqminer/MinerFactory.h - ../../nheqminer/MinerFactory.cpp + ../../nheqminer/AvailableSolvers.h + ../../nheqminer/ISolver.h + ../../nheqminer/Solver.h + ../../nheqminer/MinerFactory.h + ../../nheqminer/MinerFactory.cpp # # cpu tromp # ../../cpu_tromp/blake2/blake2bx.cpp diff --git a/blake2/blake2-config.h b/blake2/blake2-config.h new file mode 100644 index 000000000..3524209bf --- /dev/null +++ b/blake2/blake2-config.h @@ -0,0 +1,72 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_CONFIG_H__ +#define __BLAKE2_CONFIG_H__ + +// These don't work everywhere +#if (defined(__SSE2__) || defined(_M_AMD_64) || defined(_M_X64)) +#define HAVE_SSE2 +#endif + +#if defined(__SSSE3__) +#define HAVE_SSSE3 +#endif + +#if defined(__SSE4_1__) +#define HAVE_SSE41 +#endif + +#if defined(__AVX__) +#define HAVE_AVX +#endif + +#if defined(__XOP__) +#define HAVE_XOP +#endif + + +#ifdef HAVE_AVX2 +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_XOP +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_AVX +#ifndef HAVE_SSE41 +#define HAVE_SSE41 +#endif +#endif + +#ifdef HAVE_SSE41 +#ifndef HAVE_SSSE3 +#define HAVE_SSSE3 +#endif +#endif + +#ifdef HAVE_SSSE3 +#define HAVE_SSE2 +#endif + +#if !defined(HAVE_SSE2) +#error "This code requires at least SSE2." +#endif + +#endif + diff --git a/blake2/blake2-impl.h b/blake2/blake2-impl.h new file mode 100644 index 000000000..16219dbcb --- /dev/null +++ b/blake2/blake2-impl.h @@ -0,0 +1,136 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_IMPL_H__ +#define __BLAKE2_IMPL_H__ + +#include + +static inline uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + uint32_t w = *p++; + w |= ( uint32_t )( *p++ ) << 8; + w |= ( uint32_t )( *p++ ) << 16; + w |= ( uint32_t )( *p++ ) << 24; + return w; +#endif +} + +static inline uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + uint64_t w = *p++; + w |= ( uint64_t )( *p++ ) << 8; + w |= ( uint64_t )( *p++ ) << 16; + w |= ( uint64_t )( *p++ ) << 24; + w |= ( uint64_t )( *p++ ) << 32; + w |= ( uint64_t )( *p++ ) << 40; + w |= ( uint64_t )( *p++ ) << 48; + w |= ( uint64_t )( *p++ ) << 56; + return w; +#endif +} + +static inline void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static inline void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static inline uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + uint64_t w = *p++; + w |= ( uint64_t )( *p++ ) << 8; + w |= ( uint64_t )( *p++ ) << 16; + w |= ( uint64_t )( *p++ ) << 24; + w |= ( uint64_t )( *p++ ) << 32; + w |= ( uint64_t )( *p++ ) << 40; + return w; +} + +static inline void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +} + +static inline uint32_t rotl32( const uint32_t w, const unsigned c ) +{ + return ( w << c ) | ( w >> ( 32 - c ) ); +} + +static inline uint64_t rotl64( const uint64_t w, const unsigned c ) +{ + return ( w << c ) | ( w >> ( 64 - c ) ); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static inline uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static inline void secure_zero_memory( void *v, size_t n ) +{ + volatile uint8_t *p = ( volatile uint8_t * )v; + while( n-- ) *p++ = 0; +} + +#endif + diff --git a/blake2/blake2-round.h b/blake2/blake2-round.h new file mode 100644 index 000000000..400ed2034 --- /dev/null +++ b/blake2/blake2-round.h @@ -0,0 +1,85 @@ +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) + +#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + row1l = _mm_add_epi64(row1l, row2l); \ + row1h = _mm_add_epi64(row1h, row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); \ + +#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + row1l = _mm_add_epi64(row1l, row2l); \ + row1h = _mm_add_epi64(row1h, row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); \ + +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; + +#define BLAKE2_ROUND(row1l,row1h,row2l,row2h,row3l,row3h,row4l,row4h) \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); diff --git a/blake2/blake2.h b/blake2/blake2.h new file mode 100644 index 000000000..85d63866f --- /dev/null +++ b/blake2/blake2.h @@ -0,0 +1,156 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_H__ +#define __BLAKE2_H__ + +#include +#include + +#if defined(_MSC_VER) +#define ALIGN(x) __declspec(align(x)) +#else +#define ALIGN(x) __attribute__ ((__aligned__(x))) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + +#pragma pack(push, 1) + typedef struct __blake2s_param + { + uint8_t digest_length; // 1 + uint8_t key_length; // 2 + uint8_t fanout; // 3 + uint8_t depth; // 4 + uint32_t leaf_length; // 8 + uint8_t node_offset[6];// 14 + uint8_t node_depth; // 15 + uint8_t inner_length; // 16 + // uint8_t reserved[0]; + uint8_t salt[BLAKE2S_SALTBYTES]; // 24 + uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32 + } blake2s_param; + + ALIGN( 64 ) typedef struct __blake2s_state + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[2 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + uint8_t last_node; + } blake2s_state; + + typedef struct __blake2b_param + { + uint8_t digest_length; // 1 + uint8_t key_length; // 2 + uint8_t fanout; // 3 + uint8_t depth; // 4 + uint32_t leaf_length; // 8 + uint64_t node_offset; // 16 + uint8_t node_depth; // 17 + uint8_t inner_length; // 18 + uint8_t reserved[14]; // 32 + uint8_t salt[BLAKE2B_SALTBYTES]; // 48 + uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64 + } blake2b_param; + + ALIGN( 64 ) typedef struct __blake2b_state + { + uint64_t h[8]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + uint16_t counter; + uint8_t buflen; + uint8_t lastblock; + } blake2b_state; + + ALIGN( 64 ) typedef struct __blake2sp_state + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + } blake2sp_state; + + ALIGN( 64 ) typedef struct __blake2bp_state + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + } blake2bp_state; +#pragma pack(pop) + + // Streaming API + int blake2s_init( blake2s_state *S, const uint8_t outlen ); + int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen ); + int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen ); + + int blake2b_init( blake2b_state *S, const uint8_t outlen ); + int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen ); + int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen ); + + int blake2sp_init( blake2sp_state *S, const uint8_t outlen ); + int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen ); + int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen ); + + int blake2bp_init( blake2bp_state *S, const uint8_t outlen ); + int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen ); + int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen ); + + // Simple API + int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen); + + int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + + static inline int blake2( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ) + { + return blake2b( out, in, key, outlen, inlen, keylen ); + } + +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/blake2/blake2b-load-sse2.h b/blake2/blake2b-load-sse2.h new file mode 100644 index 000000000..1ba153c87 --- /dev/null +++ b/blake2/blake2b-load-sse2.h @@ -0,0 +1,68 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_LOAD_SSE2_H__ +#define __BLAKE2B_LOAD_SSE2_H__ + +#define LOAD_MSG_0_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_0_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_0_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_0_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_1_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_1_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_1_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_1_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) +#define LOAD_MSG_2_1(b0, b1) b0 = _mm_set_epi64x(m12, m11); b1 = _mm_set_epi64x(m15, m5) +#define LOAD_MSG_2_2(b0, b1) b0 = _mm_set_epi64x(m0, m8); b1 = _mm_set_epi64x(m13, m2) +#define LOAD_MSG_2_3(b0, b1) b0 = _mm_set_epi64x(m3, m10); b1 = _mm_set_epi64x(m9, m7) +#define LOAD_MSG_2_4(b0, b1) b0 = _mm_set_epi64x(m6, m14); b1 = _mm_set_epi64x(m4, m1) +#define LOAD_MSG_3_1(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m13) +#define LOAD_MSG_3_2(b0, b1) b0 = _mm_set_epi64x(m1, m9); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_3_3(b0, b1) b0 = _mm_set_epi64x(m5, m2); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_3_4(b0, b1) b0 = _mm_set_epi64x(m10, m6); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_4_1(b0, b1) b0 = _mm_set_epi64x(m5, m9); b1 = _mm_set_epi64x(m10, m2) +#define LOAD_MSG_4_2(b0, b1) b0 = _mm_set_epi64x(m7, m0); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_4_3(b0, b1) b0 = _mm_set_epi64x(m11, m14); b1 = _mm_set_epi64x(m3, m6) +#define LOAD_MSG_4_4(b0, b1) b0 = _mm_set_epi64x(m12, m1); b1 = _mm_set_epi64x(m13, m8) +#define LOAD_MSG_5_1(b0, b1) b0 = _mm_set_epi64x(m6, m2); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_5_2(b0, b1) b0 = _mm_set_epi64x(m10, m12); b1 = _mm_set_epi64x(m3, m11) +#define LOAD_MSG_5_3(b0, b1) b0 = _mm_set_epi64x(m7, m4); b1 = _mm_set_epi64x(m1, m15) +#define LOAD_MSG_5_4(b0, b1) b0 = _mm_set_epi64x(m5, m13); b1 = _mm_set_epi64x(m9, m14) +#define LOAD_MSG_6_1(b0, b1) b0 = _mm_set_epi64x(m1, m12); b1 = _mm_set_epi64x(m4, m14) +#define LOAD_MSG_6_2(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m10, m13) +#define LOAD_MSG_6_3(b0, b1) b0 = _mm_set_epi64x(m6, m0); b1 = _mm_set_epi64x(m8, m9) +#define LOAD_MSG_6_4(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m2) +#define LOAD_MSG_7_1(b0, b1) b0 = _mm_set_epi64x(m7, m13); b1 = _mm_set_epi64x(m3, m12) +#define LOAD_MSG_7_2(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m9, m1) +#define LOAD_MSG_7_3(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m2, m8) +#define LOAD_MSG_7_4(b0, b1) b0 = _mm_set_epi64x(m4, m0); b1 = _mm_set_epi64x(m10, m6) +#define LOAD_MSG_8_1(b0, b1) b0 = _mm_set_epi64x(m14, m6); b1 = _mm_set_epi64x(m0, m11) +#define LOAD_MSG_8_2(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m8, m3) +#define LOAD_MSG_8_3(b0, b1) b0 = _mm_set_epi64x(m13, m12); b1 = _mm_set_epi64x(m10, m1) +#define LOAD_MSG_8_4(b0, b1) b0 = _mm_set_epi64x(m7, m2); b1 = _mm_set_epi64x(m5, m4) +#define LOAD_MSG_9_1(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m1, m7) +#define LOAD_MSG_9_2(b0, b1) b0 = _mm_set_epi64x(m4, m2); b1 = _mm_set_epi64x(m5, m6) +#define LOAD_MSG_9_3(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m13, m3) +#define LOAD_MSG_9_4(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m0, m12) +#define LOAD_MSG_10_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_10_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_10_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_10_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_11_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_11_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_11_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_11_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) + + +#endif + diff --git a/blake2/blake2b-load-sse41.h b/blake2/blake2b-load-sse41.h new file mode 100644 index 000000000..f6c1bc839 --- /dev/null +++ b/blake2/blake2b-load-sse41.h @@ -0,0 +1,402 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_LOAD_SSE41_H__ +#define __BLAKE2B_LOAD_SSE41_H__ + +#define LOAD_MSG_0_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_0_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_1_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_1_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_1_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_1_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#define LOAD_MSG_2_1(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m5, 8); \ +b1 = _mm_unpackhi_epi64(m2, m7); \ +} while(0) + + +#define LOAD_MSG_2_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m0); \ +b1 = _mm_blend_epi16(m1, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_2_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m5, m1, 0xF0); \ +b1 = _mm_unpackhi_epi64(m3, m4); \ +} while(0) + + +#define LOAD_MSG_2_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m3); \ +b1 = _mm_alignr_epi8(m2, m0, 8); \ +} while(0) + + +#define LOAD_MSG_3_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_unpackhi_epi64(m6, m5); \ +} while(0) + + +#define LOAD_MSG_3_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m0); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_3_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m2, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_3_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m5); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_4_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m2); \ +b1 = _mm_unpacklo_epi64(m1, m5); \ +} while(0) + + +#define LOAD_MSG_4_2(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m0, m3, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m7, m5, 0xF0); \ +b1 = _mm_blend_epi16(m3, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m0, 8); \ +b1 = _mm_blend_epi16(m4, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_5_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m3); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_5_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m5); \ +b1 = _mm_unpackhi_epi64(m5, m1); \ +} while(0) + + +#define LOAD_MSG_5_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m2, m3, 0xF0); \ +b1 = _mm_unpackhi_epi64(m7, m0); \ +} while(0) + + +#define LOAD_MSG_5_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m2); \ +b1 = _mm_blend_epi16(m7, m4, 0xF0); \ +} while(0) + + +#define LOAD_MSG_6_1(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m6, m0, 0xF0); \ +b1 = _mm_unpacklo_epi64(m7, m2); \ +} while(0) + + +#define LOAD_MSG_6_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_alignr_epi8(m5, m6, 8); \ +} while(0) + + +#define LOAD_MSG_6_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m3); \ +b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \ +} while(0) + + +#define LOAD_MSG_6_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_blend_epi16(m1, m5, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m3); \ +b1 = _mm_blend_epi16(m6, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_2(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpackhi_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_7_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_unpacklo_epi64(m4, m1); \ +} while(0) + + +#define LOAD_MSG_7_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m2); \ +b1 = _mm_unpacklo_epi64(m3, m5); \ +} while(0) + + +#define LOAD_MSG_8_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m7); \ +b1 = _mm_alignr_epi8(m0, m5, 8); \ +} while(0) + + +#define LOAD_MSG_8_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_alignr_epi8(m4, m1, 8); \ +} while(0) + + +#define LOAD_MSG_8_3(b0, b1) \ +do \ +{ \ +b0 = m6; \ +b1 = _mm_alignr_epi8(m5, m0, 8); \ +} while(0) + + +#define LOAD_MSG_8_4(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m3, 0xF0); \ +b1 = m2; \ +} while(0) + + +#define LOAD_MSG_9_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_unpackhi_epi64(m3, m0); \ +} while(0) + + +#define LOAD_MSG_9_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m2); \ +b1 = _mm_blend_epi16(m3, m2, 0xF0); \ +} while(0) + + +#define LOAD_MSG_9_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_unpackhi_epi64(m1, m6); \ +} while(0) + + +#define LOAD_MSG_9_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpacklo_epi64(m6, m0); \ +} while(0) + + +#define LOAD_MSG_10_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_10_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_11_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_11_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_11_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_11_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#endif + diff --git a/blake2/blake2b-round.h b/blake2/blake2b-round.h new file mode 100644 index 000000000..3e6fd0cbe --- /dev/null +++ b/blake2/blake2b-round.h @@ -0,0 +1,170 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_ROUND_H__ +#define __BLAKE2B_ROUND_H__ + +#define LOAD(p) _mm_load_si128( (const __m128i *)(p) ) +#define STORE(p,r) _mm_store_si128((__m128i *)(p), r) + +#define LOADU(p) _mm_loadu_si128( (const __m128i *)(p) ) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r) + +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +#define LIKELY(x) __builtin_expect((x),1) + + +/* Microarchitecture-specific macros */ +#ifndef HAVE_XOP +#ifdef HAVE_SSSE3 +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) +#else +#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64( (r), -(c) ),_mm_slli_epi64( (r), 64-(-c) )) +#endif +#else +/* ... */ +#endif + + + +#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, (-32)); \ + row4h = _mm_roti_epi64(row4h, (-32)); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, (-24)); \ + row2h = _mm_roti_epi64(row2h, (-24)); \ + +#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, (-16)); \ + row4h = _mm_roti_epi64(row4h, (-16)); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, (-63)); \ + row2h = _mm_roti_epi64(row2h, (-63)); \ + +#if defined(HAVE_SSSE3) +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; +#else + +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row4l;\ + t1 = row2l;\ + row4l = row3l;\ + row3l = row3h;\ + row3h = row4l;\ + row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \ + row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \ + row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \ + row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1)) + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row3l;\ + row3l = row3h;\ + row3h = t0;\ + t0 = row2l;\ + t1 = row4l;\ + row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \ + row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \ + row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \ + row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1)) + +#endif + +#if defined(HAVE_SSE41) +#include "blake2b-load-sse41.h" +#else +#include "blake2b-load-sse2.h" +#endif + +#define ROUND(r) \ + LOAD_MSG_ ##r ##_1(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_2(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + LOAD_MSG_ ##r ##_3(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_4(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); + +#endif + +#define BLAKE2_ROUND(row1l,row1h,row2l,row2h,row3l,row3h,row4l,row4h) \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); diff --git a/blake2/blake2bx.cpp b/blake2/blake2bx.cpp new file mode 100644 index 000000000..2df512e95 --- /dev/null +++ b/blake2/blake2bx.cpp @@ -0,0 +1,346 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ + +#include +#include +#include + + +#include "blake2.h" +#include "blake2-impl.h" + +#include "blake2-config.h" + +#ifdef WIN32 +#include +#endif + +#include +#if defined(HAVE_SSSE3) +#include +#endif +#if defined(HAVE_SSE41) +#include +#endif +#if defined(HAVE_AVX) +#include +#endif +#if defined(HAVE_XOP) +#include +#endif + +#include "blake2b-round.h" + + + +ALIGN(64) static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/* init xors IV with input parameter block */ +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) +{ + //blake2b_init0( S ); + const uint8_t * v = (const uint8_t *)(blake2b_IV); + const uint8_t * p = (const uint8_t *)(P); + uint8_t * h = (uint8_t *)(S->h); + /* IV XOR ParamBlock */ + memset(S, 0, sizeof(blake2b_state)); + + for (int i = 0; i < BLAKE2B_OUTBYTES; ++i) h[i] = v[i] ^ p[i]; + + return 0; +} + +/* Some sort of default parameter block initialization, for sequential blake2b */ +int blake2b_init(blake2b_state *S, const uint8_t outlen) +{ + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + + const blake2b_param P = + { + outlen, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + { 0 }, + { 0 }, + { 0 } + }; + return blake2b_init_param(S, &P); +} + +int blake2b_init_key(blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen) +{ + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; + + if ((!keylen) || keylen > BLAKE2B_KEYBYTES) return -1; + + const blake2b_param P = + { + outlen, + keylen, + 1, + 1, + 0, + 0, + 0, + 0, + { 0 }, + { 0 }, + { 0 } + }; + + if (blake2b_init_param(S, &P) < 0) + return 0; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + secure_zero_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +static inline int blake2b_compress(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES]) +{ + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; +#if defined(HAVE_SSSE3) && !defined(HAVE_XOP) + const __m128i r16 = _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9); + const __m128i r24 = _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10); +#endif +#if defined(HAVE_SSE41) + const __m128i m0 = LOADU(block + 00); + const __m128i m1 = LOADU(block + 16); + const __m128i m2 = LOADU(block + 32); + const __m128i m3 = LOADU(block + 48); + const __m128i m4 = LOADU(block + 64); + const __m128i m5 = LOADU(block + 80); + const __m128i m6 = LOADU(block + 96); + const __m128i m7 = LOADU(block + 112); +#else + const uint64_t m0 = ( ( uint64_t * )block )[ 0]; + const uint64_t m1 = ( ( uint64_t * )block )[ 1]; + const uint64_t m2 = ( ( uint64_t * )block )[ 2]; + const uint64_t m3 = ( ( uint64_t * )block )[ 3]; + const uint64_t m4 = ( ( uint64_t * )block )[ 4]; + const uint64_t m5 = ( ( uint64_t * )block )[ 5]; + const uint64_t m6 = ( ( uint64_t * )block )[ 6]; + const uint64_t m7 = ( ( uint64_t * )block )[ 7]; + const uint64_t m8 = ( ( uint64_t * )block )[ 8]; + const uint64_t m9 = ( ( uint64_t * )block )[ 9]; + const uint64_t m10 = ( ( uint64_t * )block )[10]; + const uint64_t m11 = ( ( uint64_t * )block )[11]; + const uint64_t m12 = ( ( uint64_t * )block )[12]; + const uint64_t m13 = ( ( uint64_t * )block )[13]; + const uint64_t m14 = ( ( uint64_t * )block )[14]; + const uint64_t m15 = ( ( uint64_t * )block )[15]; +#endif + row1l = LOADU(&S->h[0]); + row1h = LOADU(&S->h[2]); + row2l = LOADU(&S->h[4]); + row2h = LOADU(&S->h[6]); + row3l = LOADU(&blake2b_IV[0]); + row3h = LOADU(&blake2b_IV[2]); + row4l = _mm_xor_si128(LOADU(&blake2b_IV[4]), _mm_set_epi32(0, 0, 0, S->counter)); + row4h = _mm_xor_si128(LOADU(&blake2b_IV[6]), _mm_set_epi32(0, 0, 0L - S->lastblock, 0L - S->lastblock)); + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + row1l = _mm_xor_si128(row3l, row1l); + row1h = _mm_xor_si128(row3h, row1h); + STOREU(&S->h[0], _mm_xor_si128(LOADU(&S->h[0]), row1l)); + STOREU(&S->h[2], _mm_xor_si128(LOADU(&S->h[2]), row1h)); + row2l = _mm_xor_si128(row4l, row2l); + row2h = _mm_xor_si128(row4h, row2h); + STOREU(&S->h[4], _mm_xor_si128(LOADU(&S->h[4]), row2l)); + STOREU(&S->h[6], _mm_xor_si128(LOADU(&S->h[6]), row2h)); + return 0; +} + + +int blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen) +{ + while (inlen > 0) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + + if (inlen > fill) + { + memcpy(S->buf + left, in, fill); // Fill buffer + in += fill; + inlen -= fill; + S->counter += BLAKE2B_BLOCKBYTES; + blake2b_compress(S, S->buf); // Compress + S->buflen = 0; + } + else // inlen <= fill + { + memcpy(S->buf + left, in, inlen); + S->buflen += inlen; // not enough to compress + in += inlen; + inlen = 0; + } + } + + return 0; +} + + +int blake2b_final(blake2b_state *S, uint8_t *out, uint8_t outlen) +{ + if (outlen > BLAKE2B_OUTBYTES) + return -1; + + if (S->buflen > BLAKE2B_BLOCKBYTES) + { + S->counter += BLAKE2B_BLOCKBYTES; + blake2b_compress(S, S->buf); + S->buflen -= BLAKE2B_BLOCKBYTES; + memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen); + } + + S->counter += S->buflen; + S->lastblock = 1; + memset(S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + memcpy(out, &S->h[0], outlen); + S->lastblock = 0; + return 0; +} + + +int blake2b(uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if (NULL == in) return -1; + + if (NULL == out) return -1; + + if (NULL == key) keylen = 0; + + if (keylen) + { + if (blake2b_init_key(S, outlen, key, keylen) < 0) return -1; + } + else + { + if (blake2b_init(S, outlen) < 0) return -1; + } + + blake2b_update(S, (const uint8_t *)in, inlen); + blake2b_final(S, out, outlen); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, in, NULL, BLAKE2B_OUTBYTES, inlen, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( int argc, char **argv ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[KAT_LENGTH]; + + for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + puts( "error" ); + return -1; + } + } + + puts( "ok" ); + return 0; +} +#endif + +int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen) +{ + blake2b_state blake_state; + if (outlen <= BLAKE2B_OUTBYTES) + { + blake2b_init(&blake_state, outlen); + blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t)); + blake2b_update(&blake_state, (const uint8_t *)in, inlen); + blake2b_final(&blake_state, out, outlen); + } + else + { + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + blake2b_init(&blake_state, BLAKE2B_OUTBYTES); + blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t)); + blake2b_update(&blake_state, (const uint8_t *)in, inlen); + blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + uint32_t toproduce = outlen - BLAKE2B_OUTBYTES / 2; + while (toproduce > BLAKE2B_OUTBYTES) + { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + blake2b(out_buffer, in_buffer, NULL, BLAKE2B_OUTBYTES, BLAKE2B_OUTBYTES, 0); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + blake2b(out_buffer, in_buffer, NULL, toproduce, BLAKE2B_OUTBYTES, 0); + memcpy(out, out_buffer, toproduce); + + } + return 0; +} \ No newline at end of file diff --git a/cpu_tromp/CMakeLists.txt b/cpu_tromp/CMakeLists.txt new file mode 100644 index 000000000..8214d97ff --- /dev/null +++ b/cpu_tromp/CMakeLists.txt @@ -0,0 +1,19 @@ +set(EXECUTABLE cpu_tromp) + +#cpu_tromp/ +file(GLOB SRC_LIST + cpu_tromp.cpp ) +file(GLOB HEADERS + cpu_tromp.hpp + equi.h + equi_miner.h + ) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CUDA_INCLUDE_DIRS}) +include_directories(..) +ADD_LIBRARY(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ) + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/cpu_tromp/equi.h b/cpu_tromp/equi.h index 94ad0ad8a..ed91cee14 100644 --- a/cpu_tromp/equi.h +++ b/cpu_tromp/equi.h @@ -2,6 +2,7 @@ // Equihash solver // Copyright (c) 2016-2016 John Tromp + #include "blake2/blake2.h" #ifdef __APPLE__ #include "osx_barrier.h" @@ -131,3 +132,4 @@ int verify(u32 indices[PROOFSIZE], const char *header, const u32 headerlen, cons uchar hash[WN/8]; return verifyrec(&ctx, indices, hash, WK); } + diff --git a/cpu_xenoncat/CMakeLists.txt b/cpu_xenoncat/CMakeLists.txt new file mode 100644 index 000000000..66c698d74 --- /dev/null +++ b/cpu_xenoncat/CMakeLists.txt @@ -0,0 +1,17 @@ +set(EXECUTABLE cpu_xenoncat) + +#cpu_xenoncat/ +file(GLOB SRC_LIST + xenoncat.cpp ) +file(GLOB HEADERS + cpu_xenoncat.hpp + ) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CUDA_INCLUDE_DIRS}) +include_directories(..) +ADD_LIBRARY(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ) + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/cpu_xenoncat/Linux/asm/t2.bin b/cpu_xenoncat/Linux/asm/t2.bin deleted file mode 100644 index 432b9ab90434a395225bb476aac7a95a3301d6c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmZQ!U|^USzf8t|=_H$H@7A)FWG5TOJ2ml003!HHG%*D diff --git a/cpu_xenoncat/Linux/blake2b/asm/assemble.sh b/cpu_xenoncat/Linux/blake2b/asm/assemble.sh deleted file mode 100644 index 91990b5d0..000000000 --- a/cpu_xenoncat/Linux/blake2b/asm/assemble.sh +++ /dev/null @@ -1,2 +0,0 @@ -fasm zcblake2_avx1.asm -fasm zcblake2_avx2.asm diff --git a/cpu_xenoncat/Linux/blake2b/asm/data_blake2b.asm b/cpu_xenoncat/Linux/blake2b/asm/data_blake2b.asm deleted file mode 100644 index be2026b1b..000000000 --- a/cpu_xenoncat/Linux/blake2b/asm/data_blake2b.asm +++ /dev/null @@ -1,36 +0,0 @@ -xshufb_ror24 db 3,4,5,6,7,0,1,2, 11,12,13,14,15,8,9,10 -xshufb_ror16 db 2,3,4,5,6,7,0,1, 10,11,12,13,14,15,8,9 -xshufb_bswap8 db 7,6,5,4,3,2,1,0, 15,14,13,12,11,10,9,8 -xctrinc dd 0,2, 0,2 - -align 32 -iv dq 0x6a09e667f3bcc908, 0xbb67ae8584caa73b -dq 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1 -dq 0x510e527fade682d1, 0x9b05688c2b3e6c1f -dq 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 - -s0 dq 0x6a09e667f3bcc908 xor 0x1010032, 0xbb67ae8584caa73b ;0x32=50 bytes output -s2 dq 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1 -s4 dq 0x510e527fade682d1, 0x9b05688c2b3e6c1f -s6 dq 0x1f83d9abfb41bd6b xor 0x576f50687361635a ;Personalization -s7 dq 0x5be0cd19137e2179 xor 0x00000009000000c8 ;n=200, k=9 - -iv4xor128 dq 0x510e527fade682d1 xor 0x80, 0x9b05688c2b3e6c1f -dq 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 -iv4xor144 dq 0x510e527fade682d1 xor 144, 0x9b05688c2b3e6c1f -iv6inverted dq 0xe07c265404be4294, 0x5be0cd19137e2179 - -align 32 -yctrinit dd 0,0, 0,1, 0,2, 0,3 -yctrinc dd 0,4, 0,4, 0,4, 0,4 - -blake2sigma db 0,2,4,6,1,3,5,7,8,10,12,14,9,11,13,15 -db 14,4,9,13,10,8,15,6,1,0,11,5,12,2,7,3 -db 11,12,5,15,8,0,2,13,10,3,7,9,14,6,1,4 -db 7,3,13,11,9,1,12,14,2,5,4,15,6,10,0,8 -db 9,5,2,10,0,7,4,15,14,11,6,3,1,12,8,13 -db 2,6,0,8,12,10,11,3,4,7,15,1,13,5,14,9 -db 12,1,14,4,5,15,13,10,0,6,9,8,7,3,2,11 -db 13,7,12,3,11,14,1,9,5,15,8,2,0,4,6,10 -db 6,14,11,0,15,9,3,8,12,13,1,10,2,7,4,5 -db 10,8,7,1,2,4,6,5,15,9,3,13,11,14,12,0 diff --git a/cpu_xenoncat/Linux/blake2b/asm/macro_blake2b_avx1.asm b/cpu_xenoncat/Linux/blake2b/asm/macro_blake2b_avx1.asm deleted file mode 100644 index fa3aeee8c..000000000 --- a/cpu_xenoncat/Linux/blake2b/asm/macro_blake2b_avx1.asm +++ /dev/null @@ -1,349 +0,0 @@ -macro hR0 m0,m1,m2,m3,m4,m5,m6,m7,lim,src -{ -vpaddq xmm0,xmm0,xmm4 -vpaddq xmm1,xmm1,xmm5 -vpaddq xmm2,xmm2,xmm6 -vpaddq xmm3,xmm3,xmm7 -if m0 -#include -#include - -void Blake2PrepareMidstate2(void *midstate, unsigned char *input); -//midstate: 256 bytes of buffer for output midstate, aligned by 32 -//input: 140 bytes header, preferably aligned by 8 - -void Blake2Run2(unsigned char *hashout, void *midstate, uint32_t indexctr); -//hashout: hash output buffer: 2*64 bytes -//midstate: 256 bytes from Blake2PrepareMidstate2 -//indexctr: For n=200, k=9: {0, 2, 4, ..., 1048574} - -unsigned char __attribute__((aligned(8))) testdata[140] = -{ - 0x04, 0x00, 0x00, 0x00, 0x91, 0x5F, 0xA6, 0x1C, 0x4F, 0xA5, 0x92, 0x3C, 0xE6, 0xEE, 0xAD, 0x06, - 0x74, 0x6B, 0x61, 0x22, 0x54, 0x94, 0xEA, 0x5A, 0x2A, 0x97, 0xAE, 0x46, 0x6E, 0x6F, 0xAA, 0x9C, - 0x6E, 0xF6, 0x3A, 0x0D, 0xA5, 0xFC, 0x67, 0xD7, 0xF8, 0xDC, 0x78, 0xC3, 0xC8, 0x70, 0xCA, 0x09, - 0xBA, 0xAB, 0xAA, 0xF7, 0x02, 0x59, 0x68, 0xA8, 0x6F, 0xEB, 0x88, 0x75, 0xD3, 0xF3, 0xFF, 0xA7, - 0x2E, 0xB0, 0x0F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x66, 0xCE, 0xD2, 0x57, 0x0F, 0x0F, 0x0F, 0x20, 0x00, 0x00, 0xF7, 0xF1, - 0x94, 0xA2, 0x53, 0x8E, 0x42, 0x5F, 0x21, 0x33, 0xCF, 0xA8, 0xD3, 0xCB, 0xF4, 0xDF, 0x71, 0xEF, - 0x38, 0x28, 0x51, 0x75, 0xCF, 0xED, 0xCB, 0x3E, 0x63, 0xA2, 0x00, 0x00 -}; -//expected output: 281dd5fc6d878538e640987b9bc597dbbd4af2cdf8bf5fb03bdfcefa40d8747d out.bin - -int main(void) -{ - unsigned char midstate_a[256+32]; - void *pmidstate = (void *) (((long) midstate_a+31L) & -32L); - unsigned char hashout_a[128+32]; - unsigned char *phashout = (unsigned char *) (((long) hashout_a+31L) & -32L); - unsigned char buf[128]; - FILE *outfile; - int i; - - Blake2PrepareMidstate2(pmidstate, testdata); - outfile = fopen("out.bin", "wb"); - - for (i=0; i<1048576; i+=2) { - Blake2Run2(phashout, pmidstate, i); - memcpy(buf, phashout, 50); - memcpy(buf+50, phashout+64, 50); - fwrite(buf, 100, 1, outfile); - } - - fclose(outfile); - - return 0; -} diff --git a/cpu_xenoncat/Linux/blake2b/example_avx2.c b/cpu_xenoncat/Linux/blake2b/example_avx2.c deleted file mode 100644 index bbf9782d3..000000000 --- a/cpu_xenoncat/Linux/blake2b/example_avx2.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -void Blake2PrepareMidstate4(void *midstate, unsigned char *input); -//midstate: 256 bytes of buffer for output midstate, aligned by 32 -//input: 140 bytes header, preferably aligned by 8 - -void Blake2Run4(unsigned char *hashout, void *midstate, uint32_t indexctr); -//hashout: hash output buffer: 4*64 bytes -//midstate: 256 bytes from Blake2PrepareMidstate4 -//indexctr: For n=200, k=9: {0, 4, 8, ..., 1048572} - -unsigned char __attribute__((aligned(8))) testdata[140] = -{ - 0x04, 0x00, 0x00, 0x00, 0x91, 0x5F, 0xA6, 0x1C, 0x4F, 0xA5, 0x92, 0x3C, 0xE6, 0xEE, 0xAD, 0x06, - 0x74, 0x6B, 0x61, 0x22, 0x54, 0x94, 0xEA, 0x5A, 0x2A, 0x97, 0xAE, 0x46, 0x6E, 0x6F, 0xAA, 0x9C, - 0x6E, 0xF6, 0x3A, 0x0D, 0xA5, 0xFC, 0x67, 0xD7, 0xF8, 0xDC, 0x78, 0xC3, 0xC8, 0x70, 0xCA, 0x09, - 0xBA, 0xAB, 0xAA, 0xF7, 0x02, 0x59, 0x68, 0xA8, 0x6F, 0xEB, 0x88, 0x75, 0xD3, 0xF3, 0xFF, 0xA7, - 0x2E, 0xB0, 0x0F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x66, 0xCE, 0xD2, 0x57, 0x0F, 0x0F, 0x0F, 0x20, 0x00, 0x00, 0xF7, 0xF1, - 0x94, 0xA2, 0x53, 0x8E, 0x42, 0x5F, 0x21, 0x33, 0xCF, 0xA8, 0xD3, 0xCB, 0xF4, 0xDF, 0x71, 0xEF, - 0x38, 0x28, 0x51, 0x75, 0xCF, 0xED, 0xCB, 0x3E, 0x63, 0xA2, 0x00, 0x00 -}; -//expected output: 281dd5fc6d878538e640987b9bc597dbbd4af2cdf8bf5fb03bdfcefa40d8747d out.bin - -int main(void) -{ - unsigned char midstate_a[256+32]; - void *pmidstate = (void *) (((long) midstate_a+31L) & -32L); - unsigned char hashout_a[256+32]; - unsigned char *phashout = (unsigned char *) (((long) hashout_a+31L) & -32L); - unsigned char buf[256]; - FILE *outfile; - int i; - - Blake2PrepareMidstate4(pmidstate, testdata); - outfile = fopen("out.bin", "wb"); - - for (i=0; i<1048576; i+=4) { - Blake2Run4(phashout, pmidstate, i); - memcpy(buf, phashout, 50); - memcpy(buf+50, phashout+64, 50); - memcpy(buf+100, phashout+128, 50); - memcpy(buf+150, phashout+192, 50); - fwrite(buf, 200, 1, outfile); - } - - fclose(outfile); - - return 0; -} diff --git a/cpu_xenoncat/Linux/demo/input.bin b/cpu_xenoncat/Linux/demo/input.bin deleted file mode 100644 index 432b9ab90434a395225bb476aac7a95a3301d6c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmZQ!U|^USzf8t|=_H$H@7A)FWG5TOJ2ml003!HHG%*D diff --git a/cpu_xenoncat/Linux/demo/quickbench.c b/cpu_xenoncat/Linux/demo/quickbench.c deleted file mode 100644 index 036f8122a..000000000 --- a/cpu_xenoncat/Linux/demo/quickbench.c +++ /dev/null @@ -1,78 +0,0 @@ -//compile with -//gcc -o quickbench quickbench.c equihash_avx2.o -#include -#include -#include -#include -#include - -#define CONTEXT_SIZE 178033152 -#define ITERATIONS 10 - -//Linkage with assembly -//EhPrepare takes in 136 bytes of input. The remaining 4 bytes of input is fed as nonce to EhSolver. -//EhPrepare saves the 136 bytes in context, and EhSolver can be called repeatedly with different nonce. -void EhPrepare(void *context, void *input); -int32_t EhSolver(void *context, uint32_t nonce); -extern char testinput[]; - -int main(void) -{ - void *context_alloc, *context, *context_end; - uint32_t *pu32; - uint64_t *pu64, previous_rdtsc; - uint8_t inputheader[144]; //140 byte header - FILE *infile, *outfile; - struct timespec time0, time1; - long t0, t1; - int32_t numsolutions, total_solutions; - uint32_t nonce, delta_time, total_time; - int i, j; - - context_alloc = malloc(CONTEXT_SIZE+4096); - context = (void*) (((long) context_alloc+4095) & -4096); - context_end = context + CONTEXT_SIZE; - - infile = 0; - infile = fopen("input.bin", "rb"); - if (infile) { - puts("Reading input.bin"); - fread(inputheader, 140, 1, infile); - fclose(infile); - } else { - puts("input.bin not found, use sample data (beta1 testnet block 2)"); - memcpy(inputheader, testinput, 140); - } - - - EhPrepare(context, (void *) inputheader); - - //Warm up, timing not taken into average - nonce = 0; - clock_gettime(CLOCK_MONOTONIC, &time0); - numsolutions = EhSolver(context, nonce); - clock_gettime(CLOCK_MONOTONIC, &time1); - delta_time = (uint32_t) ((time1.tv_sec * 1000000000 + time1.tv_nsec) - - (time0.tv_sec * 1000000000 + time0.tv_nsec))/1000000; - printf("(Warm up) Time: %u ms, solutions: %u\n", delta_time, numsolutions); - - printf("Running %d iterations...\n", ITERATIONS); - nonce = 58; //arbritary number to get 19 solutions in 10 iterations (to match 1.88 solutions per run) - total_time = total_solutions = 0; - for (i=0; i -#include -#include -#include -#include -#include -#include //for rdtsc - -#define CONTEXT_SIZE 178033152 - -//Linkage with assembly -//EhPrepare takes in 136 bytes of input. The remaining 4 bytes of input is fed as nonce to EhSolver. -//EhPrepare saves the 136 bytes in context, and EhSolver can be called repeatedly with different nonce. -void EhPrepare(void *context, void *input); -int32_t EhSolver(void *context, uint32_t nonce); -extern char testinput[]; - -//context is the memory used for Equihash computation. It should be allocated outside of SolverFunction, the size is defined by CONTEXT_SIZE, about 180MB. -//SolverFunction API has slight overhead in mining due to missing opportunity to run EhSolver multiple times after a single EhPrepare. -int SolverFunction(void* context, const unsigned char* input, - bool (*validBlock)(void*, const unsigned char*), - void* validBlockData, - bool (*cancelled)(void*), - void* cancelledData, - int numThreads, - int n, int k) -{ - int numsolutions, i; - - EhPrepare(context, (void *) input); - numsolutions = EhSolver(context, *(uint32_t *)(input+136)); - - for (i=0; i Ubuntu 14.04 check gcc versions +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-std=c++11) + +file(GLOB SRC_LIST + cuda_djezo.cpp + equi_miner.cu ) +file(GLOB HEADERS + cuda_djezo.hpp + eqcuda.hpp + ) + + +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-D_FORCE_INLINES;--disable-warnings;--ptxas-options=-v;-Xptxas=-dlcm=ca;-Xptxas=-dscm=cs; -O3) + +FIND_PACKAGE(CUDA REQUIRED) +if(COMPUTE AND (COMPUTE GREATER 0)) + LIST(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_${COMPUTE},code=sm_${COMPUTE}) +else(COMPUTE AND (COMPUTE GREATER 0)) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; -gencode arch=compute_60,code=sm_60 ) +endif(COMPUTE AND (COMPUTE GREATER 0)) + +if(CUDA_FOUND) +message("CUDA FOUND") +else() +message("CUDA NOT FOUND") +endif() + + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CUDA_INCLUDE_DIRS}) +include_directories(..) +CUDA_ADD_LIBRARY(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ${CUDA_LIBRARIES} cuda) + +message("-- CUDA_NVCC_FLAGS: ${CUDA_NVCC_FLAGS}") + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/cuda_djezo/blake2b.cu b/cuda_djezo/blake2b.cu new file mode 100644 index 000000000..866c82592 --- /dev/null +++ b/cuda_djezo/blake2b.cu @@ -0,0 +1,336 @@ +// Blake2-B CUDA Implementation +// tpruvot@github July 2016 +// permission granted to use under MIT license +// modified for use in Zcash by John Tromp September 2016 + +/** + * uint2 direct ops by c++ operator definitions + */ +static __device__ __forceinline__ uint2 operator^ (uint2 a, uint2 b) { + return make_uint2(a.x ^ b.x, a.y ^ b.y); +} +static __forceinline__ __device__ uint4 operator^ (uint4 a, uint4 b) { + return make_uint4(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); +} +// uint2 ROR/ROL methods +__device__ __forceinline__ uint2 ROR2(const uint2 a, const int offset) { + uint2 result; +#if __CUDA_ARCH__ > 300 +/* if (offset < 32) { + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.x) : "r"(a.x), "r"(a.y), "r"(offset)); + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.y) : "r"(a.y), "r"(a.x), "r"(offset)); + } else *//* if (offset < 64) */ { + /* offset SHOULD BE < 64 ! */ + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.x) : "r"(a.y), "r"(a.x), "r"(offset)); + asm("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(result.y) : "r"(a.x), "r"(a.y), "r"(offset)); + } +#else + if (!offset) + result = a; + else if (offset < 32) { + result.y = ((a.y >> offset) | (a.x << (32 - offset))); + result.x = ((a.x >> offset) | (a.y << (32 - offset))); + } else if (offset == 32) { + result.y = a.x; + result.x = a.y; + } else { + result.y = ((a.x >> (offset - 32)) | (a.y << (64 - offset))); + result.x = ((a.y >> (offset - 32)) | (a.x << (64 - offset))); + } +#endif + return result; +} +__device__ __forceinline__ uint2 SWAPUINT2(uint2 value) { + return make_uint2(value.y, value.x); +} +#ifdef __CUDA_ARCH__ +__device__ __inline__ uint2 ROR24(const uint2 a) { + uint2 result; + result.x = __byte_perm(a.y, a.x, 0x2107); + result.y = __byte_perm(a.y, a.x, 0x6543); + return result; +} +__device__ __inline__ uint2 ROR16(const uint2 a) { + uint2 result; + result.x = __byte_perm(a.y, a.x, 0x1076); + result.y = __byte_perm(a.y, a.x, 0x5432); + return result; +} +#else +#define ROR24(u) ROR2(u,24) +#define ROR16(u) ROR2(u,16) +#endif + +typedef uint64_t u64; + +static __constant__ const int8_t blake2b_sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +__device__ __constant__ +static const u64 blake_iv[] = +{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +}; + +__device__ __forceinline__ +static void G(const int r, const int i, u64 &a, u64 &b, u64 &c, u64 &d, u64 const m[16]) { + a = a + b + m[ blake2b_sigma[r][2*i] ]; + ((uint2*)&d)[0] = SWAPUINT2( ((uint2*)&d)[0] ^ ((uint2*)&a)[0] ); + c = c + d; + ((uint2*)&b)[0] = ROR24( ((uint2*)&b)[0] ^ ((uint2*)&c)[0] ); + a = a + b + m[ blake2b_sigma[r][2*i+1] ]; + ((uint2*)&d)[0] = ROR16( ((uint2*)&d)[0] ^ ((uint2*)&a)[0] ); + c = c + d; + ((uint2*)&b)[0] = ROR2( ((uint2*)&b)[0] ^ ((uint2*)&c)[0], 63U); +} + +//__device__ __forceinline__ +//static void G2(u64 &a, u64 &b, u64 &c, u64 &d, u64 x, u64 y) { +// a = a + b + x; +// ((uint2*)&d)[0] = SWAPUINT2(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); +// c = c + d; +// ((uint2*)&b)[0] = ROR24(((uint2*)&b)[0] ^ ((uint2*)&c)[0]); +// a = a + b + y; +// ((uint2*)&d)[0] = ROR16(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); +// c = c + d; +// ((uint2*)&b)[0] = ROR2(((uint2*)&b)[0] ^ ((uint2*)&c)[0], 63U); +//} + +__device__ __forceinline__ +static void G2(u64 & a, u64 & b, u64 & c, u64 & d, u64 x, u64 y) { + a = a + b + x; + ((uint2*)&d)[0] = SWAPUINT2(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); + c = c + d; + ((uint2*)&b)[0] = ROR24(((uint2*)&b)[0] ^ ((uint2*)&c)[0]); + a = a + b + y; + ((uint2*)&d)[0] = ROR16(((uint2*)&d)[0] ^ ((uint2*)&a)[0]); + c = c + d; + ((uint2*)&b)[0] = ROR2(((uint2*)&b)[0] ^ ((uint2*)&c)[0], 63U); +} + +#define ROUND(r) \ + G(r, 0, v[0], v[4], v[ 8], v[12], m); \ + G(r, 1, v[1], v[5], v[ 9], v[13], m); \ + G(r, 2, v[2], v[6], v[10], v[14], m); \ + G(r, 3, v[3], v[7], v[11], v[15], m); \ + G(r, 4, v[0], v[5], v[10], v[15], m); \ + G(r, 5, v[1], v[6], v[11], v[12], m); \ + G(r, 6, v[2], v[7], v[ 8], v[13], m); \ + G(r, 7, v[3], v[4], v[ 9], v[14], m); + + +__forceinline__ __device__ void blake2b_gpu_hash3(uint64_t* h, u32 idx, u32 nonce) { + u64 m = (u64)idx << 32 | (u64)nonce; + + u64 v[16]; + + v[0] = h[0]; + v[1] = h[1]; + v[2] = h[2]; + v[3] = h[3]; + v[4] = h[4]; + v[5] = h[5]; + v[6] = h[6]; + v[7] = h[7]; + v[8] = blake_iv[0]; + v[9] = blake_iv[1]; + v[10] = blake_iv[2]; + v[11] = blake_iv[3]; + v[12] = blake_iv[4] ^ (128 + 16); + v[13] = blake_iv[5]; + v[14] = blake_iv[6] ^ 0xffffffffffffffff; + v[15] = blake_iv[7]; + + // mix 1 + G2(v[0], v[4], v[8], v[12], 0, m); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 2 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], m, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 3 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, m); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 4 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, m); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 5 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, m); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 6 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], m, 0); + + // mix 7 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], m, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 8 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, m); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 9 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], m, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 10 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], m, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 11 + G2(v[0], v[4], v[8], v[12], 0, m); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], 0, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + // mix 12 + G2(v[0], v[4], v[8], v[12], 0, 0); + G2(v[1], v[5], v[9], v[13], 0, 0); + G2(v[2], v[6], v[10], v[14], 0, 0); + G2(v[3], v[7], v[11], v[15], 0, 0); + G2(v[0], v[5], v[10], v[15], m, 0); + G2(v[1], v[6], v[11], v[12], 0, 0); + G2(v[2], v[7], v[8], v[13], 0, 0); + G2(v[3], v[4], v[9], v[14], 0, 0); + + h[0] ^= v[0] ^ v[8]; + h[1] ^= v[1] ^ v[9]; + h[2] ^= v[2] ^ v[10]; + h[3] ^= v[3] ^ v[11]; + h[4] ^= v[4] ^ v[12]; + h[5] ^= v[5] ^ v[13]; + h[6] ^= v[6] ^ v[14]; +} + + +__forceinline__ __device__ void blake2b_gpu_hash2(uint64_t* h, u32 idx) { + u64 m[16] = { 0 }; + u32* ptr = (u32*)&m[1]; + + ptr[1] = idx; + + u64 v[16]; + + v[0] = h[0]; + v[1] = h[1]; + v[2] = h[2]; + v[3] = h[3]; + v[4] = h[4]; + v[5] = h[5]; + v[6] = h[6]; + v[7] = h[7]; + v[8] = 0x6a09e667f3bcc908; + v[9] = 0xbb67ae8584caa73b; + v[10] = 0x3c6ef372fe94f82b; + v[11] = 0xa54ff53a5f1d36f1; + v[12] = 0x510e527fade682d1 ^ (128 + 16); + v[13] = 0x9b05688c2b3e6c1f; + v[14] = 0x1f83d9abfb41bd6b ^ 0xffffffffffffffff; + v[15] = 0x5be0cd19137e2179; + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + + h[0] ^= v[0] ^ v[8]; + h[1] ^= v[1] ^ v[9]; + h[2] ^= v[2] ^ v[10]; + h[3] ^= v[3] ^ v[11]; + h[4] ^= v[4] ^ v[12]; + h[5] ^= v[5] ^ v[13]; + h[6] ^= v[6] ^ v[14]; + //h[7] ^= v[7] ^ v[15]; + //memcpy(hash, (uchar *)h, outlen); +} \ No newline at end of file diff --git a/cuda_djezo/equi_miner.cu b/cuda_djezo/equi_miner.cu index b3401b2bb..6ef9f45f2 100644 --- a/cuda_djezo/equi_miner.cu +++ b/cuda_djezo/equi_miner.cu @@ -2156,4 +2156,4 @@ template class eq_cuda_context; #ifdef CONFIG_MODE_3 template class eq_cuda_context; -#endif \ No newline at end of file +#endif diff --git a/cuda_tromp/CMakeLists.txt b/cuda_tromp/CMakeLists.txt new file mode 100644 index 000000000..12bdc8bf4 --- /dev/null +++ b/cuda_tromp/CMakeLists.txt @@ -0,0 +1,57 @@ +set(EXECUTABLE cuda_tromp) + +option(ENABLE_CUDA "Enable the cuda build" ON) + +# depending on gcc version +# ;-std=c++11 => Ubuntu 14.04 check gcc versions +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-std=c++11) + +file(GLOB SRC_LIST + cuda_tromp.cpp + equi_miner.cu ) +file(GLOB HEADERS + cuda_tromp.hpp + eqcuda.hpp + ) + + +#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) + +set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) + +add_definitions(-DHIST) +#add_definitions(-DXINTREE) +#add_definitions(-DUNROLL) + +list(APPEND CUDA_NVCC_FLAGS_RELEASE -O3) + + +FIND_PACKAGE(CUDA REQUIRED) +if(COMPUTE AND (COMPUTE GREATER 0)) + LIST(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_${COMPUTE},code=sm_${COMPUTE}) +else(COMPUTE AND (COMPUTE GREATER 0)) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};; -gencode arch=compute_20,code=sm_21; -gencode arch=compute_30,code=sm_30; -gencode arch=compute_35,code=sm_35; -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; -gencode arch=compute_61,code=sm_61 ) +endif(COMPUTE AND (COMPUTE GREATER 0)) + +include_directories(${CUDA_INCLUDE_DIRS}) + +find_package(Threads REQUIRED COMPONENTS) +find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) + +if(CUDA_FOUND) +message("CUDA FOUND") +else() +message("CUDA NOT FOUND") +endif() + + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CUDA_INCLUDE_DIRS}) +include_directories(..) +CUDA_ADD_LIBRARY(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +TARGET_LINK_LIBRARIES(${EXECUTABLE} ${CUDA_LIBRARIES}) + +message("-- CUDA_NVCC_FLAGS: ${CUDA_NVCC_FLAGS}") + +install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/nheqminer/MinerFactory.cpp b/nheqminer/MinerFactory.cpp index 7a0102e4c..b8a701956 100644 --- a/nheqminer/MinerFactory.cpp +++ b/nheqminer/MinerFactory.cpp @@ -56,6 +56,8 @@ void MinerFactory::ClearAllSolvers() { } ISolver * MinerFactory::GenCPUSolver(int use_opt) { + // TODO fix dynamic linking on Linux +#ifdef USE_CPU_XENONCAT if (_use_xenoncat) { _solvers.push_back(new CPUSolverXenoncat(use_opt)); return _solvers.back(); @@ -63,6 +65,10 @@ ISolver * MinerFactory::GenCPUSolver(int use_opt) { _solvers.push_back(new CPUSolverTromp(use_opt)); return _solvers.back(); } +#else + _solvers.push_back(new CPUSolverTromp(use_opt)); + return _solvers.back(); +#endif } ISolver * MinerFactory::GenCUDASolver(int dev_id, int blocks, int threadsperblock) { @@ -75,7 +81,7 @@ ISolver * MinerFactory::GenCUDASolver(int dev_id, int blocks, int threadsperbloc return _solvers.back(); } } - +// no OpenCL solvers at the moment keep for future reference ISolver * MinerFactory::GenOPENCLSolver(int platf_id, int dev_id) { if (_use_silentarmy) { _solvers.push_back(new OPENCLSolverSilentarmy(platf_id, dev_id)); diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index 78591189d..0b5516e2f 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -108,7 +108,12 @@ void print_help() void print_cuda_info() { - int num_devices = cuda_tromp::getcount(); +#if defined(USE_CUDA_DJEZO) || defined(USE_CUDA_TROMP) +#ifdef USE_CUDA_DJEZO + int num_devices = cuda_djezo::getcount(); +#elif USE_CUDA_TROMP + int num_devices = cuda_tromp::getcount(); +#endif std::cout << "Number of CUDA devices found: " << num_devices << std::endl; @@ -123,6 +128,7 @@ void print_cuda_info() #endif std::cout << "\t#" << i << " " << gpuname << " | SM version: " << version << " | SM count: " << smcount << std::endl; } +#endif } void print_opencl_info() { From 6c4eda5e6457efed28bf85ef6c41d1993e0f5333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 21:32:58 +0100 Subject: [PATCH 13/15] update TODO list --- nheqminer/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nheqminer/main.cpp b/nheqminer/main.cpp index 0b5516e2f..6f7a230c5 100644 --- a/nheqminer/main.cpp +++ b/nheqminer/main.cpp @@ -45,9 +45,11 @@ namespace keywords = boost::log::keywords; #endif // TODO: -// file logging -// mingw compilation for windows (faster?) -// benchmark accuracy fix: first wait for solvers to init and then measure speed +// #1 file logging +// #2 mingw compilation for windows (faster?) +// #3 benchmark accuracy fix: first wait for solvers to init and then measure speed +// #4 Linux fix cmake to generate all in one binary (just like Windows) +// #5 after #4 is done add solver chooser for CPU and CUDA devices (general and per device), example: [-s 0 automatic, -s 1 solver1, -s 2 solver2, ...] int use_avx = 0; int use_avx2 = 0; From 70db18f64accad16d48bb3c16d498a01ab9f21e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 21:39:03 +0100 Subject: [PATCH 14/15] minor ver bump, removed Linux_cmake folder --- Linux_cmake/nheqminer_cpu/CMakeLists.txt | 137 ------------- .../nheqminer_cpu_tromp/CMakeLists.txt | 143 ------------- .../nheqminer_cpu_xenoncat/CMakeLists.txt | 122 ------------ .../nheqminer_cuda_djezo/CMakeLists.txt | 188 ------------------ .../nheqminer_cuda_tromp/CMakeLists.txt | 177 ----------------- nheqminer/version.h | 2 +- 6 files changed, 1 insertion(+), 768 deletions(-) delete mode 100644 Linux_cmake/nheqminer_cpu/CMakeLists.txt delete mode 100644 Linux_cmake/nheqminer_cpu_tromp/CMakeLists.txt delete mode 100644 Linux_cmake/nheqminer_cpu_xenoncat/CMakeLists.txt delete mode 100644 Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt delete mode 100644 Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt diff --git a/Linux_cmake/nheqminer_cpu/CMakeLists.txt b/Linux_cmake/nheqminer_cpu/CMakeLists.txt deleted file mode 100644 index d4269b444..000000000 --- a/Linux_cmake/nheqminer_cpu/CMakeLists.txt +++ /dev/null @@ -1,137 +0,0 @@ -project(nheqminer_cpu) -cmake_minimum_required(VERSION 2.8) - -#aux_source_directory(. SRC_LIST) -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -# LINUX -if(CMAKE_COMPILER_IS_GNUCXX) - # use native cpu features - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - # optimizations - add_definitions(-O3) -endif() - -# Common -include_directories(${nheqminer_SOURCE_DIR}) - -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) - -find_package(Threads REQUIRED COMPONENTS) -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - -## Add solvers here -add_definitions(-DUSE_CPU_XENONCAT) -add_definitions(-DUSE_CPU_TROMP) - -add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) -set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx1.o" ) - -add_library ( xenoncat_avx2 SHARED IMPORTED GLOBAL ) -set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx2.o" ) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) - -set(SOURCE_FILES - # sources - ../../nheqminer/amount.cpp - ../../nheqminer/api.cpp - ../../nheqminer/arith_uint256.cpp - ../../nheqminer/crypto/sha256.cpp - ../../nheqminer/json/json_spirit_reader.cpp - ../../nheqminer/json/json_spirit_value.cpp - ../../nheqminer/json/json_spirit_writer.cpp - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/main.cpp - ../../nheqminer/primitives/block.cpp - ../../nheqminer/speed.cpp - ../../nheqminer/uint256.cpp - ../../nheqminer/utilstrencodings.cpp - # headers - ../../nheqminer/amount.h - ../../nheqminer/api.hpp - ../../nheqminer/arith_uint256.h - ../../nheqminer/crypto/sha256.h - ../../nheqminer/hash.h - ../../nheqminer/json/json_spirit.h - ../../nheqminer/json/json_spirit_error_position.h - ../../nheqminer/json/json_spirit_reader.h - ../../nheqminer/json/json_spirit_reader_template.h - ../../nheqminer/json/json_spirit_stream_reader.h - ../../nheqminer/json/json_spirit_utils.h - ../../nheqminer/json/json_spirit_value.h - ../../nheqminer/json/json_spirit_writer.h - ../../nheqminer/json/json_spirit_writer_template.h - ../../nheqminer/libstratum/StratumClient.cpp - ../../nheqminer/libstratum/StratumClient.h - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/libstratum/ZcashStratum.h - ../../nheqminer/primitives/block.h - ../../nheqminer/primitives/transaction.h - ../../nheqminer/script/script.h - ../../nheqminer/serialize.h - ../../nheqminer/speed.hpp - ../../nheqminer/streams.h - ../../nheqminer/support/allocators/zeroafterfree.h - ../../nheqminer/tinyformat.h - ../../nheqminer/uint252.h - ../../nheqminer/uint256.h - ../../nheqminer/utilstrencodings.h - ../../nheqminer/version.h - ../../nheqminer/zcash/JoinSplit.hpp - ../../nheqminer/zcash/NoteEncryption.hpp - ../../nheqminer/zcash/Proof.hpp - ../../nheqminer/zcash/Zcash.h - ../../nheqminer/SolverStub.h # just a stub - - # cpu tromp - ../../cpu_tromp/blake2/blake2bx.cpp - ../../cpu_tromp/cpu_tromp.cpp - ../../cpu_tromp/blake2/blake2-config.h - ../../cpu_tromp/blake2/blake2-impl.h - ../../cpu_tromp/blake2/blake2-round.h - ../../cpu_tromp/blake2/blake2.h - ../../cpu_tromp/blake2/blake2b-load-sse2.h - ../../cpu_tromp/blake2/blake2b-load-sse41.h - ../../cpu_tromp/blake2/blake2b-round.h - ../../cpu_tromp/cpu_tromp.hpp - ../../cpu_tromp/equi.h - ../../cpu_tromp/equi_miner.h - - # cpu xenocat - ../../cpu_xenoncat/cpu_xenoncat.hpp - ../../cpu_xenoncat/xenoncat.cpp - ) - -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(LIBS ${LIBS} ${Boost_LIBRARIES}) - -#message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -#message("-- LIBS: ${LIBS}") - -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT} xenoncat_avx1 xenoncat_avx2 ) diff --git a/Linux_cmake/nheqminer_cpu_tromp/CMakeLists.txt b/Linux_cmake/nheqminer_cpu_tromp/CMakeLists.txt deleted file mode 100644 index 1fe33e5e6..000000000 --- a/Linux_cmake/nheqminer_cpu_tromp/CMakeLists.txt +++ /dev/null @@ -1,143 +0,0 @@ -project(nheqminer_cpu_tromp) -cmake_minimum_required(VERSION 2.8) - -#aux_source_directory(. SRC_LIST) -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -# LINUX -if(CMAKE_COMPILER_IS_GNUCXX) - # use native cpu features - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - # optimizations - add_definitions(-O3) -endif() - -# Common -include_directories(${nheqminer_SOURCE_DIR}) - -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) - -find_package(Threads REQUIRED COMPONENTS) -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - -## Add solvers here -add_definitions(-DUSE_CPU_TROMP) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) - -set(SOURCE_FILES - # sources - ../../nheqminer/amount.cpp - ../../nheqminer/api.cpp - ../../nheqminer/arith_uint256.cpp - ../../nheqminer/crypto/sha256.cpp - ../../nheqminer/json/json_spirit_reader.cpp - ../../nheqminer/json/json_spirit_value.cpp - ../../nheqminer/json/json_spirit_writer.cpp - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/main.cpp - ../../nheqminer/primitives/block.cpp - ../../nheqminer/speed.cpp - ../../nheqminer/uint256.cpp - ../../nheqminer/utilstrencodings.cpp - # headers - ../../nheqminer/amount.h - ../../nheqminer/api.hpp - ../../nheqminer/arith_uint256.h - ../../nheqminer/crypto/sha256.h - ../../nheqminer/hash.h - ../../nheqminer/json/json_spirit.h - ../../nheqminer/json/json_spirit_error_position.h - ../../nheqminer/json/json_spirit_reader.h - ../../nheqminer/json/json_spirit_reader_template.h - ../../nheqminer/json/json_spirit_stream_reader.h - ../../nheqminer/json/json_spirit_utils.h - ../../nheqminer/json/json_spirit_value.h - ../../nheqminer/json/json_spirit_writer.h - ../../nheqminer/json/json_spirit_writer_template.h - ../../nheqminer/libstratum/StratumClient.cpp - ../../nheqminer/libstratum/StratumClient.h - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/libstratum/ZcashStratum.h - ../../nheqminer/primitives/block.h - ../../nheqminer/primitives/transaction.h - ../../nheqminer/script/script.h - ../../nheqminer/serialize.h - ../../nheqminer/speed.hpp - ../../nheqminer/streams.h - ../../nheqminer/support/allocators/zeroafterfree.h - ../../nheqminer/tinyformat.h - ../../nheqminer/uint252.h - ../../nheqminer/uint256.h - ../../nheqminer/utilstrencodings.h - ../../nheqminer/version.h - ../../nheqminer/zcash/JoinSplit.hpp - ../../nheqminer/zcash/NoteEncryption.hpp - ../../nheqminer/zcash/Proof.hpp - ../../nheqminer/zcash/Zcash.h - ../../nheqminer/SolverStub.h # just a stub - - # cpu tromp - ../../cpu_tromp/blake2/blake2bx.cpp - ../../cpu_tromp/cpu_tromp.cpp - ../../cpu_tromp/blake2/blake2-config.h - ../../cpu_tromp/blake2/blake2-impl.h - ../../cpu_tromp/blake2/blake2-round.h - ../../cpu_tromp/blake2/blake2.h - ../../cpu_tromp/blake2/blake2b-load-sse2.h - ../../cpu_tromp/blake2/blake2b-load-sse41.h - ../../cpu_tromp/blake2/blake2b-round.h - ../../cpu_tromp/cpu_tromp.hpp - ../../cpu_tromp/equi.h - ../../cpu_tromp/equi_miner.h - ) - -#if(USE_CPU_TROMP) -# set(SOURCE_FILES ${SOURCE_FILES} -# ../../cpu_tromp/blake2/blake2bx.cpp -# ../../cpu_tromp/cpu_tromp.cpp -# ../../cpu_tromp/blake2/blake2-config.h -# ../../cpu_tromp/blake2/blake2-impl.h -# ../../cpu_tromp/blake2/blake2-round.h -# ../../cpu_tromp/blake2/blake2.h -# ../../cpu_tromp/blake2/blake2b-load-sse2.h -# ../../cpu_tromp/blake2/blake2b-load-sse41.h -# ../../cpu_tromp/blake2/blake2b-round.h -# ../../cpu_tromp/cpu_tromp.hpp -# ../../cpu_tromp/equi.h -# ../../cpu_tromp/equi_miner.h -# ) -#endif() - -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(LIBS ${LIBS} ${Boost_LIBRARIES}) - -#message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -#message("-- LIBS: ${LIBS}") - -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/Linux_cmake/nheqminer_cpu_xenoncat/CMakeLists.txt b/Linux_cmake/nheqminer_cpu_xenoncat/CMakeLists.txt deleted file mode 100644 index 25d58c633..000000000 --- a/Linux_cmake/nheqminer_cpu_xenoncat/CMakeLists.txt +++ /dev/null @@ -1,122 +0,0 @@ -project(nheqminer_cpu_xenoncat) -cmake_minimum_required(VERSION 2.8) - -#aux_source_directory(. SRC_LIST) -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -# LINUX -if(CMAKE_COMPILER_IS_GNUCXX) - # use native cpu features - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - # optimizations - add_definitions(-O3) -endif() - -# Common -include_directories(${nheqminer_SOURCE_DIR}) - -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) - -find_package(Threads REQUIRED COMPONENTS) -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - -## Add solvers here -add_definitions(-DUSE_CPU_XENONCAT) - -add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) -set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx1.o" ) - -add_library ( xenoncat_avx2 SHARED IMPORTED GLOBAL ) -set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx2.o" ) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) - -set(SOURCE_FILES - # sources - ../../nheqminer/amount.cpp - ../../nheqminer/api.cpp - ../../nheqminer/arith_uint256.cpp - ../../nheqminer/crypto/sha256.cpp - ../../nheqminer/json/json_spirit_reader.cpp - ../../nheqminer/json/json_spirit_value.cpp - ../../nheqminer/json/json_spirit_writer.cpp - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/main.cpp - ../../nheqminer/primitives/block.cpp - ../../nheqminer/speed.cpp - ../../nheqminer/uint256.cpp - ../../nheqminer/utilstrencodings.cpp - # headers - ../../nheqminer/amount.h - ../../nheqminer/api.hpp - ../../nheqminer/arith_uint256.h - ../../nheqminer/crypto/sha256.h - ../../nheqminer/hash.h - ../../nheqminer/json/json_spirit.h - ../../nheqminer/json/json_spirit_error_position.h - ../../nheqminer/json/json_spirit_reader.h - ../../nheqminer/json/json_spirit_reader_template.h - ../../nheqminer/json/json_spirit_stream_reader.h - ../../nheqminer/json/json_spirit_utils.h - ../../nheqminer/json/json_spirit_value.h - ../../nheqminer/json/json_spirit_writer.h - ../../nheqminer/json/json_spirit_writer_template.h - ../../nheqminer/libstratum/StratumClient.cpp - ../../nheqminer/libstratum/StratumClient.h - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/libstratum/ZcashStratum.h - ../../nheqminer/primitives/block.h - ../../nheqminer/primitives/transaction.h - ../../nheqminer/script/script.h - ../../nheqminer/serialize.h - ../../nheqminer/speed.hpp - ../../nheqminer/streams.h - ../../nheqminer/support/allocators/zeroafterfree.h - ../../nheqminer/tinyformat.h - ../../nheqminer/uint252.h - ../../nheqminer/uint256.h - ../../nheqminer/utilstrencodings.h - ../../nheqminer/version.h - ../../nheqminer/zcash/JoinSplit.hpp - ../../nheqminer/zcash/NoteEncryption.hpp - ../../nheqminer/zcash/Proof.hpp - ../../nheqminer/zcash/Zcash.h - ../../nheqminer/SolverStub.h # just a stub - - # cpu xenocat - ../../cpu_xenoncat/cpu_xenoncat.hpp - ../../cpu_xenoncat/xenoncat.cpp - ) - -#add_executable(${PROJECT_NAME} ${SRC_LIST}) - -set(LIBS ${LIBS} ${Boost_LIBRARIES}) - -#message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -#message("-- LIBS: ${LIBS}") - -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CMAKE_THREAD_LIBS_INIT} xenoncat_avx1 xenoncat_avx2 ) diff --git a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt deleted file mode 100644 index 2c9e761c9..000000000 --- a/Linux_cmake/nheqminer_cuda_djezo/CMakeLists.txt +++ /dev/null @@ -1,188 +0,0 @@ -project(nheqminer_cuda_djezo) -cmake_minimum_required(VERSION 2.8) - -option(ENABLE_CUDA "Enable the cuda build" ON) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -# LINUX -if(CMAKE_COMPILER_IS_GNUCXX) - # use native cpu features - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - # optimizations - add_definitions(-O3) -endif() - -# Common -include_directories(${nheqminer_SOURCE_DIR}) - -#add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) -# BOOST -#find_package(Threads REQUIRED COMPONENTS) -# compile boost staticaly -set(Boost_USE_STATIC_LIBS ON) -set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") -#set(BUILD_SHARED_LIBRARIES OFF) -#set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - -#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) -#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) -set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-D_FORCE_INLINES;--disable-warnings;--ptxas-options=-v;-Xptxas=-dlcm=ca;-Xptxas=-dscm=cs; -O3) - -add_definitions(-DHIST) -#add_definitions(-DXINTREE) -#add_definitions(-DUNROLL) - - -FIND_PACKAGE(CUDA REQUIRED) -if(COMPUTE AND (COMPUTE GREATER 0)) - LIST(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_${COMPUTE},code=sm_${COMPUTE}) -else(COMPUTE AND (COMPUTE GREATER 0)) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS}; -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; -gencode arch=compute_61,code=sm_61 ) -endif(COMPUTE AND (COMPUTE GREATER 0)) - -include_directories(${CUDA_INCLUDE_DIRS}) - -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if(CUDA_FOUND) -message("CUDA FOUND") -else() -message("CUDA NOT FOUND") -endif() - -## Add solvers here -#add_definitions(-DUSE_CPU_XENONCAT) -#add_definitions(-DUSE_CPU_TROMP) -add_definitions(-DUSE_CUDA_DJEZO) - -#add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) -#set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx1.o" ) - -#add_library ( xenoncat_avx2 SHARED IMPORTED GLOBAL ) -#set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx2.o" ) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) - -set(SOURCE_FILES - # sources - ../../nheqminer/amount.cpp - ../../nheqminer/api.cpp - ../../nheqminer/arith_uint256.cpp - ../../nheqminer/crypto/sha256.cpp - ../../nheqminer/json/json_spirit_reader.cpp - ../../nheqminer/json/json_spirit_value.cpp - ../../nheqminer/json/json_spirit_writer.cpp - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/main.cpp - ../../nheqminer/primitives/block.cpp - ../../nheqminer/speed.cpp - ../../nheqminer/uint256.cpp - ../../nheqminer/utilstrencodings.cpp - # headers - ../../nheqminer/amount.h - ../../nheqminer/api.hpp - ../../nheqminer/arith_uint256.h - ../../nheqminer/crypto/sha256.h - ../../nheqminer/hash.h - ../../nheqminer/json/json_spirit.h - ../../nheqminer/json/json_spirit_error_position.h - ../../nheqminer/json/json_spirit_reader.h - ../../nheqminer/json/json_spirit_reader_template.h - ../../nheqminer/json/json_spirit_stream_reader.h - ../../nheqminer/json/json_spirit_utils.h - ../../nheqminer/json/json_spirit_value.h - ../../nheqminer/json/json_spirit_writer.h - ../../nheqminer/json/json_spirit_writer_template.h - ../../nheqminer/libstratum/StratumClient.cpp - ../../nheqminer/libstratum/StratumClient.h - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/libstratum/ZcashStratum.h - ../../nheqminer/primitives/block.h - ../../nheqminer/primitives/transaction.h - ../../nheqminer/script/script.h - ../../nheqminer/serialize.h - ../../nheqminer/speed.hpp - ../../nheqminer/streams.h - ../../nheqminer/support/allocators/zeroafterfree.h - ../../nheqminer/tinyformat.h - ../../nheqminer/uint252.h - ../../nheqminer/uint256.h - ../../nheqminer/utilstrencodings.h - ../../nheqminer/version.h - ../../nheqminer/zcash/JoinSplit.hpp - ../../nheqminer/zcash/NoteEncryption.hpp - ../../nheqminer/zcash/Proof.hpp - ../../nheqminer/zcash/Zcash.h - ../../nheqminer/SolverStub.h # just a stub - - ../../nheqminer/AvailableSolvers.h - ../../nheqminer/ISolver.h - ../../nheqminer/Solver.h - ../../nheqminer/MinerFactory.h - ../../nheqminer/MinerFactory.cpp - -# # cpu tromp -# ../../cpu_tromp/blake2/blake2bx.cpp -# ../../cpu_tromp/cpu_tromp.cpp -# ../../cpu_tromp/blake2/blake2-config.h -# ../../cpu_tromp/blake2/blake2-impl.h -# ../../cpu_tromp/blake2/blake2-round.h -# ../../cpu_tromp/blake2/blake2.h -# ../../cpu_tromp/blake2/blake2b-load-sse2.h -# ../../cpu_tromp/blake2/blake2b-load-sse41.h -# ../../cpu_tromp/blake2/blake2b-round.h -# ../../cpu_tromp/cpu_tromp.hpp -# ../../cpu_tromp/equi.h -# ../../cpu_tromp/equi_miner.h - -# # cpu xenocat -# ../../cpu_xenoncat/cpu_xenoncat.hpp -# ../../cpu_xenoncat/xenoncat.cpp - -# # cuda tromp -# ../../cuda_tromp/cuda_tromp.hpp -# ../../cuda_tromp/cuda_tromp.cpp -# ../../cuda_tromp/eqcuda.hpp -# ../../cuda_tromp/equi_miner.cu - ../../cpu_tromp/blake2/blake2bx.cpp - - # cuda djezo - ../../cuda_djezo/cuda_djezo.cpp - ../../cuda_djezo/cuda_djezo.hpp - ../../cuda_djezo/equi_miner.cu - ../../cuda_djezo/eqcuda.hpp - - ) - -#add_executable(${PROJECT_NAME} ${SRC_LIST}) -set(LIBS ${LIBS} ${Boost_LIBRARIES} "cuda") - -#message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -#message("-- LIBS: ${LIBS}") - -#add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -CUDA_ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${LIBS} ${CUDA_LIBRARIES} ) diff --git a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt b/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt deleted file mode 100644 index 69dbe66af..000000000 --- a/Linux_cmake/nheqminer_cuda_tromp/CMakeLists.txt +++ /dev/null @@ -1,177 +0,0 @@ -project(nheqminer_cuda_tromp) -cmake_minimum_required(VERSION 2.8) - -option(ENABLE_CUDA "Enable the cuda build" ON) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - -# LINUX -if(CMAKE_COMPILER_IS_GNUCXX) - # use native cpu features - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - # optimizations - add_definitions(-O3) -endif() - -# Common -include_directories(${nheqminer_SOURCE_DIR}) - -add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_ALL_DYN_LINK -DBOOST_LOG_DYN_LINK) - -#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-m64;--std=c++11;--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) - -set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};--disable-warnings;--ptxas-options=-v;-use_fast_math;-lineinfo) - -add_definitions(-DHIST) -#add_definitions(-DXINTREE) -#add_definitions(-DUNROLL) - -list(APPEND CUDA_NVCC_FLAGS_RELEASE -O3) - - -FIND_PACKAGE(CUDA REQUIRED) -if(COMPUTE AND (COMPUTE GREATER 0)) - LIST(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_${COMPUTE},code=sm_${COMPUTE}) -else(COMPUTE AND (COMPUTE GREATER 0)) - set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};; -gencode arch=compute_20,code=sm_21; -gencode arch=compute_30,code=sm_30; -gencode arch=compute_35,code=sm_35; -gencode arch=compute_50,code=sm_50; -gencode arch=compute_52,code=sm_52; -gencode arch=compute_61,code=sm_61 ) -endif(COMPUTE AND (COMPUTE GREATER 0)) - -include_directories(${CUDA_INCLUDE_DIRS}) - -find_package(Threads REQUIRED COMPONENTS) -find_package(Boost REQUIRED COMPONENTS system log_setup log date_time filesystem thread) - -if(CUDA_FOUND) -message("CUDA FOUND") -else() -message("CUDA NOT FOUND") -endif() - -if (Boost_FOUND) - # From the offical documentation: - # Add include directories to the build. [...] If the SYSTEM option is given, - # the compiler will be told the directories are meant as system include - # directories on some platforms (signalling this setting might achieve effects - # such as the compiler skipping warnings [...])." - include_directories (SYSTEM ${Boost_INCLUDE_DIR}) - - # From the offical documentation: - # "Specify directories in which the linker will look for libraries. [...] Note - # that this command is rarely necessary. Library locations returned by - # find_package() and find_library() are absolute paths. Pass these absolute - # library file paths directly to the target_link_libraries() command. CMake - # will ensure the linker finds them." - link_directories (${Boost_LIBRARY_DIRS}) -else() - message("Boost_FOUND NOT FOUND") -endif () - -## Add solvers here -#add_definitions(-DUSE_CPU_XENONCAT) -#add_definitions(-DUSE_CPU_TROMP) -add_definitions(-DUSE_CUDA_TROMP) - -#add_library ( xenoncat_avx1 SHARED IMPORTED GLOBAL ) -#set_target_properties ( xenoncat_avx1 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx1.o" ) - -#add_library ( xenoncat_avx2 SHARED IMPORTED GLOBAL ) -#set_target_properties ( xenoncat_avx2 PROPERTIES IMPORTED_LOCATION "../../cpu_xenoncat/Linux/asm/equihash_avx2.o" ) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../nheqminer/) - -set(SOURCE_FILES - # sources - ../../nheqminer/amount.cpp - ../../nheqminer/api.cpp - ../../nheqminer/arith_uint256.cpp - ../../nheqminer/crypto/sha256.cpp - ../../nheqminer/json/json_spirit_reader.cpp - ../../nheqminer/json/json_spirit_value.cpp - ../../nheqminer/json/json_spirit_writer.cpp - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/main.cpp - ../../nheqminer/primitives/block.cpp - ../../nheqminer/speed.cpp - ../../nheqminer/uint256.cpp - ../../nheqminer/utilstrencodings.cpp - # headers - ../../nheqminer/amount.h - ../../nheqminer/api.hpp - ../../nheqminer/arith_uint256.h - ../../nheqminer/crypto/sha256.h - ../../nheqminer/hash.h - ../../nheqminer/json/json_spirit.h - ../../nheqminer/json/json_spirit_error_position.h - ../../nheqminer/json/json_spirit_reader.h - ../../nheqminer/json/json_spirit_reader_template.h - ../../nheqminer/json/json_spirit_stream_reader.h - ../../nheqminer/json/json_spirit_utils.h - ../../nheqminer/json/json_spirit_value.h - ../../nheqminer/json/json_spirit_writer.h - ../../nheqminer/json/json_spirit_writer_template.h - ../../nheqminer/libstratum/StratumClient.cpp - ../../nheqminer/libstratum/StratumClient.h - ../../nheqminer/libstratum/ZcashStratum.cpp - ../../nheqminer/libstratum/ZcashStratum.h - ../../nheqminer/primitives/block.h - ../../nheqminer/primitives/transaction.h - ../../nheqminer/script/script.h - ../../nheqminer/serialize.h - ../../nheqminer/speed.hpp - ../../nheqminer/streams.h - ../../nheqminer/support/allocators/zeroafterfree.h - ../../nheqminer/tinyformat.h - ../../nheqminer/uint252.h - ../../nheqminer/uint256.h - ../../nheqminer/utilstrencodings.h - ../../nheqminer/version.h - ../../nheqminer/zcash/JoinSplit.hpp - ../../nheqminer/zcash/NoteEncryption.hpp - ../../nheqminer/zcash/Proof.hpp - ../../nheqminer/zcash/Zcash.h - ../../nheqminer/SolverStub.h # just a stub - - - ../../nheqminer/AvailableSolvers.h - ../../nheqminer/ISolver.h - ../../nheqminer/Solver.h - ../../nheqminer/MinerFactory.h - ../../nheqminer/MinerFactory.cpp - -# # cpu tromp -# ../../cpu_tromp/blake2/blake2bx.cpp -# ../../cpu_tromp/cpu_tromp.cpp -# ../../cpu_tromp/blake2/blake2-config.h -# ../../cpu_tromp/blake2/blake2-impl.h -# ../../cpu_tromp/blake2/blake2-round.h -# ../../cpu_tromp/blake2/blake2.h -# ../../cpu_tromp/blake2/blake2b-load-sse2.h -# ../../cpu_tromp/blake2/blake2b-load-sse41.h -# ../../cpu_tromp/blake2/blake2b-round.h -# ../../cpu_tromp/cpu_tromp.hpp -# ../../cpu_tromp/equi.h -# ../../cpu_tromp/equi_miner.h - -# # cpu xenocat -# ../../cpu_xenoncat/cpu_xenoncat.hpp -# ../../cpu_xenoncat/xenoncat.cpp - - # cuda tromp - ../../cuda_tromp/cuda_tromp.hpp - ../../cuda_tromp/cuda_tromp.cpp - ../../cuda_tromp/eqcuda.hpp - ../../cuda_tromp/equi_miner.cu - ../../cpu_tromp/blake2/blake2bx.cpp - ) - -#add_executable(${PROJECT_NAME} ${SRC_LIST}) -set(LIBS ${LIBS} ${Threads_LIBRARIES} ${Boost_LIBRARIES}) - -#message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") -#message("-- LIBS: ${LIBS}") - -#add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -#target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) -CUDA_ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} ${LIBS} ${CUDA_LIBRARIES} ) diff --git a/nheqminer/version.h b/nheqminer/version.h index f30425f52..af4c23e33 100644 --- a/nheqminer/version.h +++ b/nheqminer/version.h @@ -34,7 +34,7 @@ static const int BIP0031_VERSION = 60000; //! "mempool" command, enhanced "getdata" behavior starts with this version static const int MEMPOOL_GD_VERSION = 60002; -#define STANDALONE_MINER_VERSION "0.5b" +#define STANDALONE_MINER_VERSION "0.5c" // uncomment to use with ZCash address //#define ZCASH_POOL From b9900ff8e3c6f8e5a46af18db454f2a2082d9f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanko=20Krsti=C4=87?= Date: Thu, 12 Jan 2017 22:42:32 +0100 Subject: [PATCH 15/15] update README --- README.md | 60 +++++++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 5343f4e47..e13bb1845 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Build instructions: ### Dependencies: - - Boost 1.54+ + - Boost 1.62+ ## Windows: @@ -24,41 +24,35 @@ Open **nheqminer.sln** under **nheqminer/nheqminer.sln** and build. You will hav If you don't wan't to build with all solvlers you can go to **nheqminer Properties > C/C++ > Preprocessor > Preprocessor Definitions** and remove the solver you don't need. ## Linux - Work in progress. - Working solvers CPU_TROMP, CPU_XENONCAT, CUDA_TROMP, CUDA_DJEZO -## Linux (Ubuntu 14.04 / 16.04) Build CPU_XENONCAT: - - - Open terminal and run the following commands: - - `sudo apt-get install cmake build-essential libboost-all-dev` - - `git clone -b Linux https://github.com/nicehash/nheqminer.git` - - `cd nheqminer/cpu_xenoncat/Linux/asm/` - - `sh assemble.sh` - - `cd ../../../Linux_cmake/nheqminer_cpu_xenoncat` - - `cmake .` - - `make -j $(nproc)` - -## Linux (Ubuntu 14.04 / 16.04) Build CUDA_TROMP: - - - Open terminal and run the following commands: - - **Ubuntu 14.04**: - - `wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/cuda-repo-ubuntu1404_8.0.44-1_amd64.deb` - - `sudo dpkg -i cuda-repo-ubuntu1404_8.0.44-1_amd64.deb` - - **Ubuntu 16.04**: - - `wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.44-1_amd64.deb` - - `sudo dpkg -i cuda-repo-ubuntu1604_8.0.44-1_amd64.deb` - - `sudo apt-get update` - - `sudo apt-get install cuda` - - `sudo apt-get install cuda-toolkit-8-0` - - `sudo apt-get install cmake build-essential libboost-all-dev` - - `git clone -b Linux https://github.com/nicehash/nheqminer.git` - - `cd nheqminer/Linux_cmake/nheqminer_cuda_tromp && cmake . && make -j $(nproc)` - - or specify your compute version for example 50 like so `cd nheqminer/Linux_cmake/nheqminer_cuda_tromp && cmake COMPUTE=50 . && make` - - - +### General instructions: + - Install CUDA SDK v8 (make sure you have cuda libraries in **LD_LIBRARY_PATH** and cuda toolkit bins in **PATH**) + - example on Ubuntu: + - LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/lib64/stubs" + - PATH="$PATH:/usr/local/cuda-8.0/" + - PATH="$PATH:/usr/local/cuda-8.0/bin" + + - Use Boost 1.62+ (if it is not available from the repos you will have to download and build it yourself) + - CMake v3.5 (if it is not available from the repos you will have to download and build it yourself) + - Currently support only static building (CPU_XENONCAT, CUDA_DJEZO are enabled by default, check **CMakeLists.txt** in **nheqminer** root folder) + - If not on Ubuntu make sure you have **fasm** installed and accessible in **PATH** + - After that open the terminal and run the following commands: + - `git clone https://github.com/nicehash/nheqminer.git` + - Generating asm object file: + - **On Ubuntu**: + - `cd nheqminer/cpu_xenoncat/asm_linux/` + - `sh assemble.sh` + - **bundeled fasm not compatible**: + - delete/replace (inside **nheqminer/cpu_xenoncat/asm_linux/** directory) with fasm binary compatible with your distro + - `cd nheqminer/cpu_xenoncat/asm_linux/` + - `sh assemble.sh` + - `cd ../../../` + - `mkdir build && cd build` + - `cmake ../nheqminer` + - `make -j $(nproc)` + # Run instructions: Parameters: