Branch data Line data Source code
1 : : //===-- abi_x86_64.cpp - x86_64 ABI description -----------------*- C++ -*-===//
2 : : //
3 : : // LDC – the LLVM D compiler
4 : : //
5 : : // This file is distributed under the BSD-style LDC license:
6 : : //
7 : : // Copyright (c) 2007-2012 LDC Team.
8 : : // All rights reserved.
9 : : //
10 : : // Redistribution and use in source and binary forms, with or without
11 : : // modification, are permitted provided that the following conditions are met:
12 : : //
13 : : // * Redistributions of source code must retain the above copyright notice,
14 : : // this list of conditions and the following disclaimer.
15 : : // * Redistributions in binary form must reproduce the above copyright notice,
16 : : // this list of conditions and the following disclaimer in the documentation
17 : : // and/or other materials provided with the distribution.
18 : : // * Neither the name of the LDC Team nor the names of its contributors may be
19 : : // used to endorse or promote products derived from this software without
20 : : // specific prior written permission.
21 : : //
22 : : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 : : // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 : : // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 : : // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 : : // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 : : // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 : : // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 : : // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 : : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 : : // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 : : //
33 : : //===----------------------------------------------------------------------===//
34 : : //
35 : : // The ABI implementation used for 64 bit x86 (i.e. x86_64/AMD64/x64) targets.
36 : : //
37 : : //===----------------------------------------------------------------------===//
38 : :
39 : : enum ArgClass { Integer, Sse, SseUp, X87, X87Up, ComplexX87, NoClass, Memory };
40 : :
41 : : struct ABI_x86_64Layout : AbiLayout {
42 : :
43 : : // used to track the state of the ABI generator during
44 : : // code generation
45 : : uint8_t int_regs, sse_regs;
46 : :
47 : 549095 : ABI_x86_64Layout()
48 : 549095 : : int_regs(6),
49 : 549095 : sse_regs(8)
50 : : {
51 : 549095 : }
52 : :
53 : 836426 : ABI_x86_64Layout(uint8_t int_regs, uint8_t sse_regs)
54 : 836426 : : int_regs(int_regs),
55 : 836426 : sse_regs(sse_regs)
56 : : {
57 : 836426 : }
58 : :
59 : : struct Classification {
60 : : bool isMemory;
61 : : ArgClass classes[2];
62 : :
63 : 1734920 : Classification() : isMemory(false)
64 : : {
65 : 1734920 : classes[0] = NoClass;
66 : 1734920 : classes[1] = NoClass;
67 : 1734920 : }
68 : :
69 : 1653450 : void addField(unsigned offset, ArgClass cl)
70 : : {
71 [ - + ]: 1653450 : if (isMemory)
72 : 0 : return;
73 : :
74 : : // Note that we don't need to bother checking if it crosses 8 bytes.
75 : : // We don't get here with unaligned fields, and anything that can be
76 : : // big enough to cross 8 bytes (cdoubles, reals, structs and arrays)
77 : : // is special-cased in classifyType()
78 : 1653450 : int idx = (offset < 8 ? 0 : 1);
79 : :
80 : 1653450 : ArgClass nw = merge(classes[idx], cl);
81 [ + + ]: 1653450 : if (nw != classes[idx]) {
82 : 1653250 : classes[idx] = nw;
83 : :
84 [ + + ]: 1653250 : if (nw == Memory) {
85 : 149 : classes[1-idx] = Memory;
86 : 149 : isMemory = true;
87 : : }
88 : : }
89 : : }
90 : :
91 : 1653450 : static ArgClass merge(ArgClass accum, ArgClass cl)
92 : : {
93 [ + + ]: 1653450 : if (accum == cl)
94 : 172 : return accum;
95 [ + + ]: 1653280 : if (accum == NoClass)
96 : 1653250 : return cl;
97 [ - + ]: 24 : if (cl == NoClass)
98 : 0 : return accum;
99 [ + - - + ]: 24 : if (accum == Memory || cl == Memory)
100 : 0 : return Memory;
101 [ - + - - ]: 24 : if (accum == Integer || cl == Integer)
102 : 24 : return Integer;
103 [ # # # # : 0 : if (accum == X87 || accum == X87Up || accum == ComplexX87 ||
# # # # ]
104 [ # # # # ]: 0 : cl == X87 || cl == X87Up || cl == ComplexX87)
105 : 0 : return Memory;
106 : 0 : return Sse;
107 : : }
108 : : };
109 : :
110 : : /*else if (ty == jl_float80_type) { //if this is ever added
111 : : accum.addField(offset, X87);
112 : : accum.addField(offset+8, X87Up);
113 : : } else if (ty->ty == jl_complex80_type) {
114 : : accum.addField(offset, ComplexX87);
115 : : // make sure other half knows about it too:
116 : : accum.addField(offset+16, ComplexX87);
117 : : } */
118 : 1737060 : void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) const
119 : : {
120 : : // Floating point types
121 [ + + + + ]: 1737060 : if (dt == jl_float64_type || dt == jl_float32_type) {
122 : 2262 : accum.addField(offset, Sse);
123 : : }
124 : : // Misc types
125 [ + + ]: 1734790 : else if (jl_is_cpointer_type((jl_value_t*)dt)) {
126 : 953516 : accum.addField(offset, Integer); // passed as a pointer
127 : : }
128 : : // Ghost
129 [ + + ]: 781277 : else if (jl_datatype_size(dt) == 0) {
130 : : }
131 : : // BitsTypes and not float, write as Integers
132 [ + + ]: 698729 : else if (jl_is_primitivetype(dt)) {
133 [ + + ]: 697518 : if (jl_datatype_size(dt) <= 8) {
134 : 697514 : accum.addField(offset, Integer);
135 : : }
136 [ + - ]: 4 : else if (jl_datatype_size(dt) <= 16) {
137 : : // Int128 or other 128bit wide INTEGER types
138 : 4 : accum.addField(offset, Integer);
139 : 4 : accum.addField(offset+8, Integer);
140 : : }
141 : : else {
142 : 0 : accum.addField(offset, Memory);
143 : : }
144 : : }
145 : : // struct types that map to SIMD registers
146 [ - + ]: 1211 : else if (is_native_simd_type(dt)) {
147 : 0 : accum.addField(offset, Sse);
148 : : }
149 : : // Other struct types
150 [ + + + - ]: 1211 : else if (jl_datatype_size(dt) <= 16 && dt->layout) {
151 : : size_t i;
152 [ + + ]: 3194 : for (i = 0; i < jl_datatype_nfields(dt); ++i) {
153 : 2132 : jl_value_t *ty = jl_field_type(dt, i);
154 [ + + ]: 2132 : if (jl_field_isptr(dt, i))
155 : 4 : ty = (jl_value_t*)jl_voidpointer_type;
156 : 2132 : classifyType(accum, (jl_datatype_t*)ty, offset + jl_field_offset(dt, i));
157 : 1062 : }
158 : : }
159 : : else {
160 : 149 : accum.addField(offset, Memory);
161 : : }
162 : 1737060 : }
163 : :
164 : 1734920 : Classification classify(jl_datatype_t *dt) const
165 : : {
166 : 1734920 : Classification cl;
167 : 1734920 : classifyType(cl, dt, 0);
168 : 1734920 : return cl;
169 : : }
170 : :
171 : 549095 : bool use_sret(jl_datatype_t *dt, LLVMContext &ctx) override
172 : : {
173 : 549095 : int sret = classify(dt).isMemory;
174 [ + + ]: 549095 : if (sret) {
175 [ - + ]: 106 : assert(this->int_regs > 0 && "No int regs available when determining sret-ness?");
176 : 106 : this->int_regs--;
177 : : }
178 : 549095 : return sret;
179 : : }
180 : :
181 : 836469 : bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *Ty) override
182 : : {
183 : 836469 : Classification cl = classify(dt);
184 [ + + ]: 836469 : if (cl.isMemory) {
185 : 43 : ab.addByValAttr(Ty);
186 : 43 : return true;
187 : : }
188 : :
189 : : // Figure out how many registers we want for this arg:
190 : 1672850 : ABI_x86_64Layout wanted(0, 0);
191 [ + + ]: 2509280 : for (int i = 0 ; i < 2; i++) {
192 [ + + ]: 1672850 : if (cl.classes[i] == Integer)
193 : 836179 : wanted.int_regs++;
194 [ + + ]: 836673 : else if (cl.classes[i] == Sse)
195 : 328 : wanted.sse_regs++;
196 : : }
197 : :
198 [ + + + + ]: 836426 : if (wanted.int_regs <= this->int_regs && wanted.sse_regs <= this->sse_regs) {
199 : 822862 : this->int_regs -= wanted.int_regs;
200 : 822862 : this->sse_regs -= wanted.sse_regs;
201 : : }
202 [ - + ]: 13564 : else if (jl_is_structtype(dt)) {
203 : : // spill to memory even though we would ordinarily pass
204 : : // it in registers
205 : 0 : ab.addByValAttr(Ty);
206 : 0 : return true;
207 : : }
208 : 836426 : return false;
209 : : }
210 : :
211 : : // Called on behalf of ccall to determine preferred LLVM representation
212 : : // for an argument or return value.
213 : 349359 : Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override
214 : : {
215 : : (void) isret;
216 : : // no need to rewrite these types (they are returned as pointers anyways)
217 [ - + ]: 349359 : if (is_native_simd_type(dt))
218 : 0 : return NULL;
219 : :
220 : 349359 : size_t size = jl_datatype_size(dt);
221 : 349359 : size_t nbits = jl_datatype_nbits(dt);
222 [ + - - + ]: 349359 : if (size > 16 || size == 0)
223 : 0 : return NULL;
224 : :
225 : 349359 : Classification cl = classify(dt);
226 [ - + ]: 349359 : if (cl.isMemory)
227 : 0 : return NULL;
228 : :
229 : : Type *types[2];
230 [ + + - ]: 349359 : switch (cl.classes[0]) {
231 : 348463 : case Integer:
232 [ + + ]: 348463 : if (size >= 8)
233 : 271877 : types[0] = Type::getInt64Ty(ctx);
234 : : else
235 : 76586 : types[0] = Type::getIntNTy(ctx, nbits);
236 : 348463 : break;
237 : 896 : case Sse:
238 [ + + ]: 896 : if (size <= 4)
239 : 162 : types[0] = Type::getFloatTy(ctx);
240 : : else
241 : 734 : types[0] = Type::getDoubleTy(ctx);
242 : 896 : break;
243 : 0 : default:
244 : 0 : assert(0 && "Unexpected cl.classes[0]");
245 : : }
246 [ + + + - ]: 349359 : switch (cl.classes[1]) {
247 : 348920 : case NoClass:
248 : 348920 : return types[0];
249 : 242 : case Integer:
250 [ - + ]: 242 : assert(size > 8);
251 : 242 : types[1] = Type::getIntNTy(ctx, (nbits-64));
252 : 242 : return StructType::get(ctx,ArrayRef<Type*>(&types[0],2));
253 : 197 : case Sse:
254 [ - + ]: 197 : if (size <= 12)
255 : 0 : types[1] = Type::getFloatTy(ctx);
256 : : else
257 : 197 : types[1] = Type::getDoubleTy(ctx);
258 : 197 : return StructType::get(ctx,ArrayRef<Type*>(&types[0],2));
259 : 0 : default:
260 : 0 : assert(0 && "Unexpected cl.classes[0]");
261 : : }
262 : : // Silence GCC
263 : : assert(0);
264 : : return NULL;
265 : : }
266 : :
267 : : };
|