assert(sparc_is_value_imm_encodeable(value));
be_emit_irprintf("%d", value);
} else {
- be_emit_cstring("%lo(");
+ if (get_entity_owner(entity) == get_tls_type()) {
+ be_emit_cstring("%tle_lox10(");
+ } else {
+ be_emit_cstring("%lo(");
+ }
be_gas_emit_entity(entity);
if (attr->immediate_value != 0) {
be_emit_irprintf("%+d", attr->immediate_value);
const sparc_attr_t *attr = get_sparc_attr_const(node);
ir_entity *entity = attr->immediate_value_entity;
- be_emit_cstring("%hi(");
if (entity == NULL) {
uint32_t value = (uint32_t) attr->immediate_value;
- be_emit_irprintf("0x%X", value);
+ be_emit_irprintf("%%hi(0x%X)", value);
} else {
+ if (get_entity_owner(entity) == get_tls_type()) {
+ be_emit_cstring("%tle_hix22(");
+ } else {
+ be_emit_cstring("%hi(");
+ }
be_gas_emit_entity(entity);
if (attr->immediate_value != 0) {
be_emit_irprintf("%+d", attr->immediate_value);
}
+ be_emit_char(')');
}
- be_emit_char(')');
}
void sparc_emit_source_register(const ir_node *node, int pos)
static ir_node *start_mem;
static size_t start_g0_offset;
static ir_node *start_g0;
+static size_t start_g7_offset;
+static ir_node *start_g7;
static size_t start_sp_offset;
static ir_node *start_sp;
static size_t start_fp_offset;
return start_g0;
}
+static ir_node *get_g7(ir_graph *irg)
+{
+ if (start_g7 == NULL) {
+ ir_node *start = get_irg_start(irg);
+ assert(is_sparc_Start(start));
+ start_g7 = new_r_Proj(start, mode_gp, start_g7_offset);
+ }
+ return start_g7;
+}
+
+static ir_node *make_tls_offset(dbg_info *dbgi, ir_node *block,
+ ir_entity *entity, int32_t offset)
+{
+ ir_node *hi = new_bd_sparc_SetHi(dbgi, block, entity, offset);
+ ir_node *low = new_bd_sparc_Xor_imm(dbgi, block, hi, entity, offset);
+ return low;
+}
+
+static ir_node *make_address(dbg_info *dbgi, ir_node *block, ir_entity *entity,
+ int32_t offset)
+{
+ if (get_entity_owner(entity) == get_tls_type()) {
+ ir_graph *irg = get_irn_irg(block);
+ ir_node *g7 = get_g7(irg);
+ ir_node *offsetn = make_tls_offset(dbgi, block, entity, offset);
+ ir_node *add = new_bd_sparc_Add_reg(dbgi, block, g7, offsetn);
+ return add;
+ } else {
+ ir_node *hi = new_bd_sparc_SetHi(dbgi, block, entity, offset);
+ ir_node *low = new_bd_sparc_Or_imm(dbgi, block, hi, entity, offset);
+ return low;
+ }
+}
+
typedef struct address_t {
ir_node *ptr;
ir_node *ptr2;
* won't save anything but produce multiple sethi+or combinations with
* just different offsets */
if (is_SymConst(base) && get_irn_n_edges(base) == 1) {
- dbg_info *dbgi = get_irn_dbg_info(ptr);
- ir_node *block = get_nodes_block(ptr);
- ir_node *new_block = be_transform_node(block);
- entity = get_SymConst_entity(base);
- base = new_bd_sparc_SetHi(dbgi, new_block, entity, offset);
- } else if (use_ptr2 && is_Add(base) && entity == NULL && offset == 0) {
+ ir_entity *sc_entity = get_SymConst_entity(base);
+ dbg_info *dbgi = get_irn_dbg_info(ptr);
+ ir_node *block = get_nodes_block(ptr);
+ ir_node *new_block = be_transform_node(block);
+
+ if (get_entity_owner(sc_entity) == get_tls_type()) {
+ if (!use_ptr2) {
+ goto only_offset;
+ } else {
+ ptr2 = make_tls_offset(dbgi, new_block, sc_entity, offset);
+ offset = 0;
+ base = get_g7(get_irn_irg(base));
+ }
+ } else {
+ entity = sc_entity;
+ base = new_bd_sparc_SetHi(dbgi, new_block, entity, offset);
+ }
+ } else if (use_ptr2 && is_Add(base) && offset == 0) {
ptr2 = be_transform_node(get_Add_right(base));
base = be_transform_node(get_Add_left(base));
} else {
+only_offset:
if (sparc_is_value_imm_encodeable(offset)) {
base = be_transform_node(base);
} else {
return get_irn_mode(op);
}
-static ir_node *make_address(dbg_info *dbgi, ir_node *block, ir_entity *entity,
- int32_t offset)
-{
- ir_node *hi = new_bd_sparc_SetHi(dbgi, block, entity, offset);
- ir_node *low = new_bd_sparc_Or_imm(dbgi, block, hi, entity, offset);
-
- if (get_entity_owner(entity) == get_tls_type())
- panic("thread local storage not supported yet in sparc backend");
- return low;
-}
-
static ir_node *gen_SwitchJmp(ir_node *node)
{
dbg_info *dbgi = get_irn_dbg_info(node);
assert(obstack_object_size(obst) == 0);
/* calculate number of outputs */
- n_outs = 3; /* memory, zero, sp */
+ n_outs = 4; /* memory, g0, g7, sp */
if (!current_cconv->omit_fp)
++n_outs; /* framepointer */
/* function parameters */
arch_set_irn_register_out(start, o, &sparc_registers[REG_G0]);
++o;
+ /* g7 is used for TLS data */
+ start_g7_offset = o;
+ req = be_create_reg_req(obst, &sparc_registers[REG_G7],
+ arch_register_req_type_ignore);
+ arch_set_irn_register_req_out(start, o, req);
+ arch_set_irn_register_out(start, o, &sparc_registers[REG_G7]);
+ ++o;
+
/* we need an output for the stackpointer */
start_sp_offset = o;
req = be_create_reg_req(obst, sp_reg,
start_mem = NULL;
start_g0 = NULL;
+ start_g7 = NULL;
start_sp = NULL;
start_fp = NULL;
frame_base = NULL;