PR rtl-optimization/88470
[official-gcc.git] / gcc / brig / brigfrontend / brig-mem-inst-handler.cc
blobd8374f232fb3e3d725b13609b19c269560c604c9
1 /* brig-mem-inst-handler.cc -- brig memory inst handler
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
6 This file is part of GCC.
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.
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.
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/>. */
22 #include "brig-code-entry-handler.h"
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"
32 tree
33 brig_mem_inst_handler::build_mem_access (const BrigInstBase *brig_inst,
34 tree addr, tree data)
36 bool is_load = brig_inst->opcode == BRIG_OPCODE_LD;
37 bool is_store = brig_inst->opcode == BRIG_OPCODE_ST;
39 if (!is_load && !is_store)
40 gcc_unreachable ();
42 tree instr_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
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)
49 instr_type = TREE_TYPE (data);
51 tree ptype = build_pointer_type (instr_type);
53 /* The HSAIL mem instructions are unaligned by default.
54 TODO: exploit the align modifier, it should lead to faster code.
56 tree unaligned_type = build_aligned_type (instr_type, 8);
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));
62 if (is_load)
64 /* Add a temporary variable so there won't be multiple
65 reads in case of vector unpack. */
66 mem_ref = m_parent.m_cf->add_temp_var ("mem_read", mem_ref);
67 return build_output_assignment (*brig_inst, data, mem_ref);
69 else
71 tree stmt = build2 (MODIFY_EXPR, TREE_TYPE (mem_ref), mem_ref, data);
72 return m_parent.m_cf->append_statement (stmt);
74 return mem_ref;
77 size_t
78 brig_mem_inst_handler::operator () (const BrigBase *base)
80 const BrigInstBase *brig_inst
81 = (const BrigInstBase *) &((const BrigInstBasic *) base)->base;
83 if (brig_inst->opcode == BRIG_OPCODE_ALLOCA)
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)
90 alignment = 1 << (mem_inst->align - 1);
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
98 = m_parent.m_cf->expand_or_call_builtin (BRIG_OPCODE_ALLOCA,
99 BRIG_TYPE_U32,
100 uint32_type_node, inputs);
101 build_output_assignment (*brig_inst, operands[0], builtin_call);
102 m_parent.m_cf->m_has_allocas = true;
103 return base->byteCount;
106 tree instr_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
108 const BrigData *operand_entries
109 = m_parent.get_brig_data_entry (brig_inst->operands);
111 uint32_t data_operand_offset;
112 memcpy (&data_operand_offset, &operand_entries->bytes, 4);
114 const BrigBase *operand
115 = m_parent.get_brig_operand_entry (data_operand_offset);
117 const BrigData *operandData = NULL;
119 bool is_store = brig_inst->opcode == BRIG_OPCODE_ST;
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;
127 if (is_three_element_vector_access)
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;
136 uint32_t addr_operand_offset;
137 memcpy (&addr_operand_offset, &operand_entries->bytes + 4, 4);
139 const BrigOperandAddress *addr_operand
140 = (const BrigOperandAddress *) m_parent.get_brig_operand_entry
141 (addr_operand_offset);
143 tree address_base = build_address_operand (*brig_inst, *addr_operand);
145 uint32_t address_offset = 0;
146 while (bytes > 0)
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);
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);
158 if (is_store && TREE_TYPE (data) != instr_type)
159 data = build_resize_convert_view (instr_type, data);
161 build_mem_access (brig_inst, address, data);
163 address_offset += int_size_in_bytes (instr_type);
164 ++operand_ptr;
165 bytes -= 4;
168 else
170 tree_stl_vec operands = build_operands (*brig_inst);
172 tree &data = operands.at (0);
173 tree &addr = operands.at (1);
174 build_mem_access (brig_inst, addr, data);
177 return base->byteCount;