111
|
1 /* brig-mem-inst-handler.cc -- brig memory inst handler
|
131
|
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
|
111
|
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
|
|
4 for General Processor Tech.
|
|
5
|
|
6 This file is part of GCC.
|
|
7
|
|
8 GCC is free software; you can redistribute it and/or modify it under
|
|
9 the terms of the GNU General Public License as published by the Free
|
|
10 Software Foundation; either version 3, or (at your option) any later
|
|
11 version.
|
|
12
|
|
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
16 for more details.
|
|
17
|
|
18 You should have received a copy of the GNU General Public License
|
|
19 along with GCC; see the file COPYING3. If not see
|
|
20 <http://www.gnu.org/licenses/>. */
|
|
21
|
|
22 #include "brig-code-entry-handler.h"
|
|
23
|
|
24 #include "errors.h"
|
|
25 #include "brig-util.h"
|
|
26 #include "gimple-expr.h"
|
|
27 #include "print-tree.h"
|
|
28 #include "tree-pretty-print.h"
|
|
29 #include "convert.h"
|
|
30 #include "diagnostic-core.h"
|
|
31
|
|
32 tree
|
|
33 brig_mem_inst_handler::build_mem_access (const BrigInstBase *brig_inst,
|
|
34 tree addr, tree data)
|
|
35 {
|
|
36 bool is_load = brig_inst->opcode == BRIG_OPCODE_LD;
|
|
37 bool is_store = brig_inst->opcode == BRIG_OPCODE_ST;
|
|
38
|
|
39 if (!is_load && !is_store)
|
|
40 gcc_unreachable ();
|
|
41
|
|
42 tree instr_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
|
|
43
|
131
|
44 /* In case of {ld,st}_v{2,4}. Note: since 'register' variables may
|
|
45 be any type, even a vector type, we distinguish the registers
|
|
46 from operand lists by checking for constructor nodes (which
|
|
47 operand lists are represented as). */
|
|
48 if (VECTOR_TYPE_P (TREE_TYPE (data)) && TREE_CODE (data) == CONSTRUCTOR)
|
111
|
49 instr_type = TREE_TYPE (data);
|
|
50
|
|
51 tree ptype = build_pointer_type (instr_type);
|
|
52
|
|
53 /* The HSAIL mem instructions are unaligned by default.
|
|
54 TODO: exploit the align modifier, it should lead to faster code.
|
|
55 */
|
|
56 tree unaligned_type = build_aligned_type (instr_type, 8);
|
|
57
|
|
58 /* Create a mem ref from the previous result, without offset. */
|
|
59 tree mem_ref
|
|
60 = build2 (MEM_REF, unaligned_type, addr, build_int_cst (ptype, 0));
|
|
61
|
|
62 if (is_load)
|
|
63 {
|
|
64 /* Add a temporary variable so there won't be multiple
|
|
65 reads in case of vector unpack. */
|
131
|
66 mem_ref = m_parent.m_cf->add_temp_var ("mem_read", mem_ref);
|
111
|
67 return build_output_assignment (*brig_inst, data, mem_ref);
|
|
68 }
|
|
69 else
|
|
70 {
|
|
71 tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (mem_ref), mem_ref, data);
|
|
72 return m_parent.m_cf->append_statement (stmt);
|
|
73 }
|
|
74 return mem_ref;
|
|
75 }
|
|
76
|
|
77 size_t
|
|
78 brig_mem_inst_handler::operator () (const BrigBase *base)
|
|
79 {
|
|
80 const BrigInstBase *brig_inst
|
|
81 = (const BrigInstBase *) &((const BrigInstBasic *) base)->base;
|
|
82
|
|
83 if (brig_inst->opcode == BRIG_OPCODE_ALLOCA)
|
|
84 {
|
|
85 tree_stl_vec operands = build_operands (*brig_inst);
|
|
86 size_t alignment = 1;
|
|
87 const BrigInstMem *mem_inst = (const BrigInstMem *) brig_inst;
|
|
88 if (mem_inst->align != BRIG_ALIGNMENT_NONE)
|
|
89 {
|
|
90 alignment = 1 << (mem_inst->align - 1);
|
|
91 }
|
|
92
|
|
93 tree align_opr = build_int_cstu (size_type_node, alignment);
|
|
94 tree_stl_vec inputs;
|
|
95 inputs.push_back (operands[1]);
|
|
96 inputs.push_back (align_opr);
|
|
97 tree builtin_call
|
131
|
98 = m_parent.m_cf->expand_or_call_builtin (BRIG_OPCODE_ALLOCA,
|
|
99 BRIG_TYPE_U32,
|
|
100 uint32_type_node, inputs);
|
111
|
101 build_output_assignment (*brig_inst, operands[0], builtin_call);
|
|
102 m_parent.m_cf->m_has_allocas = true;
|
|
103 return base->byteCount;
|
|
104 }
|
|
105
|
|
106 tree instr_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
|
|
107
|
|
108 const BrigData *operand_entries
|
|
109 = m_parent.get_brig_data_entry (brig_inst->operands);
|
|
110
|
|
111 uint32_t data_operand_offset;
|
|
112 memcpy (&data_operand_offset, &operand_entries->bytes, 4);
|
|
113
|
|
114 const BrigBase *operand
|
|
115 = m_parent.get_brig_operand_entry (data_operand_offset);
|
|
116
|
|
117 const BrigData *operandData = NULL;
|
|
118
|
|
119 bool is_store = brig_inst->opcode == BRIG_OPCODE_ST;
|
|
120
|
|
121 bool is_three_element_vector_access
|
|
122 = operand->kind == BRIG_KIND_OPERAND_OPERAND_LIST
|
|
123 && (operandData = m_parent.get_brig_data_entry
|
|
124 (((const BrigOperandOperandList *) operand)->elements))
|
|
125 && operandData->byteCount / 4 == 3;
|
|
126
|
|
127 if (is_three_element_vector_access)
|
|
128 {
|
|
129 /* We need to scalarize the 3-element vector accesses here
|
|
130 because gcc assumes the GENERIC vector datatypes are of two exponent
|
|
131 size internally. */
|
|
132 size_t bytes = operandData->byteCount;
|
|
133 const BrigOperandOffset32_t *operand_ptr
|
|
134 = (const BrigOperandOffset32_t *) operandData->bytes;
|
|
135
|
|
136 uint32_t addr_operand_offset;
|
|
137 memcpy (&addr_operand_offset, &operand_entries->bytes + 4, 4);
|
|
138
|
|
139 const BrigOperandAddress *addr_operand
|
|
140 = (const BrigOperandAddress *) m_parent.get_brig_operand_entry
|
|
141 (addr_operand_offset);
|
|
142
|
|
143 tree address_base = build_address_operand (*brig_inst, *addr_operand);
|
|
144
|
|
145 uint32_t address_offset = 0;
|
|
146 while (bytes > 0)
|
|
147 {
|
|
148 BrigOperandOffset32_t offset = *operand_ptr;
|
|
149 const BrigBase *operand_element
|
|
150 = m_parent.get_brig_operand_entry (offset);
|
|
151 tree data
|
|
152 = build_tree_operand (*brig_inst, *operand_element, instr_type);
|
|
153
|
|
154 tree ptr_offset = build_int_cst (size_type_node, address_offset);
|
|
155 tree address = build2 (POINTER_PLUS_EXPR, TREE_TYPE (address_base),
|
|
156 address_base, ptr_offset);
|
|
157
|
|
158 if (is_store && TREE_TYPE (data) != instr_type)
|
131
|
159 data = build_resize_convert_view (instr_type, data);
|
111
|
160
|
|
161 build_mem_access (brig_inst, address, data);
|
|
162
|
|
163 address_offset += int_size_in_bytes (instr_type);
|
|
164 ++operand_ptr;
|
|
165 bytes -= 4;
|
|
166 }
|
|
167 }
|
|
168 else
|
|
169 {
|
|
170 tree_stl_vec operands = build_operands (*brig_inst);
|
|
171
|
|
172 tree &data = operands.at (0);
|
|
173 tree &addr = operands.at (1);
|
|
174 build_mem_access (brig_inst, addr, data);
|
|
175 }
|
|
176
|
|
177 return base->byteCount;
|
|
178 }
|