/* Producing binary form of HSA BRIG from our internal representation.
- Copyright (C) 2013-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2020 Free Software Foundation, Inc.
Contributed by Martin Jambor <mjambor@suse.cz> and
Martin Liska <mliska@suse.cz>.
#include "coretypes.h"
#include "tm.h"
#include "target.h"
+#include "memmodel.h"
#include "tm_p.h"
#include "is-a.h"
#include "vec.h"
#include "tree-iterator.h"
#include "stor-layout.h"
#include "output.h"
-#include "cfg.h"
+#include "basic-block.h"
#include "function.h"
+#include "cfg.h"
#include "fold-const.h"
#include "stringpool.h"
#include "gimple-pretty-print.h"
#include "cgraph.h"
#include "dumpfile.h"
#include "print-tree.h"
+#include "alloc-pool.h"
#include "symbol-summary.h"
-#include "hsa.h"
+#include "hsa-common.h"
#include "gomp-constants.h"
/* Convert VAL to little endian form, if necessary. */
/* Structure representing a BRIG section, holding and writing its data. */
-class hsa_brig_section
+struct hsa_brig_section
{
-public:
/* Section name that will be output to the BRIG. */
const char *section_name;
/* Size in bytes of all data stored in the section. */
/* The size of the header of the section without any padding. */
unsigned header_byte_delta;
- /* Buffers of binary data, each containing BRIG_CHUNK_MAX_SIZE bytes. */
- vec <struct hsa_brig_data_chunk> chunks;
-
- /* More convenient access to the last chunk from the vector above. */
- struct hsa_brig_data_chunk *cur_chunk;
-
- void allocate_new_chunk ();
void init (const char *name);
void release ();
void output ();
- unsigned add (const void *data, unsigned len);
+ unsigned add (const void *data, unsigned len, void **output = NULL);
void round_size_up (int factor);
void *get_ptr_by_offset (unsigned int offset);
+
+private:
+ void allocate_new_chunk ();
+
+ /* Buffers of binary data, each containing BRIG_CHUNK_MAX_SIZE bytes. */
+ vec <struct hsa_brig_data_chunk> chunks;
+
+ /* More convenient access to the last chunk from the vector above. */
+ struct hsa_brig_data_chunk *cur_chunk;
};
static struct hsa_brig_section brig_data, brig_code, brig_operand;
/* List of sbr instructions. */
static vec <hsa_insn_sbr *> *switch_instructions;
-struct function_linkage_pair
+class function_linkage_pair
{
+public:
function_linkage_pair (tree decl, unsigned int off)
: function_decl (decl), offset (off) {}
}
/* Add to the stream LEN bytes of opaque binary DATA. Return the offset at
- which it was stored. */
+ which it was stored. If OUTPUT is not NULL, store into it the pointer to
+ the place where DATA was actually stored. */
unsigned
-hsa_brig_section::add (const void *data, unsigned len)
+hsa_brig_section::add (const void *data, unsigned len, void **output)
{
unsigned offset = total_size;
if (cur_chunk->size > (BRIG_CHUNK_MAX_SIZE - len))
allocate_new_chunk ();
- memcpy (cur_chunk->data + cur_chunk->size, data, len);
+ char *dst = cur_chunk->data + cur_chunk->size;
+ memcpy (dst, data, len);
+ if (output)
+ *output = dst;
cur_chunk->size += len;
total_size += len;
else
part++;
char *modname2;
- asprintf (&modname2, "%s_%s", modname, part);
+ modname2 = xasprintf ("%s_%s", modname, part);
free (modname);
modname = modname2;
}
return ret;
}
+static void emit_immediate_operand (hsa_op_immed *imm);
/* Emit directive describing a symbol if it has not been emitted already.
Return the offset of the directive. */
static unsigned
-emit_directive_variable (struct hsa_symbol *symbol)
+emit_directive_variable (class hsa_symbol *symbol)
{
struct BrigDirectiveVariable dirvar;
unsigned name_offset;
}
dirvar.name = lendian32 (name_offset);
- dirvar.init = 0;
+
+ if (symbol->m_decl && TREE_CODE (symbol->m_decl) == CONST_DECL)
+ {
+ hsa_op_immed *tmp = new hsa_op_immed (DECL_INITIAL (symbol->m_decl));
+ dirvar.init = lendian32 (enqueue_op (tmp));
+ }
+ else
+ dirvar.init = 0;
dirvar.type = lendian16 (symbol->m_type);
dirvar.segment = symbol->m_segment;
dirvar.align = symbol->m_align;
return symbol->m_directive_offset;
}
-/* Emit directives describing either a function declaration or
- definition F. */
+/* Emit directives describing either a function declaration or definition F and
+ return the produced BrigDirectiveExecutable structure. The function does
+ not take into account any instructions when calculating nextModuleEntry
+ field of the produced BrigDirectiveExecutable structure so when emitting
+ actual definitions, this field needs to be updated after all of the function
+ is actually added to the code section. */
static BrigDirectiveExecutable *
emit_function_directives (hsa_function_representation *f, bool is_declaration)
struct BrigDirectiveExecutable fndir;
unsigned name_offset, inarg_off, scoped_off, next_toplev_off;
int count = 0;
- BrigDirectiveExecutable *ptr_to_fndir;
+ void *ptr_to_fndir;
hsa_symbol *sym;
if (!f->m_declaration_p)
*slot = int_fn;
}
- brig_code.add (&fndir, sizeof (fndir));
- /* terrible hack: we need to set instCount after we emit all
- insns, but we need to emit directive in order, and we emit directives
- during insn emitting. So we need to emit the FUNCTION directive
- early, then the insns, and then we need to set instCount, so remember
- a pointer to it, in some horrible way. cur_chunk.data+size points
- directly to after fndir here. */
- ptr_to_fndir
- = (BrigDirectiveExecutable *)(brig_code.cur_chunk->data
- + brig_code.cur_chunk->size
- - sizeof (fndir));
+ brig_code.add (&fndir, sizeof (fndir), &ptr_to_fndir);
if (f->m_output_arg)
emit_directive_variable (f->m_output_arg);
}
}
- return ptr_to_fndir;
+ return (BrigDirectiveExecutable *) ptr_to_fndir;
}
/* Emit a label directive for the given HBB. We assume it is about to start on
"operands");
return 2;
}
- unsigned int_len = GET_MODE_SIZE (TYPE_MODE (type));
+ unsigned int_len = GET_MODE_SIZE (SCALAR_FLOAT_TYPE_MODE (type));
/* There are always 32 bits in each long, no matter the size of
the hosts long. */
long tmp[6];
if (TREE_CODE (m_tree_value) == VECTOR_CST)
{
- int i, num = VECTOR_CST_NELTS (m_tree_value);
+ /* Variable-length vectors aren't supported. */
+ int i, num = VECTOR_CST_NELTS (m_tree_value).to_constant ();
for (i = 0; i < num; i++)
{
tree v = VECTOR_CST_ELT (m_tree_value, i);
}
else if (TREE_CODE (m_tree_value) == CONSTRUCTOR)
{
- unsigned len = vec_safe_length (CONSTRUCTOR_ELTS (m_tree_value));
+ unsigned len = CONSTRUCTOR_NELTS (m_tree_value);
for (unsigned i = 0; i < len; i++)
{
tree v = CONSTRUCTOR_ELT (m_tree_value, i)->value;
operand_offsets;
unsigned l = insn->operand_count ();
- operand_offsets.safe_grow (l);
-
- for (unsigned i = 0; i < l; i++)
- operand_offsets[i] = lendian32 (enqueue_op (insn->get_op (i)));
/* We have N operands so use 4 * N for the byte_count. */
uint32_t byte_count = lendian32 (4 * l);
-
unsigned offset = brig_data.add (&byte_count, sizeof (byte_count));
- brig_data.add (operand_offsets.address (),
- l * sizeof (BrigOperandOffset32_t));
+ if (l > 0)
+ {
+ operand_offsets.safe_grow (l);
+ for (unsigned i = 0; i < l; i++)
+ operand_offsets[i] = lendian32 (enqueue_op (insn->get_op (i)));
+ brig_data.add (operand_offsets.address (),
+ l * sizeof (BrigOperandOffset32_t));
+ }
brig_data.round_size_up (4);
-
return offset;
}
{
struct BrigInstSignal repr;
- /* This is necessary because of the erroneous typedef of
- BrigMemoryModifier8_t which introduces padding which may then contain
- random stuff (which we do not want so that we can test things don't
- change). */
memset (&repr, 0, sizeof (repr));
repr.base.base.byteCount = lendian16 (sizeof (repr));
repr.base.base.kind = lendian16 (BRIG_KIND_INST_SIGNAL);
repr.base.type = lendian16 (mem->m_type);
repr.base.operands = lendian32 (emit_insn_operands (mem));
- repr.memoryOrder = mem->m_memoryorder;
- repr.signalOperation = mem->m_atomicop;
- repr.signalType = BRIG_TYPE_SIG64;
+ repr.memoryOrder = mem->m_memory_order;
+ repr.signalOperation = mem->m_signalop;
+ repr.signalType = hsa_machine_large_p () ? BRIG_TYPE_SIG64 : BRIG_TYPE_SIG32;
brig_code.add (&repr, sizeof (repr));
brig_insn_count++;
else
addr = as_a <hsa_op_address *> (mem->get_op (1));
- /* This is necessary because of the erroneous typedef of
- BrigMemoryModifier8_t which introduces padding which may then contain
- random stuff (which we do not want so that we can test things don't
- change). */
memset (&repr, 0, sizeof (repr));
repr.base.base.byteCount = lendian16 (sizeof (repr));
repr.base.base.kind = lendian16 (BRIG_KIND_INST_ATOMIC);
struct BrigInstMem repr;
gcc_checking_assert (alloca->operand_count () == 2);
- /* This is necessary because of the erroneous typedef of
- BrigMemoryModifier8_t which introduces padding which may then contain
- random stuff (which we do not want so that we can test things don't
- change). */
memset (&repr, 0, sizeof (repr));
repr.base.base.byteCount = lendian16 (sizeof (repr));
repr.base.base.kind = lendian16 (BRIG_KIND_INST_MEM);
brig_insn_count++;
}
-/* Emit an HSA branching instruction and all necessary directives, schedule
- necessary operands for writing. */
+/* Emit an HSA generic branching/sycnronization instruction. */
+
+static void
+emit_generic_branch_insn (hsa_insn_br *br)
+{
+ struct BrigInstBr repr;
+ repr.base.base.byteCount = lendian16 (sizeof (repr));
+ repr.base.base.kind = lendian16 (BRIG_KIND_INST_BR);
+ repr.base.opcode = lendian16 (br->m_opcode);
+ repr.width = br->m_width;
+ repr.base.type = lendian16 (br->m_type);
+ repr.base.operands = lendian32 (emit_insn_operands (br));
+ memset (&repr.reserved, 0, sizeof (repr.reserved));
+
+ brig_code.add (&repr, sizeof (repr));
+ brig_insn_count++;
+}
+
+/* Emit an HSA conditional branching instruction and all necessary directives,
+ schedule necessary operands for writing. */
static void
-emit_branch_insn (hsa_insn_br *br)
+emit_cond_branch_insn (hsa_insn_cbr *br)
{
struct BrigInstBr repr;
repr.base.base.byteCount = lendian16 (sizeof (repr));
repr.base.base.kind = lendian16 (BRIG_KIND_INST_BR);
repr.base.opcode = lendian16 (br->m_opcode);
- repr.width = BRIG_WIDTH_1;
+ repr.width = br->m_width;
/* For Conditional jumps the type is always B1. */
repr.base.type = lendian16 (BRIG_TYPE_B1);
repr.base.base.kind = lendian16 (BRIG_KIND_INST_QUEUE);
repr.base.opcode = lendian16 (insn->m_opcode);
repr.base.type = lendian16 (insn->m_type);
- repr.segment = BRIG_SEGMENT_GLOBAL;
- repr.memoryOrder = BRIG_MEMORY_ORDER_SC_RELEASE;
+ repr.segment = insn->m_segment;
+ repr.memoryOrder = insn->m_memory_order;
repr.base.operands = lendian32 (emit_insn_operands (insn));
brig_data.round_size_up (4);
brig_code.add (&repr, sizeof (repr));
emit_segment_insn (seg);
else if (hsa_insn_cmp *cmp = dyn_cast <hsa_insn_cmp *> (insn))
emit_cmp_insn (cmp);
- else if (hsa_insn_br *br = dyn_cast <hsa_insn_br *> (insn))
- emit_branch_insn (br);
+ else if (hsa_insn_cbr *br = dyn_cast <hsa_insn_cbr *> (insn))
+ emit_cond_branch_insn (br);
else if (hsa_insn_sbr *sbr = dyn_cast <hsa_insn_sbr *> (insn))
{
if (switch_instructions == NULL)
switch_instructions->safe_push (sbr);
emit_switch_insn (sbr);
}
+ else if (hsa_insn_br *br = dyn_cast <hsa_insn_br *> (insn))
+ emit_generic_branch_insn (br);
else if (hsa_insn_arg_block *block = dyn_cast <hsa_insn_arg_block *> (insn))
emit_arg_block_insn (block);
else if (hsa_insn_call *call = dyn_cast <hsa_insn_call *> (insn))
prev_bb = bb;
}
perhaps_emit_branch (prev_bb, NULL);
- ptr_to_fndir->nextModuleEntry = brig_code.total_size;
+ ptr_to_fndir->nextModuleEntry = lendian32 (brig_code.total_size);
/* Fill up label references for all sbr instructions. */
if (switch_instructions)
tree gridified_kernel_p_tree = build_int_cstu (boolean_type_node,
gridified_kernel_p);
unsigned count = 0;
-
- kernel_dependencies_vector_type
- = build_array_type (build_pointer_type (char_type_node),
- build_index_type (size_int (0)));
-
vec<constructor_elt, va_gc> *kernel_dependencies_vec = NULL;
if (hsa_decl_kernel_dependencies)
{
if (count > 0)
{
ASM_GENERATE_INTERNAL_LABEL (tmp_name, "__hsa_dependencies_list", i);
+ gcc_checking_assert (kernel_dependencies_vector_type);
tree dependencies_list = build_decl (UNKNOWN_LOCATION, VAR_DECL,
get_identifier (tmp_name),
kernel_dependencies_vector_type);