}
}
+/**
+ * Transform the Thread Local Store base.
+ */
+static void transform_tls(ir_graph *irg) {
+ ir_node *irn = get_irg_tls(irg);
+
+ if (irn) {
+ dbg_info *dbg = get_irn_dbg_info(irn);
+ ir_node *blk = get_nodes_block(irn);
+ ir_node *newn;
+ newn = new_rd_ia32_LdTls(dbg, irg, blk, get_irn_mode(irn));
+
+ exchange(irn, newn);
+ }
+}
+
/**
* Transforms the standard firm graph into
* an ia32 firm graph
dom = be_compute_dominance_frontiers(cg->irg);
cg->kill_conv = new_nodeset(5);
+ transform_tls(cg->irg);
irg_walk_blkwise_graph(cg->irg, NULL, ia32_transform_node, cg);
ia32_kill_convs(cg);
del_nodeset(cg->kill_conv);
static section_t curr_sec = NO_SECTION;
static const char *text[ASM_MAX][SECTION_MAX] = {
{
- ".section\t.text", ".section\t.data", ".section\t.rodata", ".section\t.text"
+ ".section\t.text",
+ ".section\t.data",
+ ".section\t.rodata",
+ ".section\t.text",
+ ".section\t.tbss,\"awT\",@nobits"
},
{
- ".section\t.text", ".section\t.data", ".section .rdata,\"dr\"", ".section\t.text"
+ ".section\t.text",
+ ".section\t.data",
+ ".section .rdata,\"dr\"",
+ ".section\t.text",
+ ".section\t.tbss,\"awT\",@nobits"
}
};
case SECTION_DATA:
case SECTION_RODATA:
case SECTION_COMMON:
+ case SECTION_TLS:
fprintf(F, "\t%s\n", text[asm_flavour][sec]);
break;
* Emits code to increase stack pointer.
*/
static void emit_ia32_AddSP(const ir_node *irn, ia32_emit_env_t *emit_env) {
- FILE *F = emit_env->out;
+ FILE *F = emit_env->out;
char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
if (is_ia32_ImmConst(irn)) {
IA32_DO_EMIT(irn);
}
+/**
+ * Emits code to load the TLS base
+ */
+static void emit_ia32_LdTls(const ir_node *irn, ia32_emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+
+ switch (asm_flavour) {
+ case ASM_LINUX_GAS:
+ lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, DWORD PTR %%gs:0", irn);
+ break;
+ case ASM_MINGW_GAS:
+ lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, DWORD PTR %%gs:0", irn);
+ break;
+ default:
+ assert(0 && "unsupported TLS");
+ break;
+ }
+ snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get thread local storage base */");
+
+ IA32_DO_EMIT(irn);
+}
+
static void emit_be_Return(const ir_node *n, ia32_emit_env_t *env) {
FILE *F = env->out;
const lc_arg_env_t *arg_env = ia32_get_arg_env();
IA32_EMIT(Conv_I2I8Bit);
IA32_EMIT(Const);
IA32_EMIT(AddSP);
+ IA32_EMIT(LdTls);
IA32_EMIT(xCmp);
IA32_EMIT(xCmpSet);
IA32_EMIT(xCmpCMov);
SECTION_DATA = 1, /**< data section */
SECTION_RODATA = 2, /**< rodata section */
SECTION_COMMON = 3, /**< common section */
- SECTION_MAX = 4
+ SECTION_TLS = 4, /**< thread local storage section */
+ SECTION_MAX = 5
} section_t;
/**
}
}
-/*
- * output the alignment
+/**
+ * output the alignment to an obstack
*/
static void ia32_dump_align(struct obstack *obst, int align)
{
obstack_printf(obst, "\t.align %d\n", align);
}
+/**
+ * output the alignment to a FILE
+ */
+static void ia32_dump_align_f(FILE *f, int align)
+{
+ int h = highest_bit(align);
+
+ if ((1 << h) < align)
+ ++h;
+ align = (1 << h);
+
+ if (align > 1)
+ fprintf(f, "\t.align %d\n", align);
+}
+
+/**
+ * output a tarval
+ */
static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
{
switch (bytes) {
int size;
};
+/**
+ * Dump the size of an object
+ */
static void dump_object_size(struct obstack *obst, const char *name, int size) {
switch (asm_flavour) {
case ASM_LINUX_GAS:
struct obstack *obst = data_obstack;
/*
- * FIXME: did NOT work for partly constant values
- */
+ * FIXME: did NOT work for partly constant values
+ */
if (! is_Method_type(ty)) {
ent_variability variability = get_entity_variability(ent);
visibility visibility = get_entity_visibility(ent);
if (visibility == visibility_external_visible) {
obstack_printf(obst, ".globl\t%s\n", ld_name);
}
- dump_object_size(obst, ld_name, (get_type_size_bits(ty) + 7) >> 3);
+ dump_object_size(obst, ld_name, get_type_size_bytes(ty));
align = get_type_alignment_bytes(ty);
ia32_dump_align(obst, align);
int type_size, j;
/* Compound entities are NOT sorted.
- * The sorting strategy used doesn't work for `value' compound fields nor
- * for partially_constant entities.
- */
+ * The sorting strategy used doesn't work for `value' compound fields nor
+ * for partially_constant entities.
+ */
/*
- * in the worst case, every entity allocates one byte, so the type
- * size should be equal or bigger the number of fields
- */
+ * in the worst case, every entity allocates one byte, so the type
+ * size should be equal or bigger the number of fields
+ */
type_size = get_type_size_bytes(ty);
vals = xcalloc(type_size, sizeof(*vals));
ai = xcalloc(graph_length, sizeof(struct arr_info));
/* We wanna know how many arrays are on the path to the entity. We also have to know how
- * many elements each array holds to calculate the offset for the entity. */
+ * many elements each array holds to calculate the offset for the entity. */
for (j = 0; j < graph_length; j++) {
entity *step = get_compound_graph_path_node(path, j);
ir_type *step_type = get_entity_type(step);
obstack_printf(obst, "\n");
}
else if (visibility != visibility_external_allocated) {
- /* calculate the alignment */
- align = get_type_alignment_bytes(ty);
- h = highest_bit(align);
-
- if ((1 << h) < align)
- ++h;
- align = (1 << h);
-
- if (align < 1)
- align = 1;
-
- ia32_dump_comm(comm_obstack, ld_name, visibility,
- (get_type_size_bits(ty) + 7) >> 3, align);
+ /* uninitialized and NOT external */
+ if (get_entity_owner(ent) != get_tls_type()) {
+ /* calculate the alignment */
+ align = get_type_alignment_bytes(ty);
+ h = highest_bit(align);
+
+ if ((1 << h) < align)
+ ++h;
+ align = (1 << h);
+
+ if (align < 1)
+ align = 1;
+
+ ia32_dump_comm(comm_obstack, ld_name, visibility,
+ get_type_size_bytes(ty), align);
+ } else {
+ /* TLS */
+ if (visibility == visibility_external_visible) {
+ obstack_printf(obst, ".globl\t%s\n", ld_name);
+ }
+ dump_object_size(comm_obstack, ld_name, get_type_size_bytes(ty));
+ align = get_type_alignment_bytes(ty);
+ ia32_dump_align(obst, align);
+ obstack_printf(comm_obstack, "%s:\n\t.zero %d\n", ld_name, get_type_size_bytes(ty));
+ }
}
}
}
-/*
+/**
* Dumps declarations of global variables and the initialization code.
*/
-void ia32_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
+static void ia32_dump_globals(ir_type *gt, struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
{
- ir_type *gt = get_glob_type();
- int i, n = get_class_n_members(gt);
+ int i, n = get_compound_n_members(gt);
for (i = 0; i < n; i++)
- dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
+ dump_global(rdata_obstack, data_obstack, comm_obstack, get_compound_member(gt, i));
}
/************************************************************************/
int size;
char *cp;
+ /* dump the global type */
obstack_init(&rodata);
obstack_init(&data);
obstack_init(&comm);
- ia32_dump_globals(&rodata, &data, &comm);
+ ia32_dump_globals(get_glob_type(), &rodata, &data, &comm);
size = obstack_object_size(&data);
cp = obstack_finish(&data);
size = obstack_object_size(&rodata);
cp = obstack_finish(&rodata);
if (size > 0) {
- fprintf(out, "\t.section\t.rodata\n");
+ ia32_switch_section(out, SECTION_RODATA);
fwrite(cp, 1, size, out);
}
obstack_free(&rodata, NULL);
obstack_free(&data, NULL);
obstack_free(&comm, NULL);
+
+ /* dump the Thread Local Storage */
+ obstack_init(&data);
+ ia32_dump_globals(get_tls_type(), &data, &data, &data);
+
+ size = obstack_object_size(&data);
+ cp = obstack_finish(&data);
+ if (size > 0) {
+ ia32_switch_section(out, SECTION_TLS);
+ ia32_dump_align_f(out, 32);
+ fwrite(cp, 1, size, out);
+ }
+
}
* @return The ident of the SymConst
*/
static ident *get_sc_ident(ir_node *symc) {
- assert(get_irn_opcode(symc) == iro_SymConst && "need symconst to get ident");
+ entity *ent;
+ ir_type *owner;
+ ident *id;
switch (get_SymConst_kind(symc)) {
case symconst_addr_name:
return get_SymConst_name(symc);
case symconst_addr_ent:
- return get_entity_ld_ident(get_SymConst_entity(symc));
+ ent = get_SymConst_entity(symc);
+ owner = get_entity_owner(ent);
+ id = get_entity_ld_ident(ent);
+ if (owner == get_tls_type()) {
+ id = mangle(id, new_id_from_chars("@NTPOFF", 7));
+ }
+ return id;
default:
assert(0 && "Unsupported SymConst");
attr->cnst = get_ident_for_tv(tv);
}
-/**
- * Return the sc attribute.
- */
-ident *get_ia32_sc(const ir_node *node) {
- ia32_attr_t *attr = get_ia32_attr(node);
- return attr->cnst_val.sc;
-}
-
-/**
- * Sets the sc attribute.
- */
-void set_ia32_sc(ir_node *node, ident *sc) {
- ia32_attr_t *attr = get_ia32_attr(node);
- attr->cnst_val.sc = sc;
- attr->cnst = attr->cnst_val.sc;
-}
-
/**
* Gets the string representation of the internal const (tv or symconst)
*/
}
/**
- * Copy the attributes from a Firm Const to an ia32_Const
+ * Copy the attributes from a Firm Const/SymConst to an ia32_Const
*/
void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) {
ia32_attr_t *attr = get_ia32_attr(ia32_cnst);
*/
void set_ia32_Immop_tarval(ir_node *node, tarval *tv);
-/**
- * Return the sc attribute.
- */
-ident *get_ia32_sc(const ir_node *node);
-
-/**
- * Sets the sc attribute.
- */
-void set_ia32_sc(ir_node *node, ident *sc);
-
/**
* Gets the string representation of the internal const (tv or symconst)
*/
"outs" => [ "stack", "M" ],
},
+"LdTls" => {
+ "irn_flags" => "R",
+ "comment" => "get the TLS base address",
+ "reg_req" => { "out" => [ "gp" ] },
+},
+
+
+
#-----------------------------------------------------------------------------#
# _____ _____ ______ __ _ _ _ #
# / ____/ ____| ____| / _| | | | | | #
# constants
"fldz" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load 0.0: Ld 0.0 -> reg",
"reg_req" => { },
"emit" => '. fldz /* x87 0.0 -> %D1 */',
},
"fld1" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load 1.0: Ld 1.0 -> reg",
"reg_req" => { },
"emit" => '. fld1 /* x87 1.0 -> %D1 */',
},
"fldpi" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load pi: Ld pi -> reg",
"reg_req" => { },
"emit" => '. fldpi /* x87 pi -> %D1 */',
},
"fldln2" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load ln 2: Ld ln 2 -> reg",
"reg_req" => { },
"emit" => '. fldln2 /* x87 ln(2) -> %D1 */',
},
"fldlg2" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load lg 2: Ld lg 2 -> reg",
"reg_req" => { },
"emit" => '. fldlg2 /* x87 log(2) -> %D1 */',
},
"fldl2t" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load ld 10: Ld ld 10 -> reg",
"reg_req" => { },
"emit" => '. fldll2t /* x87 ld(10) -> %D1 */',
},
"fldl2e" => {
- "op_flags" => "R",
+ "op_flags" => "R|c",
"irn_flags" => "R",
- "rd_constructor" => "NONE",
"comment" => "x87 fp Load ld e: Ld ld e -> reg",
"reg_req" => { },
"emit" => '. fldl2e /* x87 ld(e) -> %D1 */',