1 /**************************************************************************
2  *
3  * Copyright 2010 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  **************************************************************************/
27 
28 
29 #include "util/u_debug.h"
30 
31 #include "lp_bld_type.h"
32 #include "lp_bld_debug.h"
33 #include "lp_bld_const.h"
34 #include "lp_bld_bitarit.h"
35 #include "lp_bld_intr.h"
36 
37 /**
38  * Return (a | b)
39  */
40 LLVMValueRef
lp_build_or(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)41 lp_build_or(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
42 {
43    LLVMBuilderRef builder = bld->gallivm->builder;
44    const struct lp_type type = bld->type;
45    LLVMValueRef res;
46 
47    assert(lp_check_value(type, a));
48    assert(lp_check_value(type, b));
49 
50    /* can't do bitwise ops on floating-point values */
51    if (type.floating) {
52       a = LLVMBuildBitCast(builder, a, bld->int_vec_type, "");
53       b = LLVMBuildBitCast(builder, b, bld->int_vec_type, "");
54    }
55 
56    res = LLVMBuildOr(builder, a, b, "");
57 
58    if (type.floating) {
59       res = LLVMBuildBitCast(builder, res, bld->vec_type, "");
60    }
61 
62    return res;
63 }
64 
65 /* bitwise XOR (a ^ b) */
66 LLVMValueRef
lp_build_xor(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)67 lp_build_xor(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
68 {
69    LLVMBuilderRef builder = bld->gallivm->builder;
70    const struct lp_type type = bld->type;
71    LLVMValueRef res;
72 
73    assert(lp_check_value(type, a));
74    assert(lp_check_value(type, b));
75 
76    /* can't do bitwise ops on floating-point values */
77    if (type.floating) {
78       a = LLVMBuildBitCast(builder, a, bld->int_vec_type, "");
79       b = LLVMBuildBitCast(builder, b, bld->int_vec_type, "");
80    }
81 
82    res = LLVMBuildXor(builder, a, b, "");
83 
84    if (type.floating) {
85       res = LLVMBuildBitCast(builder, res, bld->vec_type, "");
86    }
87 
88    return res;
89 }
90 
91 /**
92  * Return (a & b)
93  */
94 LLVMValueRef
lp_build_and(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)95 lp_build_and(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
96 {
97    LLVMBuilderRef builder = bld->gallivm->builder;
98    const struct lp_type type = bld->type;
99    LLVMValueRef res;
100 
101    assert(lp_check_value(type, a));
102    assert(lp_check_value(type, b));
103 
104    /* can't do bitwise ops on floating-point values */
105    if (type.floating) {
106       a = LLVMBuildBitCast(builder, a, bld->int_vec_type, "");
107       b = LLVMBuildBitCast(builder, b, bld->int_vec_type, "");
108    }
109 
110    res = LLVMBuildAnd(builder, a, b, "");
111 
112    if (type.floating) {
113       res = LLVMBuildBitCast(builder, res, bld->vec_type, "");
114    }
115 
116    return res;
117 }
118 
119 
120 /**
121  * Return (a & ~b)
122  */
123 LLVMValueRef
lp_build_andnot(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)124 lp_build_andnot(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
125 {
126    LLVMBuilderRef builder = bld->gallivm->builder;
127    const struct lp_type type = bld->type;
128    LLVMValueRef res;
129 
130    assert(lp_check_value(type, a));
131    assert(lp_check_value(type, b));
132 
133    /* can't do bitwise ops on floating-point values */
134    if (type.floating) {
135       a = LLVMBuildBitCast(builder, a, bld->int_vec_type, "");
136       b = LLVMBuildBitCast(builder, b, bld->int_vec_type, "");
137    }
138 
139    res = LLVMBuildNot(builder, b, "");
140    res = LLVMBuildAnd(builder, a, res, "");
141 
142    if (type.floating) {
143       res = LLVMBuildBitCast(builder, res, bld->vec_type, "");
144    }
145 
146    return res;
147 }
148 
149 /* bitwise NOT */
150 LLVMValueRef
lp_build_not(struct lp_build_context * bld,LLVMValueRef a)151 lp_build_not(struct lp_build_context *bld, LLVMValueRef a)
152 {
153    LLVMBuilderRef builder = bld->gallivm->builder;
154    const struct lp_type type = bld->type;
155    LLVMValueRef res;
156 
157    assert(lp_check_value(type, a));
158 
159    if (type.floating) {
160       a = LLVMBuildBitCast(builder, a, bld->int_vec_type, "");
161    }
162    res = LLVMBuildNot(builder, a, "");
163    if (type.floating) {
164       res = LLVMBuildBitCast(builder, res, bld->vec_type, "");
165    }
166    return res;
167 }
168 
169 /**
170  * Shift left.
171  * Result is undefined if the shift count is not smaller than the type width.
172  */
173 LLVMValueRef
lp_build_shl(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)174 lp_build_shl(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
175 {
176    LLVMBuilderRef builder = bld->gallivm->builder;
177    const struct lp_type type = bld->type;
178    LLVMValueRef res;
179 
180    assert(!type.floating);
181 
182    assert(lp_check_value(type, a));
183    assert(lp_check_value(type, b));
184 
185    (void)type;
186 
187    res = LLVMBuildShl(builder, a, b, "");
188 
189    return res;
190 }
191 
192 
193 /**
194  * Shift right.
195  * Result is undefined if the shift count is not smaller than the type width.
196  */
197 LLVMValueRef
lp_build_shr(struct lp_build_context * bld,LLVMValueRef a,LLVMValueRef b)198 lp_build_shr(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b)
199 {
200    LLVMBuilderRef builder = bld->gallivm->builder;
201    const struct lp_type type = bld->type;
202    LLVMValueRef res;
203 
204    assert(!type.floating);
205 
206    assert(lp_check_value(type, a));
207    assert(lp_check_value(type, b));
208 
209    if (type.sign) {
210       res = LLVMBuildAShr(builder, a, b, "");
211    } else {
212       res = LLVMBuildLShr(builder, a, b, "");
213    }
214 
215    return res;
216 }
217 
218 
219 /**
220  * Shift left with immediate.
221  * The immediate shift count must be smaller than the type width.
222  */
223 LLVMValueRef
lp_build_shl_imm(struct lp_build_context * bld,LLVMValueRef a,unsigned imm)224 lp_build_shl_imm(struct lp_build_context *bld, LLVMValueRef a, unsigned imm)
225 {
226    LLVMValueRef b = lp_build_const_int_vec(bld->gallivm, bld->type, imm);
227    assert(imm < bld->type.width);
228    return lp_build_shl(bld, a, b);
229 }
230 
231 
232 /**
233  * Shift right with immediate.
234  * The immediate shift count must be smaller than the type width.
235  */
236 LLVMValueRef
lp_build_shr_imm(struct lp_build_context * bld,LLVMValueRef a,unsigned imm)237 lp_build_shr_imm(struct lp_build_context *bld, LLVMValueRef a, unsigned imm)
238 {
239    LLVMValueRef b = lp_build_const_int_vec(bld->gallivm, bld->type, imm);
240    assert(imm < bld->type.width);
241    return lp_build_shr(bld, a, b);
242 }
243 
244 LLVMValueRef
lp_build_popcount(struct lp_build_context * bld,LLVMValueRef a)245 lp_build_popcount(struct lp_build_context *bld, LLVMValueRef a)
246 {
247    LLVMBuilderRef builder = bld->gallivm->builder;
248    LLVMValueRef result;
249    char intr_str[256];
250 
251    lp_format_intrinsic(intr_str, sizeof(intr_str), "llvm.ctpop", bld->vec_type);
252    result = lp_build_intrinsic_unary(builder, intr_str, bld->vec_type, a);
253    return result;
254 }
255 
256 LLVMValueRef
lp_build_bitfield_reverse(struct lp_build_context * bld,LLVMValueRef a)257 lp_build_bitfield_reverse(struct lp_build_context *bld, LLVMValueRef a)
258 {
259    LLVMBuilderRef builder = bld->gallivm->builder;
260    LLVMValueRef result;
261    char intr_str[256];
262 
263    lp_format_intrinsic(intr_str, sizeof(intr_str), "llvm.bitreverse", bld->vec_type);
264    result = lp_build_intrinsic_unary(builder, intr_str, bld->vec_type, a);
265    return result;
266 }
267 
268 LLVMValueRef
lp_build_cttz(struct lp_build_context * bld,LLVMValueRef a)269 lp_build_cttz(struct lp_build_context *bld, LLVMValueRef a)
270 {
271    LLVMBuilderRef builder = bld->gallivm->builder;
272    LLVMValueRef result;
273    char intr_str[256];
274 
275    lp_format_intrinsic(intr_str, sizeof(intr_str), "llvm.cttz", bld->vec_type);
276 
277    LLVMValueRef undef_val = LLVMConstNull(LLVMInt1TypeInContext(bld->gallivm->context));
278    result = lp_build_intrinsic_binary(builder, intr_str, bld->vec_type, a, undef_val);
279    return LLVMBuildSelect(builder, LLVMBuildICmp(builder, LLVMIntEQ, a, bld->zero, ""),
280 			  lp_build_const_int_vec(bld->gallivm, bld->type, -1), result, "");
281 }
282 
283 LLVMValueRef
lp_build_ctlz(struct lp_build_context * bld,LLVMValueRef a)284 lp_build_ctlz(struct lp_build_context *bld, LLVMValueRef a)
285 {
286    LLVMBuilderRef builder = bld->gallivm->builder;
287    LLVMValueRef result;
288    char intr_str[256];
289 
290    lp_format_intrinsic(intr_str, sizeof(intr_str), "llvm.ctlz", bld->vec_type);
291 
292    LLVMValueRef undef_val = LLVMConstNull(LLVMInt1TypeInContext(bld->gallivm->context));
293    result = lp_build_intrinsic_binary(builder, intr_str, bld->vec_type, a, undef_val);
294    return result;
295 }
296