1 /*
2 * Copyright © 2018 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "brw_asm.h"
7 #include "brw_asm_internal.h"
8 #include "brw_disasm_info.h"
9
10 /* TODO: Check if we can use bison/flex without globals. */
11
12 extern FILE *yyin;
13 struct list_head instr_labels;
14 struct list_head target_labels;
15
16 struct brw_codegen *p;
17 const char *input_filename;
18 int errors;
19
20 static bool
i965_postprocess_labels()21 i965_postprocess_labels()
22 {
23 void *store = p->store;
24
25 struct target_label *tlabel;
26 struct instr_label *ilabel, *s;
27
28 const unsigned to_bytes_scale = brw_jump_scale(p->devinfo);
29
30 LIST_FOR_EACH_ENTRY(tlabel, &target_labels, link) {
31 LIST_FOR_EACH_ENTRY_SAFE(ilabel, s, &instr_labels, link) {
32 if (!strcmp(tlabel->name, ilabel->name)) {
33 brw_inst *inst = store + ilabel->offset;
34
35 int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(brw_inst);
36 relative_offset *= to_bytes_scale;
37
38 unsigned opcode = brw_inst_opcode(p->isa, inst);
39
40 if (ilabel->type == INSTR_LABEL_JIP) {
41 switch (opcode) {
42 case BRW_OPCODE_IF:
43 case BRW_OPCODE_ELSE:
44 case BRW_OPCODE_ENDIF:
45 case BRW_OPCODE_WHILE:
46 brw_inst_set_jip(p->devinfo, inst, relative_offset);
47 break;
48 case BRW_OPCODE_BREAK:
49 case BRW_OPCODE_HALT:
50 case BRW_OPCODE_CONTINUE:
51 brw_inst_set_jip(p->devinfo, inst, relative_offset);
52 break;
53 default:
54 fprintf(stderr, "Unknown opcode %d with JIP label\n", opcode);
55 return false;
56 }
57 } else {
58 switch (opcode) {
59 case BRW_OPCODE_IF:
60 case BRW_OPCODE_ELSE:
61 brw_inst_set_uip(p->devinfo, inst, relative_offset);
62 break;
63 case BRW_OPCODE_WHILE:
64 case BRW_OPCODE_ENDIF:
65 fprintf(stderr, "WHILE/ENDIF cannot have UIP offset\n");
66 return false;
67 case BRW_OPCODE_BREAK:
68 case BRW_OPCODE_CONTINUE:
69 case BRW_OPCODE_HALT:
70 brw_inst_set_uip(p->devinfo, inst, relative_offset);
71 break;
72 default:
73 fprintf(stderr, "Unknown opcode %d with UIP label\n", opcode);
74 return false;
75 }
76 }
77
78 list_del(&ilabel->link);
79 }
80 }
81 }
82
83 LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
84 fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
85 }
86
87 return list_is_empty(&instr_labels);
88 }
89
90 /* TODO: Would be nice to make this operate on string instead on a FILE. */
91
92 brw_assemble_result
brw_assemble(void * mem_ctx,const struct intel_device_info * devinfo,FILE * f,const char * filename,brw_assemble_flags flags)93 brw_assemble(void *mem_ctx, const struct intel_device_info *devinfo,
94 FILE *f, const char *filename, brw_assemble_flags flags)
95 {
96 brw_assemble_result result = {0};
97
98 list_inithead(&instr_labels);
99 list_inithead(&target_labels);
100
101 struct brw_isa_info isa;
102 brw_init_isa_info(&isa, devinfo);
103
104 p = rzalloc(mem_ctx, struct brw_codegen);
105 brw_init_codegen(&isa, p, p);
106
107 yyin = f;
108 input_filename = filename;
109
110 int err = yyparse();
111 if (err || errors)
112 goto end;
113
114 if (!i965_postprocess_labels())
115 goto end;
116
117 struct disasm_info *disasm_info = disasm_initialize(p->isa, NULL);
118 if (!disasm_info) {
119 ralloc_free(disasm_info);
120 fprintf(stderr, "Unable to initialize disasm_info struct instance\n");
121 goto end;
122 }
123
124 if (!brw_validate_instructions(p->isa, p->store, 0,
125 p->next_insn_offset, disasm_info)) {
126 ralloc_free(disasm_info);
127 fprintf(stderr, "Invalid instructions\n");
128 goto end;
129 }
130
131 result.bin = p->store;
132 result.bin_size = p->next_insn_offset;
133 result.inst_count = p->next_insn_offset / 16;
134
135 if ((flags & BRW_ASSEMBLE_COMPACT) != 0) {
136 brw_compact_instructions(p, 0, disasm_info);
137
138 /* Adjust bin size to account for compacted instructions. */
139 int compacted = 0;
140 for (int i = 0; i < result.inst_count; i++) {
141 const brw_inst *inst = result.bin + i;
142 if (brw_inst_cmpt_control(devinfo, inst))
143 compacted++;
144 }
145 result.bin_size -= compacted * 8;
146 }
147
148 ralloc_free(disasm_info);
149
150 end:
151 /* Reset internal state. */
152 yyin = NULL;
153 input_filename = NULL;
154 p = NULL;
155 list_inithead(&instr_labels);
156 list_inithead(&target_labels);
157
158 return result;
159 }
160
161