summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/tgsi/tgsi_llvm.h
blob: b8377d1fec73d846c8d1df823d86d2f4848c55e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

#ifndef TGSI_LLVM_H
#define TGSI_LLVM_H

#include "gallivm/lp_bld_init.h"
#include "gallivm/lp_bld_tgsi.h"
#include "pipe/p_shader_tokens.h"

#define TGSI_LLVM_MAX_INPUTS 16 * 4
#define TGSI_LLVM_MAX_OUTPUTS 16 * 4
#define TGSI_LLVM_MAX_BRANCH_DEPTH 16
#define TGSI_LLVM_MAX_LOOP_DEPTH 16

struct tgsi_token;
struct tgsi_llvm_context;

struct tgsi_llvm_branch {
      LLVMBasicBlockRef endif_block;
      LLVMBasicBlockRef if_block;
      LLVMBasicBlockRef else_block;
      unsigned has_else;
};

struct tgsi_llvm_loop {
      LLVMBasicBlockRef loop_block;
      LLVMBasicBlockRef endloop_block;
};

struct tgsi_llvm_emit_data {
   /* Arguments that are passed to tgsi_llvm_opcode_action::emit.  The
    * order of the arguments should be as follows:
    * SOA: s0.x, s0.y, s0.z, s0.w, s1.x, s1.y, s1.z, s1.w, s2.x, s2.y, s2.x, s2.w
    * AOS: s0.xyzw, s1.xyzw, s2.xyzw
    * TEXTURE Instructions: coord.xyzw
    *
    * Arguments should be packed into the args array.  For example an SOA
    * instructions that reads s0.x and s1.x args should look like this:
    * args[0] = s0.x;
    * args[1] = s1.x;
    */
   LLVMValueRef args[12];
   unsigned arg_count;
   LLVMTypeRef dst_type;
   unsigned chan;

   /* These fields (inst and info) should be NULL if the
    * tgsi_llvm_opcode_action::emit is called without first calling the
    * tgsi_llvm_opcode_action::fetch_args function.
    * For example, if TGSI_OPCODE_MAD is implemented using a MUL
    * instruction and an ADD instruction, when the emit functions are
    * called for MUL and ADD inst and info should be NULL.
    */
   const struct tgsi_full_instruction * inst;
   const struct tgsi_opcode_info * info;
};

struct tgsi_llvm_opcode_action {
   void (*fetch_args)(struct tgsi_llvm_context *,
                      struct tgsi_llvm_emit_data *);

   LLVMValueRef (*emit)(const struct tgsi_llvm_opcode_action *,
                        struct tgsi_llvm_context *,
                        struct tgsi_llvm_emit_data *);

   const char * intr_name;
};


struct tgsi_llvm_context {

   /*=== Front end configuration ===*/

   /** Boolean value if set to non-zero tgsi_llvm will emit llvm code in vector
     * form.  If it is set to zero tgsi_llvm will emit scalar llvm * XXX: Vector code is not fully supported, if you set this to non-zero,
     * it won't work.  This should be set to zero. */
   unsigned aos;

   /* Special Intrinsics */

   /** Write to an output register: float store_output(float, i32) */
   const char * store_output_intr;

   /** Swizzle a vector value: <4 x float> swizzle(<4 x float>, i32)
    * The swizzle is an unsigned integer that encodes a TGSI_SWIZZLE_* value
    * in 2-bits.
    * Swizzle{0-1} = X Channel
    * Swizzle{2-3} = Y Channel
    * Swizzle{4-5} = Z Channel
    * Swizzle{6-7} = W Channel
    */
   const char * swizzle_intr;

   /** This array stores functions that are used to transform TGSI opcodes to
     * LLVM instructions.
     */
   struct tgsi_llvm_opcode_action op_actions[TGSI_OPCODE_LAST];

   /* Instructions that are not described by any of the TGSI opcodes. */

   /* The TGSI_OPCODE_RSQ is defined as 1 / sqrt( abs(src0.x) ), rsq_action
    * should compute 1 / sqrt (src0.x) */
   struct tgsi_llvm_opcode_action rsq_action;


   /** This function allows the user to insert some instructions at the
     * beginning of the program.  It is optional and does not need to be
     * implemented.
     */
   void (*emit_prologue)(struct tgsi_llvm_context *);

   /** This function allows the user to insert some instructions at the end of
     * the program.  This callback is intended to be used for emitting
     * instructions to handle the export for the output registers, but it can
     * be used for any purpose.  Implementing this function is optiona, but
     * recommended.
     */
   void (*emit_epilogue)(struct tgsi_llvm_context *);

   /** This function is for reading values from constant registers. */
   LLVMValueRef (*fetch_constant)(struct tgsi_llvm_context *,
                                  const struct tgsi_full_src_register * reg,
                                  const unsigned swizzle);

   /** This function is responsible for initilizing the inputs array and will be
     * called once for each input declared in the TGSI shader.
     */
   void (*load_input)(struct tgsi_llvm_context *,
                              unsigned input_index,
                              const struct tgsi_full_declaration *decl);


   /** User data to use with the callbacks */
   void * userdata;

   /** This array contains the input values for the shader.  Typically these
     * values will be in the form of a target intrinsic that will inform the
     * backend how to load the actual inputs to the shader. 
     */
   LLVMValueRef inputs[TGSI_LLVM_MAX_INPUTS];

   unsigned output_reg_count;

   union {
      struct lp_build_tgsi_aos_context aos;
      struct lp_build_tgsi_soa_context soa;
   } bld_ctx;

   struct gallivm_state gallivm;

   /*=== Private Members ===*/

   struct tgsi_llvm_branch branch[TGSI_LLVM_MAX_BRANCH_DEPTH];
   struct tgsi_llvm_loop loop[TGSI_LLVM_MAX_LOOP_DEPTH];

   unsigned branch_depth;
   unsigned loop_depth;


   LLVMValueRef main_fn;

};

/** Compile TGSI to an LLVM module */
LLVMModuleRef tgsi_llvm(struct tgsi_llvm_context * ctx,
                        const struct tgsi_token * tokens);

/** Clean up LLVM data structures */
void tgsi_llvm_dispose(struct tgsi_llvm_context * ctx);


/*=== Helper Functions ===*/

struct lp_build_context * tgsi_llvm_get_base(struct tgsi_llvm_context * ctx);

unsigned tgsi_llvm_reg_index_soa(unsigned index, unsigned chan); 

LLVMValueRef tgsi_llvm_emit_intr(
   const struct tgsi_llvm_opcode_action * action,
   struct tgsi_llvm_context * ctx,
   struct tgsi_llvm_emit_data * emit_data);

void tgsi_llvm_fetch_args(
   struct tgsi_llvm_context * ctx,
   struct tgsi_llvm_emit_data * emit_data);

void tgsi_llvm_fetch_args_tex(
   struct tgsi_llvm_context * ctx,
   struct tgsi_llvm_emit_data * emit_data);

#endif /* TGSI_LLVM_H */