2 * Copyright © 2019 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #ifndef GEN_MI_BUILDER_H
25 #define GEN_MI_BUILDER_H
27 #include "util/bitscan.h"
28 #include "util/fast_idiv_by_const.h"
29 #include "util/u_math.h"
31 #ifndef GEN_MI_BUILDER_NUM_ALLOC_GPRS
32 /** The number of GPRs the MI builder is allowed to allocate
34 * This may be set by a user of this API so that it can reserve some GPRs at
35 * the top end for its own use.
37 #define GEN_MI_BUILDER_NUM_ALLOC_GPRS 16
40 /** These must be defined by the user of the builder
42 * void *__gen_get_batch_dwords(__gen_user_data *user_data,
43 * unsigned num_dwords);
46 * __gen_address_offset(__gen_address_type addr, uint64_t offset);
51 * Start of the actual MI builder
54 #define __genxml_cmd_length(cmd) cmd ## _length
55 #define __genxml_cmd_header(cmd) cmd ## _header
56 #define __genxml_cmd_pack(cmd) cmd ## _pack
58 #define gen_mi_builder_pack(b, cmd, dst, name) \
59 for (struct cmd name = { __genxml_cmd_header(cmd) }, \
60 *_dst = (struct cmd *)(dst); __builtin_expect(_dst != NULL, 1); \
61 __genxml_cmd_pack(cmd)((b)->user_data, (void *)_dst, &name), \
64 #define gen_mi_builder_emit(b, cmd, name) \
65 gen_mi_builder_pack((b), cmd, __gen_get_batch_dwords((b)->user_data, __genxml_cmd_length(cmd)), name)
68 enum gen_mi_value_type
{
69 GEN_MI_VALUE_TYPE_IMM
,
70 GEN_MI_VALUE_TYPE_MEM32
,
71 GEN_MI_VALUE_TYPE_MEM64
,
72 GEN_MI_VALUE_TYPE_REG32
,
73 GEN_MI_VALUE_TYPE_REG64
,
77 enum gen_mi_value_type type
;
81 __gen_address_type addr
;
85 #if GEN_GEN >= 7 || GEN_IS_HASWELL
91 #define GEN_MI_BUILDER_MAX_MATH_DWORDS 256
93 #define GEN_MI_BUILDER_MAX_MATH_DWORDS 64
96 struct gen_mi_builder
{
97 __gen_user_data
*user_data
;
99 #if GEN_GEN >= 8 || GEN_IS_HASWELL
101 uint8_t gpr_refs
[GEN_MI_BUILDER_NUM_ALLOC_GPRS
];
103 unsigned num_math_dwords
;
104 uint32_t math_dwords
[GEN_MI_BUILDER_MAX_MATH_DWORDS
];
109 gen_mi_builder_init(struct gen_mi_builder
*b
, __gen_user_data
*user_data
)
111 memset(b
, 0, sizeof(*b
));
112 b
->user_data
= user_data
;
114 #if GEN_GEN >= 8 || GEN_IS_HASWELL
116 b
->num_math_dwords
= 0;
121 gen_mi_builder_flush_math(struct gen_mi_builder
*b
)
123 #if GEN_GEN >= 8 || GEN_IS_HASWELL
124 if (b
->num_math_dwords
== 0)
127 uint32_t *dw
= (uint32_t *)__gen_get_batch_dwords(b
->user_data
,
128 1 + b
->num_math_dwords
);
129 gen_mi_builder_pack(b
, GENX(MI_MATH
), dw
, math
) {
130 math
.DWordLength
= 1 + b
->num_math_dwords
- GENX(MI_MATH_length_bias
);
132 memcpy(dw
+ 1, b
->math_dwords
, b
->num_math_dwords
* sizeof(uint32_t));
133 b
->num_math_dwords
= 0;
137 #define _GEN_MI_BUILDER_GPR_BASE 0x2600
138 /* The actual hardware limit on GPRs */
139 #define _GEN_MI_BUILDER_NUM_HW_GPRS 16
141 #if GEN_GEN >= 8 || GEN_IS_HASWELL
144 gen_mi_value_is_gpr(struct gen_mi_value val
)
146 return (val
.type
== GEN_MI_VALUE_TYPE_REG32
||
147 val
.type
== GEN_MI_VALUE_TYPE_REG64
) &&
148 val
.reg
>= _GEN_MI_BUILDER_GPR_BASE
&&
149 val
.reg
< _GEN_MI_BUILDER_GPR_BASE
+
150 _GEN_MI_BUILDER_NUM_HW_GPRS
* 8;
154 _gen_mi_value_is_allocated_gpr(struct gen_mi_value val
)
156 return (val
.type
== GEN_MI_VALUE_TYPE_REG32
||
157 val
.type
== GEN_MI_VALUE_TYPE_REG64
) &&
158 val
.reg
>= _GEN_MI_BUILDER_GPR_BASE
&&
159 val
.reg
< _GEN_MI_BUILDER_GPR_BASE
+
160 GEN_MI_BUILDER_NUM_ALLOC_GPRS
* 8;
163 static inline uint32_t
164 _gen_mi_value_as_gpr(struct gen_mi_value val
)
166 assert(gen_mi_value_is_gpr(val
));
167 assert(val
.reg
% 8 == 0);
168 return (val
.reg
- _GEN_MI_BUILDER_GPR_BASE
) / 8;
171 static inline struct gen_mi_value
172 gen_mi_new_gpr(struct gen_mi_builder
*b
)
174 unsigned gpr
= ffs(~b
->gprs
) - 1;
175 assert(gpr
< GEN_MI_BUILDER_NUM_ALLOC_GPRS
);
176 assert(b
->gpr_refs
[gpr
] == 0);
177 b
->gprs
|= (1u << gpr
);
178 b
->gpr_refs
[gpr
] = 1;
180 return (struct gen_mi_value
) {
181 .type
= GEN_MI_VALUE_TYPE_REG64
,
182 .reg
= _GEN_MI_BUILDER_GPR_BASE
+ gpr
* 8,
185 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
187 /** Take a reference to a gen_mi_value
189 * The MI builder uses reference counting to automatically free ALU GPRs for
190 * re-use in calculations. All gen_mi_* math functions consume the reference
191 * they are handed for each source and return a reference to a value which the
192 * caller must consume. In particular, if you pas the same value into a
193 * single gen_mi_* math function twice (say to add a number to itself), you
194 * are responsible for calling gen_mi_value_ref() to get a second reference
195 * because the gen_mi_* math function will consume it twice.
197 static inline struct gen_mi_value
198 gen_mi_value_ref(struct gen_mi_builder
*b
, struct gen_mi_value val
)
200 #if GEN_GEN >= 8 || GEN_IS_HASWELL
201 if (_gen_mi_value_is_allocated_gpr(val
)) {
202 unsigned gpr
= _gen_mi_value_as_gpr(val
);
203 assert(gpr
< GEN_MI_BUILDER_NUM_ALLOC_GPRS
);
204 assert(b
->gprs
& (1u << gpr
));
205 assert(b
->gpr_refs
[gpr
] < UINT8_MAX
);
208 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
213 /** Drop a reference to a gen_mi_value
215 * See also gen_mi_value_ref.
218 gen_mi_value_unref(struct gen_mi_builder
*b
, struct gen_mi_value val
)
220 #if GEN_GEN >= 8 || GEN_IS_HASWELL
221 if (_gen_mi_value_is_allocated_gpr(val
)) {
222 unsigned gpr
= _gen_mi_value_as_gpr(val
);
223 assert(gpr
< GEN_MI_BUILDER_NUM_ALLOC_GPRS
);
224 assert(b
->gprs
& (1u << gpr
));
225 assert(b
->gpr_refs
[gpr
] > 0);
226 if (--b
->gpr_refs
[gpr
] == 0)
227 b
->gprs
&= ~(1u << gpr
);
229 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
232 static inline struct gen_mi_value
233 gen_mi_imm(uint64_t imm
)
235 return (struct gen_mi_value
) {
236 .type
= GEN_MI_VALUE_TYPE_IMM
,
241 static inline struct gen_mi_value
242 gen_mi_reg32(uint32_t reg
)
244 struct gen_mi_value val
= {
245 .type
= GEN_MI_VALUE_TYPE_REG32
,
248 #if GEN_GEN >= 8 || GEN_IS_HASWELL
249 assert(!_gen_mi_value_is_allocated_gpr(val
));
254 static inline struct gen_mi_value
255 gen_mi_reg64(uint32_t reg
)
257 struct gen_mi_value val
= {
258 .type
= GEN_MI_VALUE_TYPE_REG64
,
261 #if GEN_GEN >= 8 || GEN_IS_HASWELL
262 assert(!_gen_mi_value_is_allocated_gpr(val
));
267 static inline struct gen_mi_value
268 gen_mi_mem32(__gen_address_type addr
)
270 return (struct gen_mi_value
) {
271 .type
= GEN_MI_VALUE_TYPE_MEM32
,
276 static inline struct gen_mi_value
277 gen_mi_mem64(__gen_address_type addr
)
279 return (struct gen_mi_value
) {
280 .type
= GEN_MI_VALUE_TYPE_MEM64
,
285 static inline struct gen_mi_value
286 gen_mi_value_half(struct gen_mi_value value
, bool top_32_bits
)
288 switch (value
.type
) {
289 case GEN_MI_VALUE_TYPE_IMM
:
293 value
.imm
&= 0xffffffffu
;
296 case GEN_MI_VALUE_TYPE_MEM32
:
297 assert(!top_32_bits
);
300 case GEN_MI_VALUE_TYPE_MEM64
:
302 value
.addr
= __gen_address_offset(value
.addr
, 4);
303 value
.type
= GEN_MI_VALUE_TYPE_MEM32
;
306 case GEN_MI_VALUE_TYPE_REG32
:
307 assert(!top_32_bits
);
310 case GEN_MI_VALUE_TYPE_REG64
:
313 value
.type
= GEN_MI_VALUE_TYPE_REG32
;
317 unreachable("Invalid gen_mi_value type");
321 _gen_mi_copy_no_unref(struct gen_mi_builder
*b
,
322 struct gen_mi_value dst
, struct gen_mi_value src
)
324 #if GEN_GEN >= 7 || GEN_IS_HASWELL
325 /* TODO: We could handle src.invert by emitting a bit of math if we really
328 assert(!dst
.invert
&& !src
.invert
);
330 gen_mi_builder_flush_math(b
);
333 case GEN_MI_VALUE_TYPE_IMM
:
334 unreachable("Cannot copy to an immediate");
336 case GEN_MI_VALUE_TYPE_MEM64
:
337 case GEN_MI_VALUE_TYPE_REG64
:
338 /* If the destination is 64 bits, we have to copy in two halves */
339 _gen_mi_copy_no_unref(b
, gen_mi_value_half(dst
, false),
340 gen_mi_value_half(src
, false));
342 case GEN_MI_VALUE_TYPE_IMM
:
343 case GEN_MI_VALUE_TYPE_MEM64
:
344 case GEN_MI_VALUE_TYPE_REG64
:
345 /* TODO: Use MI_STORE_DATA_IMM::StoreQWord when we have it */
346 _gen_mi_copy_no_unref(b
, gen_mi_value_half(dst
, true),
347 gen_mi_value_half(src
, true));
350 _gen_mi_copy_no_unref(b
, gen_mi_value_half(dst
, true),
356 case GEN_MI_VALUE_TYPE_MEM32
:
358 case GEN_MI_VALUE_TYPE_IMM
:
359 gen_mi_builder_emit(b
, GENX(MI_STORE_DATA_IMM
), sdi
) {
360 sdi
.Address
= dst
.addr
;
362 sdi
.ForceWriteCompletionCheck
= true;
364 sdi
.ImmediateData
= src
.imm
;
368 case GEN_MI_VALUE_TYPE_MEM32
:
369 case GEN_MI_VALUE_TYPE_MEM64
:
371 gen_mi_builder_emit(b
, GENX(MI_COPY_MEM_MEM
), cmm
) {
372 cmm
.DestinationMemoryAddress
= dst
.addr
;
373 cmm
.SourceMemoryAddress
= src
.addr
;
377 struct gen_mi_value tmp
= gen_mi_new_gpr(b
);
378 _gen_mi_copy_no_unref(b
, tmp
, src
);
379 _gen_mi_copy_no_unref(b
, dst
, tmp
);
380 gen_mi_value_unref(b
, tmp
);
383 unreachable("Cannot do mem <-> mem copy on IVB and earlier");
387 case GEN_MI_VALUE_TYPE_REG32
:
388 case GEN_MI_VALUE_TYPE_REG64
:
389 gen_mi_builder_emit(b
, GENX(MI_STORE_REGISTER_MEM
), srm
) {
390 srm
.RegisterAddress
= src
.reg
;
391 srm
.MemoryAddress
= dst
.addr
;
396 unreachable("Invalid gen_mi_value type");
400 case GEN_MI_VALUE_TYPE_REG32
:
402 case GEN_MI_VALUE_TYPE_IMM
:
403 gen_mi_builder_emit(b
, GENX(MI_LOAD_REGISTER_IMM
), lri
) {
404 lri
.RegisterOffset
= dst
.reg
;
405 lri
.DataDWord
= src
.imm
;
409 case GEN_MI_VALUE_TYPE_MEM32
:
410 case GEN_MI_VALUE_TYPE_MEM64
:
411 gen_mi_builder_emit(b
, GENX(MI_LOAD_REGISTER_MEM
), lrm
) {
412 lrm
.RegisterAddress
= dst
.reg
;
413 lrm
.MemoryAddress
= src
.addr
;
417 case GEN_MI_VALUE_TYPE_REG32
:
418 case GEN_MI_VALUE_TYPE_REG64
:
419 #if GEN_GEN >= 8 || GEN_IS_HASWELL
420 if (src
.reg
!= dst
.reg
) {
421 gen_mi_builder_emit(b
, GENX(MI_LOAD_REGISTER_REG
), lrr
) {
422 lrr
.SourceRegisterAddress
= src
.reg
;
423 lrr
.DestinationRegisterAddress
= dst
.reg
;
427 unreachable("Cannot do reg <-> reg copy on IVB and earlier");
432 unreachable("Invalid gen_mi_value type");
437 unreachable("Invalid gen_mi_value type");
441 /** Store the value in src to the value represented by dst
443 * If the bit size of src and dst mismatch, this function does an unsigned
444 * integer cast. If src has more bits than dst, it takes the bottom bits. If
445 * src has fewer bits then dst, it fills the top bits with zeros.
447 * This function consumes one reference for each of src and dst.
450 gen_mi_store(struct gen_mi_builder
*b
,
451 struct gen_mi_value dst
, struct gen_mi_value src
)
453 _gen_mi_copy_no_unref(b
, dst
, src
);
454 gen_mi_value_unref(b
, src
);
455 gen_mi_value_unref(b
, dst
);
459 gen_mi_memset(struct gen_mi_builder
*b
, __gen_address_type dst
,
460 uint32_t value
, uint32_t size
)
462 #if GEN_GEN >= 8 || GEN_IS_HASWELL
463 assert(b
->num_math_dwords
== 0);
466 /* This memset operates in units of dwords. */
467 assert(size
% 4 == 0);
469 for (uint32_t i
= 0; i
< size
; i
+= 4) {
470 gen_mi_store(b
, gen_mi_mem32(__gen_address_offset(dst
, i
)),
475 /* NOTE: On IVB, this function stomps GEN7_3DPRIM_BASE_VERTEX */
477 gen_mi_memcpy(struct gen_mi_builder
*b
, __gen_address_type dst
,
478 __gen_address_type src
, uint32_t size
)
480 #if GEN_GEN >= 8 || GEN_IS_HASWELL
481 assert(b
->num_math_dwords
== 0);
484 /* This memcpy operates in units of dwords. */
485 assert(size
% 4 == 0);
487 for (uint32_t i
= 0; i
< size
; i
+= 4) {
488 struct gen_mi_value dst_val
= gen_mi_mem32(__gen_address_offset(dst
, i
));
489 struct gen_mi_value src_val
= gen_mi_mem32(__gen_address_offset(src
, i
));
490 #if GEN_GEN >= 8 || GEN_IS_HASWELL
491 gen_mi_store(b
, dst_val
, src_val
);
493 /* IVB does not have a general purpose register for command streamer
494 * commands. Therefore, we use an alternate temporary register.
496 struct gen_mi_value tmp_reg
= gen_mi_reg32(0x2440); /* GEN7_3DPRIM_BASE_VERTEX */
497 gen_mi_store(b
, tmp_reg
, src_val
);
498 gen_mi_store(b
, dst_val
, tmp_reg
);
504 * MI_MATH Section. Only available on Haswell+
507 #if GEN_GEN >= 8 || GEN_IS_HASWELL
510 * Perform a predicated store (assuming the condition is already loaded
511 * in the MI_PREDICATE_RESULT register) of the value in src to the memory
512 * location specified by dst. Non-memory destinations are not supported.
514 * This function consumes one reference for each of src and dst.
517 gen_mi_store_if(struct gen_mi_builder
*b
,
518 struct gen_mi_value dst
,
519 struct gen_mi_value src
)
521 assert(!dst
.invert
&& !src
.invert
);
523 gen_mi_builder_flush_math(b
);
525 /* We can only predicate MI_STORE_REGISTER_MEM, so restrict the
526 * destination to be memory, and resolve the source to a temporary
527 * register if it isn't in one already.
529 assert(dst
.type
== GEN_MI_VALUE_TYPE_MEM64
||
530 dst
.type
== GEN_MI_VALUE_TYPE_MEM32
);
532 if (src
.type
!= GEN_MI_VALUE_TYPE_REG32
&&
533 src
.type
!= GEN_MI_VALUE_TYPE_REG64
) {
534 struct gen_mi_value tmp
= gen_mi_new_gpr(b
);
535 _gen_mi_copy_no_unref(b
, tmp
, src
);
539 if (dst
.type
== GEN_MI_VALUE_TYPE_MEM64
) {
540 gen_mi_builder_emit(b
, GENX(MI_STORE_REGISTER_MEM
), srm
) {
541 srm
.RegisterAddress
= src
.reg
;
542 srm
.MemoryAddress
= dst
.addr
;
543 srm
.PredicateEnable
= true;
545 gen_mi_builder_emit(b
, GENX(MI_STORE_REGISTER_MEM
), srm
) {
546 srm
.RegisterAddress
= src
.reg
+ 4;
547 srm
.MemoryAddress
= __gen_address_offset(dst
.addr
, 4);
548 srm
.PredicateEnable
= true;
551 gen_mi_builder_emit(b
, GENX(MI_STORE_REGISTER_MEM
), srm
) {
552 srm
.RegisterAddress
= src
.reg
;
553 srm
.MemoryAddress
= dst
.addr
;
554 srm
.PredicateEnable
= true;
558 gen_mi_value_unref(b
, src
);
559 gen_mi_value_unref(b
, dst
);
563 _gen_mi_builder_push_math(struct gen_mi_builder
*b
,
564 const uint32_t *dwords
,
567 assert(num_dwords
< GEN_MI_BUILDER_MAX_MATH_DWORDS
);
568 if (b
->num_math_dwords
+ num_dwords
> GEN_MI_BUILDER_MAX_MATH_DWORDS
)
569 gen_mi_builder_flush_math(b
);
571 memcpy(&b
->math_dwords
[b
->num_math_dwords
],
572 dwords
, num_dwords
* sizeof(*dwords
));
573 b
->num_math_dwords
+= num_dwords
;
576 static inline uint32_t
577 _gen_mi_pack_alu(uint32_t opcode
, uint32_t operand1
, uint32_t operand2
)
579 struct GENX(MI_MATH_ALU_INSTRUCTION
) instr
= {
580 .Operand2
= operand2
,
581 .Operand1
= operand1
,
586 GENX(MI_MATH_ALU_INSTRUCTION_pack
)(NULL
, &dw
, &instr
);
591 static inline struct gen_mi_value
592 gen_mi_value_to_gpr(struct gen_mi_builder
*b
, struct gen_mi_value val
)
594 if (gen_mi_value_is_gpr(val
))
597 /* Save off the invert flag because it makes copy() grumpy */
598 bool invert
= val
.invert
;
601 struct gen_mi_value tmp
= gen_mi_new_gpr(b
);
602 _gen_mi_copy_no_unref(b
, tmp
, val
);
608 static inline uint32_t
609 _gen_mi_math_load_src(struct gen_mi_builder
*b
,
610 unsigned src
, struct gen_mi_value
*val
)
612 if (val
->type
== GEN_MI_VALUE_TYPE_IMM
&&
613 (val
->imm
== 0 || val
->imm
== UINT64_MAX
)) {
614 uint64_t imm
= val
->invert
? ~val
->imm
: val
->imm
;
615 return _gen_mi_pack_alu(imm
? MI_ALU_LOAD1
: MI_ALU_LOAD0
, src
, 0);
617 *val
= gen_mi_value_to_gpr(b
, *val
);
618 return _gen_mi_pack_alu(val
->invert
? MI_ALU_LOADINV
: MI_ALU_LOAD
,
619 src
, _gen_mi_value_as_gpr(*val
));
623 static inline struct gen_mi_value
624 gen_mi_math_binop(struct gen_mi_builder
*b
, uint32_t opcode
,
625 struct gen_mi_value src0
, struct gen_mi_value src1
,
626 uint32_t store_op
, uint32_t store_src
)
628 struct gen_mi_value dst
= gen_mi_new_gpr(b
);
631 dw
[0] = _gen_mi_math_load_src(b
, MI_ALU_SRCA
, &src0
);
632 dw
[1] = _gen_mi_math_load_src(b
, MI_ALU_SRCB
, &src1
);
633 dw
[2] = _gen_mi_pack_alu(opcode
, 0, 0);
634 dw
[3] = _gen_mi_pack_alu(store_op
, _gen_mi_value_as_gpr(dst
), store_src
);
635 _gen_mi_builder_push_math(b
, dw
, 4);
637 gen_mi_value_unref(b
, src0
);
638 gen_mi_value_unref(b
, src1
);
643 static inline struct gen_mi_value
644 gen_mi_inot(struct gen_mi_builder
*b
, struct gen_mi_value val
)
646 /* TODO These currently can't be passed into gen_mi_copy */
647 val
.invert
= !val
.invert
;
651 static inline struct gen_mi_value
652 gen_mi_iadd(struct gen_mi_builder
*b
,
653 struct gen_mi_value src0
, struct gen_mi_value src1
)
655 return gen_mi_math_binop(b
, MI_ALU_ADD
, src0
, src1
,
656 MI_ALU_STORE
, MI_ALU_ACCU
);
659 static inline struct gen_mi_value
660 gen_mi_iadd_imm(struct gen_mi_builder
*b
,
661 struct gen_mi_value src
, uint64_t N
)
666 return gen_mi_iadd(b
, src
, gen_mi_imm(N
));
669 static inline struct gen_mi_value
670 gen_mi_isub(struct gen_mi_builder
*b
,
671 struct gen_mi_value src0
, struct gen_mi_value src1
)
673 return gen_mi_math_binop(b
, MI_ALU_SUB
, src0
, src1
,
674 MI_ALU_STORE
, MI_ALU_ACCU
);
677 static inline struct gen_mi_value
678 gen_mi_ult(struct gen_mi_builder
*b
,
679 struct gen_mi_value src0
, struct gen_mi_value src1
)
681 /* Compute "less than" by subtracting and storing the carry bit */
682 return gen_mi_math_binop(b
, MI_ALU_SUB
, src0
, src1
,
683 MI_ALU_STORE
, MI_ALU_CF
);
686 static inline struct gen_mi_value
687 gen_mi_uge(struct gen_mi_builder
*b
,
688 struct gen_mi_value src0
, struct gen_mi_value src1
)
690 /* Compute "less than" by subtracting and storing the carry bit */
691 return gen_mi_math_binop(b
, MI_ALU_SUB
, src0
, src1
,
692 MI_ALU_STOREINV
, MI_ALU_CF
);
695 static inline struct gen_mi_value
696 gen_mi_iand(struct gen_mi_builder
*b
,
697 struct gen_mi_value src0
, struct gen_mi_value src1
)
699 return gen_mi_math_binop(b
, MI_ALU_AND
, src0
, src1
,
700 MI_ALU_STORE
, MI_ALU_ACCU
);
704 * Returns (src != 0) ? 1 : 0.
706 static inline struct gen_mi_value
707 gen_mi_nz(struct gen_mi_builder
*b
, struct gen_mi_value src
)
709 return gen_mi_math_binop(b
, MI_ALU_ADD
, src
, gen_mi_imm(0),
710 MI_ALU_STOREINV
, MI_ALU_ZF
);
714 * Returns (src == 0) ? 1 : 0.
716 static inline struct gen_mi_value
717 gen_mi_z(struct gen_mi_builder
*b
, struct gen_mi_value src
)
719 return gen_mi_math_binop(b
, MI_ALU_ADD
, src
, gen_mi_imm(0),
720 MI_ALU_STORE
, MI_ALU_ZF
);
723 static inline struct gen_mi_value
724 gen_mi_ior(struct gen_mi_builder
*b
,
725 struct gen_mi_value src0
, struct gen_mi_value src1
)
727 return gen_mi_math_binop(b
, MI_ALU_OR
, src0
, src1
,
728 MI_ALU_STORE
, MI_ALU_ACCU
);
731 static inline struct gen_mi_value
732 gen_mi_imul_imm(struct gen_mi_builder
*b
,
733 struct gen_mi_value src
, uint32_t N
)
736 gen_mi_value_unref(b
, src
);
737 return gen_mi_imm(0);
743 src
= gen_mi_value_to_gpr(b
, src
);
745 struct gen_mi_value res
= gen_mi_value_ref(b
, src
);
747 unsigned top_bit
= 31 - __builtin_clz(N
);
748 for (int i
= top_bit
- 1; i
>= 0; i
--) {
749 res
= gen_mi_iadd(b
, res
, gen_mi_value_ref(b
, res
));
751 res
= gen_mi_iadd(b
, res
, gen_mi_value_ref(b
, src
));
754 gen_mi_value_unref(b
, src
);
759 static inline struct gen_mi_value
760 gen_mi_ishl_imm(struct gen_mi_builder
*b
,
761 struct gen_mi_value src
, uint32_t shift
)
763 struct gen_mi_value res
= gen_mi_value_to_gpr(b
, src
);
765 for (unsigned i
= 0; i
< shift
; i
++)
766 res
= gen_mi_iadd(b
, res
, gen_mi_value_ref(b
, res
));
771 static inline struct gen_mi_value
772 gen_mi_ushr32_imm(struct gen_mi_builder
*b
,
773 struct gen_mi_value src
, uint32_t shift
)
775 /* We right-shift by left-shifting by 32 - shift and taking the top 32 bits
776 * of the result. This assumes the top 32 bits are zero.
779 return gen_mi_imm(0);
782 struct gen_mi_value tmp
= gen_mi_new_gpr(b
);
783 _gen_mi_copy_no_unref(b
, gen_mi_value_half(tmp
, false),
784 gen_mi_value_half(src
, true));
785 _gen_mi_copy_no_unref(b
, gen_mi_value_half(tmp
, true), gen_mi_imm(0));
786 gen_mi_value_unref(b
, src
);
791 struct gen_mi_value tmp
= gen_mi_ishl_imm(b
, src
, 32 - shift
);
792 struct gen_mi_value dst
= gen_mi_new_gpr(b
);
793 _gen_mi_copy_no_unref(b
, gen_mi_value_half(dst
, false),
794 gen_mi_value_half(tmp
, true));
795 _gen_mi_copy_no_unref(b
, gen_mi_value_half(dst
, true), gen_mi_imm(0));
796 gen_mi_value_unref(b
, tmp
);
800 static inline struct gen_mi_value
801 gen_mi_udiv32_imm(struct gen_mi_builder
*b
,
802 struct gen_mi_value N
, uint32_t D
)
804 /* We implicitly assume that N is only a 32-bit value */
806 /* This is invalid but we should do something */
807 return gen_mi_imm(0);
808 } else if (util_is_power_of_two_or_zero(D
)) {
809 return gen_mi_ushr32_imm(b
, N
, util_logbase2(D
));
811 struct util_fast_udiv_info m
= util_compute_fast_udiv_info(D
, 32, 32);
812 assert(m
.multiplier
<= UINT32_MAX
);
815 N
= gen_mi_ushr32_imm(b
, N
, m
.pre_shift
);
817 /* Do the 32x32 multiply into gpr0 */
818 N
= gen_mi_imul_imm(b
, N
, m
.multiplier
);
821 N
= gen_mi_iadd(b
, N
, gen_mi_imm(m
.multiplier
));
823 N
= gen_mi_ushr32_imm(b
, N
, 32);
826 N
= gen_mi_ushr32_imm(b
, N
, m
.post_shift
);
832 #endif /* MI_MATH section */
834 #endif /* GEN_MI_BUILDER_H */