xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/brig/brigfrontend/brig-mem-inst-handler.cc (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* brig-mem-inst-handler.cc -- brig memory inst handler
2    Copyright (C) 2016-2020 Free Software Foundation, Inc.
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
build_mem_access(const BrigInstBase * brig_inst,tree addr,tree data)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 
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);
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.  */
66       mem_ref = m_parent.m_cf->add_temp_var ("mem_read", mem_ref);
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
operator ()(const BrigBase * base)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
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;
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)
159 	    data = build_resize_convert_view (instr_type, data);
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 }
179