Skip to content

Commit

Permalink
or1k: Re-worked TLS handling to register correctly
Browse files Browse the repository at this point in the history
A problem was detected where the call to __tls_get_addr would be emitted
but the call-clobbered registers wouldn't register as clobbered.

These changes makes GCC take TLS in account in the earlier phases and
seems to do the correct thing.
  • Loading branch information
bluecmd committed May 9, 2014
1 parent b5529b9 commit 62a1a27
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 45 deletions.
144 changes: 100 additions & 44 deletions gcc/config/or1k/or1k.c
Expand Up @@ -677,62 +677,102 @@ gen_tls_get_addr (void)

/* Emit call to '__tls_get_addr' */
static void
or1k_tls_call (rtx arg)
or1k_tls_call (rtx dest, rtx arg)
{
emit_library_call_value (gen_tls_get_addr(), arg,
emit_library_call_value (gen_tls_get_addr(), dest,
LCT_CONST, Pmode, 1, arg, Pmode);
}

bool
or1k_expand_symbol_ref(enum machine_mode mode, rtx operands[])
static rtx
or1k_legitimize_tls_address (rtx dest, rtx x)
{
if (mode == Pmode)
{
rtx op0, op1;
enum tls_model tls_kind;
rtx sym;
rtx tp = gen_rtx_REG(Pmode, THREAD_PTR_REGNUM);
rtx addend = NULL_RTX;
rtx result = dest;

op0 = operands[0];
op1 = operands[1];
enum tls_model tls_kind = or1k_tls_symbolic_operand (x);

if ((tls_kind = or1k_tls_symbolic_operand (op1)) != TLS_MODEL_NONE)
if (GET_CODE (x) == SYMBOL_REF)
sym = gen_rtx_SYMBOL_REF(Pmode, XSTR(x, 0));
else if (GET_CODE (x) == CONST)
{
rtx tp;
tp = gen_rtx_REG(Pmode, THREAD_PTR_REGNUM);
switch (tls_kind)
result = gen_reg_rtx (Pmode);
split_const (x, &sym, &addend);
sym = gen_rtx_SYMBOL_REF(Pmode, XSTR(sym, 0));
}
else
gcc_unreachable ();

switch (tls_kind) {
case TLS_MODEL_GLOBAL_DYNAMIC:
case TLS_MODEL_LOCAL_DYNAMIC:
{
case TLS_MODEL_GLOBAL_DYNAMIC:
case TLS_MODEL_LOCAL_DYNAMIC:
/* TODO: For now, treat LD as GD */
crtl->uses_pic_offset_table = 1;
emit_insn (gen_movsi_tlsgdhi (op0, op1));
emit_insn (gen_movsi_tlsgdlo (op0, op0, op1));
emit_insn (gen_add3_insn (op0, op0, pic_offset_table_rtx));
or1k_tls_call (op0);
break;

case TLS_MODEL_INITIAL_EXEC:
crtl->uses_pic_offset_table = 1;
emit_insn (gen_movsi_gottpoffhi (op0, op1));
emit_insn (gen_movsi_gottpofflo (op0, op0, op1));
emit_insn (gen_add3_insn (op0, op0, pic_offset_table_rtx));
emit_insn (gen_load_gottpoff (op0, op0));
emit_insn (gen_add3_insn (op0, op0, tp));
break;

case TLS_MODEL_LOCAL_EXEC:
emit_insn (gen_movsi_tpoffhi (op0, op1));
emit_insn (gen_movsi_tpofflo (op0, op0, op1));
emit_insn (gen_add3_insn (op0, op0, tp));
break;

default:
gcc_unreachable ();
/* TODO: For now, treat LD as GD */
rtx hi = gen_reg_rtx (Pmode);
rtx offset = gen_reg_rtx (Pmode);
rtx addr = gen_reg_rtx (Pmode);
crtl->uses_pic_offset_table = 1;
/* Generate a new symbol ref that is not marked as TLS or we will recurse
* in or1k_legitimate_constant_p. */
emit_insn (gen_movsi_tlsgdhi (hi, sym));
emit_insn (gen_movsi_tlsgdlo (offset, hi, sym));
emit_insn (gen_add3_insn (addr, offset, pic_offset_table_rtx));
or1k_tls_call (result, addr);
break;
}

return true;
}
case TLS_MODEL_INITIAL_EXEC:
{
rtx hi = gen_reg_rtx (Pmode);
rtx offset = gen_reg_rtx (Pmode);
rtx addr = gen_reg_rtx (Pmode);
rtx tpoffset = gen_reg_rtx (Pmode);
crtl->uses_pic_offset_table = 1;
emit_insn (gen_movsi_gottpoffhi (hi, sym));
emit_insn (gen_movsi_gottpofflo (offset, hi, sym));
emit_insn (gen_add3_insn (addr, offset, pic_offset_table_rtx));
emit_insn (gen_load_gottpoff (tpoffset, addr));
emit_insn (gen_add3_insn (result, tpoffset, tp));
break;
}
case TLS_MODEL_LOCAL_EXEC:
{
rtx hi = gen_reg_rtx (Pmode);
rtx addr = gen_reg_rtx (Pmode);
emit_insn (gen_movsi_tpoffhi (hi, sym));
emit_insn (gen_movsi_tpofflo (addr, hi, sym));
emit_insn (gen_add3_insn (result, addr, tp));
break;
}
default:
gcc_unreachable ();
}

if (addend != NULL_RTX)
emit_insn (gen_add3_insn (dest, result, addend));

return dest;
}

static rtx
or1k_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (or1k_tls_symbolic_operand (x) != TLS_MODEL_NONE)
return or1k_legitimize_tls_address (gen_reg_rtx (Pmode), x);

return x;
}

static bool
or1k_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
return or1k_tls_symbolic_operand (x) != TLS_MODEL_NONE;
}

bool
or1k_expand_symbol_ref(enum machine_mode mode, rtx operands[])
{
if (flag_pic && or1k_expand_pic_symbol_ref(mode, operands))
return true;

Expand All @@ -753,6 +793,13 @@ or1k_expand_move (enum machine_mode mode, rtx operands[])
}
}

if (or1k_tls_symbolic_operand (operands[1]) != TLS_MODEL_NONE)
{
or1k_legitimize_tls_address (force_reg (Pmode, operands[0]),
operands[1]);
return true;
}

if (or1k_expand_symbol_ref (mode, operands))
return true;

Expand Down Expand Up @@ -2010,9 +2057,15 @@ or1k_dwarf_calling_convention (const_tree function ATTRIBUTE_UNUSED)
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P or1k_legitimate_address_p

#undef TARGET_LEGITIMIZE_ADDRESS
#define TARGET_LEGITIMIZE_ADDRESS or1k_legitimize_address

#undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT or1k_trampoline_init

#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM or1k_cannot_force_const_mem

#undef TARGET_DWARF_CALLING_CONVENTION
#define TARGET_DWARF_CALLING_CONVENTION or1k_dwarf_calling_convention

Expand All @@ -2030,6 +2083,9 @@ or1k_dwarf_calling_convention (const_tree function ATTRIBUTE_UNUSED)
static bool
or1k_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
if (or1k_tls_symbolic_operand (x) != TLS_MODEL_NONE)
return 0;

return GET_CODE(x) != CONST_DOUBLE || (GET_MODE (x) == VOIDmode && !flag_pic);
}
#undef TARGET_LEGITIMATE_CONSTANT_P
Expand Down
2 changes: 1 addition & 1 deletion gcc/config/or1k/or1k.md
Expand Up @@ -309,7 +309,7 @@

(define_insn "movsi_got"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(match_operand 1 "" "")] UNSPEC_GOT))
(unspec:SI [(match_operand 1 "symbolic_operand" "")] UNSPEC_GOT))
(use (reg:SI 16))]
"flag_pic"
"l.lwz \t%0, got(%1)(r16)"
Expand Down
47 changes: 47 additions & 0 deletions gcc/config/or1k/predicates.md
Expand Up @@ -72,3 +72,50 @@
}
return 0;
})

;; True iff OP is a symbolic operand.

(define_predicate "symbolic_operand"
(match_code "symbol_ref,label_ref,const")
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
return !SYMBOL_REF_TLS_MODEL (op);
case LABEL_REF:
return true;
case CONST:
op = XEXP (op, 0);
return (GET_CODE (op) == PLUS
&& ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
break;
}
return false;
})

;; Return true if OP is a symbolic operand for the TLS Global Dynamic model.
(define_predicate "tgd_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_GLOBAL_DYNAMIC")))

;; Return true if OP is a symbolic operand for the TLS Local Dynamic model.

(define_predicate "tld_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_DYNAMIC")))

;; Return true if OP is a symbolic operand for the TLS Initial Exec model.

(define_predicate "tie_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC")))

;; Return true if OP is a symbolic operand for the TLS Local Exec model.

(define_predicate "tle_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC")))

0 comments on commit 62a1a27

Please sign in to comment.