2 // Copyright 2012-2016 Francisco Jerez
3 // Copyright 2012-2016 Advanced Micro Devices, Inc.
4 // Copyright 2015 Zoltan Gilian
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 // OTHER DEALINGS IN THE SOFTWARE.
27 /// Codegen back-end-independent part of the construction of an executable
28 /// clover::module, including kernel argument metadata extraction and
29 /// formatting of the pre-generated binary code in a form that can be
30 /// understood by pipe drivers.
33 #include "llvm/codegen.hpp"
34 #include "llvm/metadata.hpp"
38 #include "pipe/p_state.h"
39 #include "util/u_math.h"
41 #include <clang/Basic/TargetInfo.h>
43 using namespace clover
;
44 using namespace clover::llvm
;
47 using ::llvm::Function
;
51 using ::llvm::dyn_cast
;
54 enum module::argument::type
55 get_image_type(const std::string
&type
,
56 const std::string
&qual
) {
57 if (type
== "image2d_t" && qual
== "read_only")
58 return module::argument::image2d_rd
;
59 else if (type
== "image2d_t" && qual
== "write_only")
60 return module::argument::image2d_wr
;
61 else if (type
== "image3d_t" && qual
== "read_only")
62 return module::argument::image3d_rd
;
63 else if (type
== "image3d_t" && qual
== "write_only")
64 return module::argument::image3d_wr
;
66 unreachable("Unknown image type");
69 std::vector
<module::argument
>
70 make_kernel_args(const Module
&mod
, const std::string
&kernel_name
,
71 const clang::CompilerInstance
&c
) {
72 std::vector
<module::argument
> args
;
73 const auto address_spaces
= c
.getTarget().getAddressSpaceMap();
74 const Function
&f
= *mod
.getFunction(kernel_name
);
75 ::llvm::DataLayout
dl(&mod
);
76 const auto size_type
=
77 dl
.getSmallestLegalIntType(mod
.getContext(), sizeof(cl_uint
) * 8);
79 for (const auto &arg
: f
.args()) {
80 const auto arg_type
= arg
.getType();
82 // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
83 // type that is not a power of two bytes in size must be
84 // aligned to the next larger power of two.
85 // This rule applies to built-in types only, not structs or unions."
86 const unsigned arg_store_size
= dl
.getTypeStoreSize(arg_type
);
87 const unsigned arg_api_size
= dl
.getTypeAllocSize(arg_type
);
89 const auto target_type
= !arg_type
->isIntegerTy() ? arg_type
:
90 dl
.getSmallestLegalIntType(mod
.getContext(), arg_store_size
* 8);
91 const unsigned target_size
= dl
.getTypeStoreSize(target_type
);
92 const unsigned target_align
= dl
.getABITypeAlignment(target_type
);
94 const auto type_name
= get_argument_metadata(f
, arg
,
97 if (type_name
== "image2d_t" || type_name
== "image3d_t") {
99 const auto access_qual
= get_argument_metadata(
100 f
, arg
, "kernel_arg_access_qual");
101 args
.emplace_back(get_image_type(type_name
, access_qual
),
102 arg_store_size
, target_size
,
103 target_align
, module::argument::zero_ext
);
105 } else if (type_name
== "__llvm_image_size") {
106 // Image size implicit argument.
107 args
.emplace_back(module::argument::scalar
, sizeof(cl_uint
),
108 dl
.getTypeStoreSize(size_type
),
109 dl
.getABITypeAlignment(size_type
),
110 module::argument::zero_ext
,
111 module::argument::image_size
);
113 } else if (type_name
== "__llvm_image_format") {
114 // Image format implicit argument.
115 args
.emplace_back(module::argument::scalar
, sizeof(cl_uint
),
116 dl
.getTypeStoreSize(size_type
),
117 dl
.getABITypeAlignment(size_type
),
118 module::argument::zero_ext
,
119 module::argument::image_format
);
123 const auto actual_type
=
124 isa
< ::llvm::PointerType
>(arg_type
) && arg
.hasByValAttr() ?
125 cast
< ::llvm::PointerType
>(arg_type
)->getElementType() : arg_type
;
127 if (actual_type
->isPointerTy()) {
128 const unsigned address_space
=
129 cast
< ::llvm::PointerType
>(actual_type
)->getAddressSpace();
131 if (address_space
== address_spaces
[clang::LangAS::opencl_local
132 - compat::lang_as_offset
]) {
133 args
.emplace_back(module::argument::local
, arg_api_size
,
134 target_size
, target_align
,
135 module::argument::zero_ext
);
137 // XXX: Correctly handle constant address space. There is no
138 // way for r600g to pass a handle for constant buffers back
139 // to clover like it can for global buffers, so
140 // creating constant arguments will break r600g. For now,
141 // continue treating constant buffers as global buffers
142 // until we can come up with a way to create handles for
144 args
.emplace_back(module::argument::global
, arg_api_size
,
145 target_size
, target_align
,
146 module::argument::zero_ext
);
150 const bool needs_sign_ext
= f
.getAttributes().hasAttribute(
151 arg
.getArgNo() + 1, ::llvm::Attribute::SExt
);
153 args
.emplace_back(module::argument::scalar
, arg_api_size
,
154 target_size
, target_align
,
155 (needs_sign_ext
? module::argument::sign_ext
:
156 module::argument::zero_ext
));
161 // Append implicit arguments. XXX - The types, ordering and
162 // vector size of the implicit arguments should depend on the
163 // target according to the selected calling convention.
164 args
.emplace_back(module::argument::scalar
, sizeof(cl_uint
),
165 dl
.getTypeStoreSize(size_type
),
166 dl
.getABITypeAlignment(size_type
),
167 module::argument::zero_ext
,
168 module::argument::grid_dimension
);
170 args
.emplace_back(module::argument::scalar
, sizeof(cl_uint
),
171 dl
.getTypeStoreSize(size_type
),
172 dl
.getABITypeAlignment(size_type
),
173 module::argument::zero_ext
,
174 module::argument::grid_offset
);
180 make_text_section(const std::vector
<char> &code
) {
181 const pipe_llvm_program_header header
{ uint32_t(code
.size()) };
182 module::section text
{ 0, module::section::text_executable
,
183 header
.num_bytes
, {} };
185 text
.data
.insert(text
.data
.end(), reinterpret_cast<const char *>(&header
),
186 reinterpret_cast<const char *>(&header
) + sizeof(header
));
187 text
.data
.insert(text
.data
.end(), code
.begin(), code
.end());
194 clover::llvm::build_module_common(const Module
&mod
,
195 const std::vector
<char> &code
,
196 const std::map
<std::string
,
198 const clang::CompilerInstance
&c
) {
201 for (const auto &name
: map(std::mem_fn(&Function::getName
),
203 if (offsets
.count(name
))
204 m
.syms
.emplace_back(name
, 0, offsets
.at(name
),
205 make_kernel_args(mod
, name
, c
));
208 m
.secs
.push_back(make_text_section(code
));