Commit 3dd4d9c1 authored by Michael Beck's avatar Michael Beck
Browse files

Add support for Linux TLS

parent 6d6da064
......@@ -801,6 +801,22 @@ static void ia32_kill_convs(ia32_code_gen_t *cg) {
}
}
/**
* 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
......@@ -820,6 +836,7 @@ static void ia32_prepare_graph(void *self) {
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);
......
......@@ -49,10 +49,18 @@ void ia32_switch_section(FILE *F, section_t sec) {
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"
}
};
......@@ -69,6 +77,7 @@ void ia32_switch_section(FILE *F, section_t sec) {
case SECTION_DATA:
case SECTION_RODATA:
case SECTION_COMMON:
case SECTION_TLS:
fprintf(F, "\t%s\n", text[asm_flavour][sec]);
break;
......@@ -1802,7 +1811,7 @@ static void emit_ia32_Const(const ir_node *n, ia32_emit_env_t *env) {
* 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)) {
......@@ -1822,6 +1831,29 @@ static void emit_ia32_AddSP(const ir_node *irn, ia32_emit_env_t *emit_env) {
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();
......@@ -1884,6 +1916,7 @@ static void ia32_register_emitters(void) {
IA32_EMIT(Conv_I2I8Bit);
IA32_EMIT(Const);
IA32_EMIT(AddSP);
IA32_EMIT(LdTls);
IA32_EMIT(xCmp);
IA32_EMIT(xCmpSet);
IA32_EMIT(xCmpCMov);
......
......@@ -46,7 +46,8 @@ typedef enum section_t {
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;
/**
......
......@@ -70,8 +70,8 @@ static void ia32_dump_comm(struct obstack *obst, const char *name, visibility vi
}
}
/*
* output the alignment
/**
* output the alignment to an obstack
*/
static void ia32_dump_align(struct obstack *obst, int align)
{
......@@ -85,6 +85,24 @@ 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) {
......@@ -335,6 +353,9 @@ struct arr_info {
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:
......@@ -356,8 +377,8 @@ static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obst
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);
......@@ -372,7 +393,7 @@ static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obst
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);
......@@ -419,14 +440,14 @@ static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obst
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));
......@@ -442,7 +463,7 @@ static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obst
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);
......@@ -515,33 +536,44 @@ static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obst
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));
}
/************************************************************************/
......@@ -551,11 +583,12 @@ void ia32_gen_decls(FILE *out) {
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);
......@@ -567,7 +600,7 @@ void ia32_gen_decls(FILE *out) {
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);
}
......@@ -581,4 +614,17 @@ void ia32_gen_decls(FILE *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);
}
}
......@@ -42,14 +42,22 @@
* @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");
......@@ -678,23 +686,6 @@ void set_ia32_Immop_tarval(ir_node *node, tarval *tv) {
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)
*/
......@@ -1184,7 +1175,7 @@ void copy_ia32_Immop_attr(ir_node *dst, ir_node *src) {
}
/**
* 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);
......
......@@ -126,16 +126,6 @@ tarval *get_ia32_Immop_tarval(const ir_node *node);
*/
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)
*/
......
......@@ -770,6 +770,14 @@ else {
"outs" => [ "stack", "M" ],
},
"LdTls" => {
"irn_flags" => "R",
"comment" => "get the TLS base address",
"reg_req" => { "out" => [ "gp" ] },
},
#-----------------------------------------------------------------------------#
# _____ _____ ______ __ _ _ _ #
# / ____/ ____| ____| / _| | | | | | #
......@@ -1543,63 +1551,56 @@ else {
# 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 */',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment