Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
3dd4d9c1
Commit
3dd4d9c1
authored
Aug 31, 2006
by
Michael Beck
Browse files
Add support for Linux TLS
parent
6d6da064
Changes
7
Hide whitespace changes
Inline
Side-by-side
ir/be/ia32/bearch_ia32.c
View file @
3dd4d9c1
...
...
@@ -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
);
...
...
ir/be/ia32/ia32_emitter.c
View file @
3dd4d9c1
...
...
@@ -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
);
...
...
ir/be/ia32/ia32_emitter.h
View file @
3dd4d9c1
...
...
@@ -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
;
/**
...
...
ir/be/ia32/ia32_gen_decls.c
View file @
3dd4d9c1
...
...
@@ -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_b
it
s
(
ty
)
+
7
)
>>
3
);
dump_object_size
(
obst
,
ld_name
,
get_type_size_b
yte
s
(
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_c
lass
_member
(
gt
,
i
));
dump_global
(
rdata_obstack
,
data_obstack
,
comm_obstack
,
get_c
ompound
_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
);
}
}
ir/be/ia32/ia32_new_nodes.c
View file @
3dd4d9c1
...
...
@@ -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
);
...
...
ir/be/ia32/ia32_new_nodes.h
View file @
3dd4d9c1
...
...
@@ -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)
*/
...
...
ir/be/ia32/ia32_spec.pl
View file @
3dd4d9c1
...
...
@@ -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 */
',
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment