+ be_emit_cstring("\t.p2align ");
+ be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
+ be_emit_write_line();
+ }
+ emit_visibility(entity);
+
+ switch (be_gas_object_file_format) {
+ case OBJECT_FILE_FORMAT_ELF:
+ be_emit_cstring("\t.type\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(", ");
+ be_emit_char(be_gas_elf_type_char);
+ be_emit_cstring("function\n");
+ be_emit_write_line();
+ break;
+ case OBJECT_FILE_FORMAT_COFF:
+ be_emit_cstring("\t.def\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(";");
+ if (get_entity_visibility(entity) == ir_visibility_local) {
+ be_emit_cstring("\t.scl\t3;");
+ } else {
+ be_emit_cstring("\t.scl\t2;");
+ }
+ be_emit_cstring("\t.type\t32;\t.endef\n");
+ be_emit_write_line();
+ break;
+ case OBJECT_FILE_FORMAT_MACH_O:
+ break;
+ }
+ be_gas_emit_entity(entity);
+ be_emit_cstring(":\n");
+ be_emit_write_line();
+
+ be_dwarf_method_begin();
+}
+
+void be_gas_emit_function_epilog(const ir_entity *entity)
+{
+ be_dwarf_method_end();
+
+ if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
+ be_emit_cstring("\t.size\t");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(", .-");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ if (be_options.verbose_asm) {
+ be_emit_cstring("# -- End ");
+ be_gas_emit_entity(entity);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+
+ be_emit_char('\n');
+ be_emit_write_line();
+
+ next_block_nr += 199;
+ next_block_nr -= next_block_nr % 100;
+}
+
+/**
+ * Output a tarval.
+ *
+ * @param tv the tarval
+ * @param bytes the width of the tarvals value in bytes
+ */
+static void emit_arith_tarval(ir_tarval *tv, unsigned bytes)
+{
+ switch (bytes) {
+ case 1:
+ be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0));
+ return;
+
+ case 2:
+ be_emit_irprintf("0x%02x%02x",
+ get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+ return;
+
+ case 4:
+ be_emit_irprintf("0x%02x%02x%02x%02x",
+ get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2),
+ get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+ return;
+
+ case 8:
+ be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6),
+ get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
+ get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2),
+ get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+ return;
+ }
+
+ panic("Can't dump a tarval with %d bytes", bytes);
+}
+
+/**
+ * Return the label prefix for labeled instructions.
+ */
+const char *be_gas_insn_label_prefix(void)
+{
+ return ".LE";
+}
+
+/**
+ * Dump an atomic value.
+ *
+ * @param env the gas output environment
+ * @param init a node representing the atomic value (on the const code irg)
+ */
+static void emit_init_expression(be_gas_decl_env_t *env, ir_node *init)
+{
+ ir_mode *mode = get_irn_mode(init);
+ int bytes = get_mode_size_bytes(mode);
+ ir_tarval *tv;
+ ir_entity *ent;
+
+ init = skip_Id(init);
+
+ switch (get_irn_opcode(init)) {
+ case iro_Cast:
+ emit_init_expression(env, get_Cast_op(init));
+ return;
+
+ case iro_Conv:
+ emit_init_expression(env, get_Conv_op(init));
+ return;
+
+ case iro_Const:
+ tv = get_Const_tarval(init);
+
+ /* it's an arithmetic value */
+ emit_arith_tarval(tv, bytes);
+ return;
+
+ case iro_SymConst:
+ switch (get_SymConst_kind(init)) {
+ case symconst_addr_ent:
+ ent = get_SymConst_entity(init);
+ be_gas_emit_entity(ent);
+ break;
+
+ case symconst_ofs_ent:
+ ent = get_SymConst_entity(init);
+ be_emit_irprintf("%d", get_entity_offset(ent));
+ break;
+
+ case symconst_type_size:
+ be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
+ break;
+
+ case symconst_type_align:
+ be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
+ break;
+
+ case symconst_enum_const:
+ tv = get_enumeration_value(get_SymConst_enum(init));
+ emit_arith_tarval(tv, bytes);
+ break;
+
+ default:
+ assert(!"emit_atomic_init(): don't know how to init from this SymConst");
+ }
+ return;
+
+ case iro_Add:
+ if (!mode_is_int(mode) && !mode_is_reference(mode)) {
+ panic("Constant must be int or pointer for '+' to work");
+ }
+ emit_init_expression(env, get_Add_left(init));
+ be_emit_cstring(" + ");
+ emit_init_expression(env, get_Add_right(init));
+ return;
+
+ case iro_Sub:
+ if (!mode_is_int(mode) && !mode_is_reference(mode)) {
+ panic("Constant must be int or pointer for '-' to work");
+ }
+ emit_init_expression(env, get_Sub_left(init));
+ be_emit_cstring(" - ");
+ emit_init_expression(env, get_Sub_right(init));
+ return;
+
+ case iro_Mul:
+ if (!mode_is_int(mode) && !mode_is_reference(mode)) {
+ panic("Constant must be int or pointer for '*' to work");
+ }
+ emit_init_expression(env, get_Mul_left(init));
+ be_emit_cstring(" * ");
+ emit_init_expression(env, get_Mul_right(init));
+ return;
+
+ case iro_Unknown:
+ be_emit_cstring("0");
+ return;
+
+ default:
+ panic("unsupported IR-node %+F", init);
+ }
+}
+
+/**
+ * Dumps the type for given size (.byte, .long, ...)
+ *
+ * @param size the size in bytes
+ */
+static void emit_size_type(size_t size)
+{
+ switch (size) {
+ case 1: be_emit_cstring("\t.byte\t"); break;
+ case 2: be_emit_cstring("\t.short\t"); break;
+ case 4: be_emit_cstring("\t.long\t"); break;
+ case 8: be_emit_cstring("\t.quad\t"); break;
+
+ default:
+ panic("Try to dump a type with %u bytes", (unsigned)size);
+ }
+}
+
+static void emit_string_char(int c)
+{
+ switch (c) {
+ case '"' : be_emit_cstring("\\\""); break;
+ case '\n': be_emit_cstring("\\n"); break;
+ case '\r': be_emit_cstring("\\r"); break;
+ case '\t': be_emit_cstring("\\t"); break;
+ case '\\': be_emit_cstring("\\\\"); break;
+ default :
+ if (isprint(c))
+ be_emit_char(c);
+ else
+ be_emit_irprintf("\\%03o", c);
+ break;
+ }
+}
+
+static size_t emit_string_initializer(const ir_initializer_t *initializer)
+{
+ be_emit_cstring("\t.asciz \"");
+
+ size_t len = initializer->compound.n_initializers;
+ for (size_t i = 0; i < len-1; ++i) {
+ const ir_initializer_t *sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ ir_tarval *tv = get_initializer_tarval(sub_initializer);
+ int c = get_tarval_long(tv);
+ emit_string_char(c);
+ }
+ be_emit_cstring("\"\n");
+ be_emit_write_line();
+
+ return initializer->compound.n_initializers;
+}
+
+void be_gas_emit_cstring(const char *string)
+{
+ be_emit_cstring("\t.asciz \"");
+ for (const char *c = string; *c != '\0'; ++c) {
+ emit_string_char(*c);
+ }
+ be_emit_cstring("\"\n");
+ be_emit_write_line();
+}
+
+typedef enum normal_or_bitfield_kind {
+ NORMAL = 0,
+ TARVAL,
+ STRING,
+ BITFIELD
+} normal_or_bitfield_kind;
+
+typedef struct {
+ normal_or_bitfield_kind kind;
+ ir_type *type;
+ union {
+ ir_node *value;
+ ir_tarval *tarval;
+ unsigned char bf_val;
+ const ir_initializer_t *string;
+ } v;
+} normal_or_bitfield;
+
+static size_t get_initializer_size(const ir_initializer_t *initializer,
+ ir_type *type)
+{
+ switch (get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_TARVAL:
+ assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
+ return get_type_size_bytes(type);
+ case IR_INITIALIZER_CONST:
+ case IR_INITIALIZER_NULL:
+ return get_type_size_bytes(type);
+ case IR_INITIALIZER_COMPOUND:
+ if (is_Array_type(type)) {
+ if (is_array_variable_size(type)) {
+ ir_type *element_type = get_array_element_type(type);
+ unsigned element_size = get_type_size_bytes(element_type);
+ unsigned element_align
+ = get_type_alignment_bytes(element_type);
+ unsigned misalign = element_size % element_align;
+ size_t n_inits
+ = get_initializer_compound_n_entries(initializer);
+ element_size += element_align - misalign;
+ return n_inits * element_size;
+ } else {
+ return get_type_size_bytes(type);
+ }
+ } else {
+ assert(is_compound_type(type));
+ size_t size = get_type_size_bytes(type);
+ if (is_compound_variable_size(type)) {
+ /* last initializer has to be an array of variable size */
+ size_t l = get_initializer_compound_n_entries(initializer)-1;
+ const ir_initializer_t *last
+ = get_initializer_compound_value(initializer, l);
+ const ir_entity *last_ent = get_compound_member(type, l);
+ ir_type *last_type = get_entity_type(last_ent);
+ assert(is_array_variable_size(last_type));
+ size += get_initializer_size(last, last_type);
+ }
+ return size;
+ }
+ }
+
+ panic("found invalid initializer");
+}
+
+#ifndef NDEBUG
+static normal_or_bitfield *glob_vals;
+static size_t max_vals;
+#endif
+
+static void emit_bitfield(normal_or_bitfield *vals, size_t offset_bits,
+ const ir_initializer_t *initializer, ir_type *type)
+{
+ static const size_t BITS_PER_BYTE = 8;
+ ir_mode *mode = get_type_mode(type);
+ ir_tarval *tv = NULL;
+ int value_len;
+ size_t bit_offset;
+ size_t end;
+ bool big_endian = be_get_backend_param()->byte_order_big_endian;
+
+ switch (get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_NULL:
+ return;
+ case IR_INITIALIZER_TARVAL:
+ tv = get_initializer_tarval_value(initializer);
+ break;
+ case IR_INITIALIZER_CONST: {
+ ir_node *node = get_initializer_const_value(initializer);
+ if (!is_Const(node)) {
+ panic("bitfield initializer not a Const node");
+ }
+ tv = get_Const_tarval(node);
+ break;
+ }
+ case IR_INITIALIZER_COMPOUND:
+ panic("bitfield initializer is compound");
+ }
+ if (tv == NULL) {
+ panic("Couldn't get numeric value for bitfield initializer");
+ }
+ tv = tarval_convert_to(tv, get_type_mode(type));
+
+ value_len = get_type_size_bytes(get_primitive_base_type(type));
+ bit_offset = 0;
+ end = get_mode_size_bits(mode);
+ while (bit_offset < end) {
+ size_t src_offset = bit_offset / BITS_PER_BYTE;
+ size_t src_offset_bits = bit_offset % BITS_PER_BYTE;
+ size_t dst_offset = (bit_offset+offset_bits) / BITS_PER_BYTE;
+ size_t dst_offset_bits = (bit_offset+offset_bits) % BITS_PER_BYTE;
+ size_t src_bits_len = end-bit_offset;
+ size_t dst_bits_len = BITS_PER_BYTE-dst_offset_bits;
+ unsigned char curr_bits;
+ normal_or_bitfield *val;
+ if (src_bits_len > dst_bits_len)
+ src_bits_len = dst_bits_len;
+
+ if (big_endian) {
+ val = &vals[value_len - dst_offset - 1];
+ } else {
+ val = &vals[dst_offset];
+ }
+
+ assert((val-glob_vals) < (ptrdiff_t) max_vals);
+ assert(val->kind == BITFIELD ||
+ (val->kind == NORMAL && val->v.value == NULL));
+ val->kind = BITFIELD;
+ curr_bits = get_tarval_sub_bits(tv, src_offset);
+ curr_bits = curr_bits >> src_offset_bits;
+ if (src_offset_bits + src_bits_len > 8) {
+ unsigned next_bits = get_tarval_sub_bits(tv, src_offset+1);
+ curr_bits |= next_bits << (8 - src_offset_bits);
+ }
+ curr_bits &= (1 << src_bits_len) - 1;
+ val->v.bf_val |= curr_bits << dst_offset_bits;
+
+ bit_offset += dst_bits_len;
+ }
+}
+
+static void emit_ir_initializer(normal_or_bitfield *vals,
+ const ir_initializer_t *initializer,
+ ir_type *type)
+{
+ assert((size_t) (vals - glob_vals) <= max_vals);
+
+ if (initializer_is_string_const(initializer)) {
+ assert(vals->kind != BITFIELD);
+ vals->kind = STRING;
+ vals->v.string = initializer;
+ return;
+ }
+
+ switch (get_initializer_kind(initializer)) {
+ case IR_INITIALIZER_NULL:
+ return;
+ case IR_INITIALIZER_TARVAL: {
+ size_t i;
+
+ assert(vals->kind != BITFIELD);
+ vals->kind = TARVAL;
+ vals->type = type;
+ vals->v.tarval = get_initializer_tarval_value(initializer);
+ assert(get_type_mode(type) == get_tarval_mode(vals->v.tarval));
+ for (i = 1; i < get_type_size_bytes(type); ++i) {
+ vals[i].kind = NORMAL;
+ vals[i].type = NULL;
+ vals[i].v.value = NULL;
+ }
+ return;
+ }
+ case IR_INITIALIZER_CONST: {
+ size_t i;
+
+ assert(vals->kind != BITFIELD);
+ vals->kind = NORMAL;
+ vals->type = type;
+ vals->v.value = get_initializer_const_value(initializer);
+ for (i = 1; i < get_type_size_bytes(type); ++i) {
+ vals[i].kind = NORMAL;
+ vals[i].type = NULL;
+ vals[i].v.value = NULL;
+ }
+ return;
+ }
+ case IR_INITIALIZER_COMPOUND: {
+ size_t i = 0;
+ size_t n = get_initializer_compound_n_entries(initializer);
+
+ if (is_Array_type(type)) {
+ ir_type *element_type = get_array_element_type(type);
+ size_t skip = get_type_size_bytes(element_type);
+ size_t alignment = get_type_alignment_bytes(element_type);
+ size_t misalign = skip % alignment;
+ if (misalign != 0) {
+ skip += alignment - misalign;
+ }
+
+ for (i = 0; i < n; ++i) {
+ ir_initializer_t *sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ emit_ir_initializer(vals, sub_initializer, element_type);
+
+ vals += skip;
+ }
+ } else {
+ size_t n_members, i;
+ assert(is_compound_type(type));
+ n_members = get_compound_n_members(type);
+ for (i = 0; i < n_members; ++i) {
+ ir_entity *member = get_compound_member(type, i);
+ size_t offset = get_entity_offset(member);
+ ir_type *subtype = get_entity_type(member);
+ ir_mode *mode = get_type_mode(subtype);
+ ir_initializer_t *sub_initializer;
+
+ assert(i < get_initializer_compound_n_entries(initializer));
+ sub_initializer
+ = get_initializer_compound_value(initializer, i);
+
+ if (mode != NULL) {
+ size_t offset_bits
+ = get_entity_offset_bits_remainder(member);
+
+ if (is_Primitive_type(subtype)
+ && get_primitive_base_type(subtype) != NULL) {
+ emit_bitfield(&vals[offset], offset_bits,
+ sub_initializer, subtype);
+ continue;
+ } else {
+ assert(offset_bits == 0);
+ }
+ }
+
+ emit_ir_initializer(&vals[offset], sub_initializer, subtype);