Skip to content

Commit

Permalink
i#3544 RV64: Support mangling exclusive loads using tp register (#7062)
Browse files Browse the repository at this point in the history
Similar to the way we mangle exclusive loads using the stolen register,
spill out a register and load the guest value of tp. One more argument
is added to pick_scratch_reg() for cases where two scratch registers
have been occupied.

Tests will be included after all corner cases have been covered. For
now, a hand-crafted assembly sequence like

```
_start:
        lla             a0,            slot
        mv              tp,             a0
        lr.w.aqrl       s11,            (tp)
        mv              a0,             s11
        li              a7,             93
        ecall
        .align          4
slot:   .long           55
```

could be used as a test by checking return value. Manually checking
generated code confirms scratch registers are correctly saved.

Issue: #3544
  • Loading branch information
ziyao233 authored Nov 1, 2024
1 parent 4e6e71d commit 57d9fe9
Showing 1 changed file with 41 additions and 16 deletions.
57 changes: 41 additions & 16 deletions core/arch/riscv64/mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,14 +644,14 @@ mangle_rel_addr(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,

static reg_id_t
pick_scratch_reg(dcontext_t *dcontext, instr_t *instr, reg_id_t do_not_pick,
ushort *scratch_slot DR_PARAM_OUT)
reg_id_t do_not_pick_2, ushort *scratch_slot DR_PARAM_OUT)
{
reg_id_t reg = REG_NULL;
ushort slot = 0;

for (reg = SCRATCH_REG0, slot = TLS_REG0_SLOT; reg <= SCRATCH_REG_LAST;
reg++, slot += sizeof(reg_t)) {
if (!instr_uses_reg(instr, reg) && reg != do_not_pick)
if (!instr_uses_reg(instr, reg) && reg != do_not_pick && reg != do_not_pick_2)
break;
}

Expand Down Expand Up @@ -682,7 +682,7 @@ mangle_stolen_reg_and_tp_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t *
* likewise, if it's only used for dst, do not restore it from app's TLS.
*/
if (instr_uses_reg(instr, DR_REG_TP)) {
scratch_reg = pick_scratch_reg(dcontext, instr, DR_REG_NULL, &slot);
scratch_reg = pick_scratch_reg(dcontext, instr, DR_REG_NULL, DR_REG_NULL, &slot);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg, slot));
PRE(ilist, instr,
instr_create_restore_from_tls(dcontext, scratch_reg,
Expand Down Expand Up @@ -725,7 +725,7 @@ mangle_stolen_reg_and_tp_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t *
* TLS; likewise, if it's only used for dst, do not restore it from app's TLS.
*/
if (instr_uses_reg(instr, dr_reg_stolen)) {
scratch_reg = pick_scratch_reg(dcontext, instr, scratch_reg, &slot);
scratch_reg = pick_scratch_reg(dcontext, instr, scratch_reg, DR_REG_NULL, &slot);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg, slot));
PRE(ilist, instr,
instr_create_restore_from_tls(dcontext, scratch_reg, TLS_REG_STOLEN_SLOT));
Expand Down Expand Up @@ -793,15 +793,17 @@ mangle_cbr_stolen_reg_and_tp_reg(dcontext_t *dcontext, instrlist_t *ilist, instr
bool instr_uses_reg_stolen = instr_uses_reg(instr, dr_reg_stolen);

if (instr_uses_tp) {
scratch_reg1 = pick_scratch_reg(dcontext, instr, DR_REG_NULL, &slot1);
scratch_reg1 =
pick_scratch_reg(dcontext, instr, DR_REG_NULL, DR_REG_NULL, &slot1);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg1, slot1));
PRE(ilist, instr,
instr_create_restore_from_tls(dcontext, scratch_reg1,
os_get_app_tls_base_offset(TLS_REG_LIB)));
}

if (instr_uses_reg_stolen) {
scratch_reg2 = pick_scratch_reg(dcontext, instr, scratch_reg1, &slot2);
scratch_reg2 =
pick_scratch_reg(dcontext, instr, scratch_reg1, DR_REG_NULL, &slot2);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg2, slot2));
PRE(ilist, instr,
instr_create_restore_from_tls(dcontext, scratch_reg2, TLS_REG_STOLEN_SLOT));
Expand Down Expand Up @@ -910,32 +912,41 @@ static instr_t *
mangle_exclusive_load(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
instr_t *next_instr)
{
/* TODO i#3544: Not implemented. */
ASSERT_NOT_IMPLEMENTED(!instr_uses_reg(instr, DR_REG_TP));

reg_id_t scratch_reg1 = DR_REG_NULL, scratch_reg2 = DR_REG_NULL;
ushort slot1, slot2;
reg_id_t scratch_reg1 = DR_REG_NULL, scratch_reg2 = DR_REG_NULL,
scratch_reg3 = DR_REG_NULL;
ushort slot1, slot2, slot3;
int aqrl, opcode;
opnd_t dst, src0;
opnd_size_t opsz;
bool uses_reg_stolen;
bool uses_reg_stolen, uses_reg_tp;
ASSERT(instr_is_exclusive_load(instr));
ASSERT(instr_num_dsts(instr) == 1 && instr_num_srcs(instr) == 2 &&
opnd_is_immed_int(instr_get_src(instr, 1)));

aqrl = opnd_get_immed_int(instr_get_src(instr, 1));
uses_reg_stolen = instr_uses_reg(instr, dr_reg_stolen);
uses_reg_tp = instr_uses_reg(instr, DR_REG_TP);

/* Pick and spill scratch register(s). */
scratch_reg1 = pick_scratch_reg(dcontext, instr, DR_REG_NULL, &slot1);
scratch_reg1 = pick_scratch_reg(dcontext, instr, DR_REG_NULL, DR_REG_NULL, &slot1);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg1, slot1));

if (uses_reg_stolen) {
scratch_reg2 = pick_scratch_reg(dcontext, instr, scratch_reg1, &slot2);
scratch_reg2 =
pick_scratch_reg(dcontext, instr, scratch_reg1, DR_REG_NULL, &slot2);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg2, slot2));
PRE(ilist, instr,
instr_create_restore_from_tls(dcontext, scratch_reg2, TLS_REG_STOLEN_SLOT));
}
if (uses_reg_tp) {
scratch_reg3 =
pick_scratch_reg(dcontext, instr, scratch_reg1, scratch_reg2, &slot3);
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg3, slot3));
PRE(ilist, instr,
instr_create_restore_from_tls(
dcontext, scratch_reg3,
os_tls_offset(os_get_app_tls_base_offset(TLS_REG_LIB))));
}

/* Keep the release semantics if needed. */
if (TESTALL(LRSC_ORDERING_RL_MASK, aqrl)) {
Expand All @@ -953,11 +964,17 @@ mangle_exclusive_load(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
opcode = instr_get_opcode(instr) == OP_lr_d ? OP_ld : OP_lw;
opsz = opcode == OP_ld ? OPSZ_8 : OPSZ_4;
ASSERT(opnd_is_reg(dst) && opnd_is_base_disp(src0));
/* XXX: Simplify this with instr_replace_reg_resize after opnd_replace_reg_resize is
* implemented */
if (opnd_get_reg(dst) == dr_reg_stolen) {
opnd_replace_reg(&dst, dr_reg_stolen, scratch_reg2);
} else if (opnd_get_reg(dst) == DR_REG_TP) {
opnd_replace_reg(&dst, DR_REG_TP, scratch_reg3);
}
if (opnd_get_base(src0) == dr_reg_stolen) {
opnd_replace_reg(&src0, dr_reg_stolen, scratch_reg2);
} else if (opnd_get_base(src0) == DR_REG_TP) {
opnd_replace_reg(&src0, DR_REG_TP, scratch_reg3);
}
instr_reset(dcontext, instr);
instr_set_opcode(instr, opcode);
Expand Down Expand Up @@ -996,6 +1013,14 @@ mangle_exclusive_load(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
PRE(ilist, next_instr,
instr_create_restore_from_tls(dcontext, scratch_reg2, slot2));
}
if (uses_reg_tp) {
PRE(ilist, next_instr,
instr_create_save_to_tls(
dcontext, scratch_reg3,
os_tls_offset(os_get_app_tls_base_offset(TLS_REG_LIB))));
PRE(ilist, next_instr,
instr_create_restore_from_tls(dcontext, scratch_reg3, slot3));
}
return next_instr;
}

Expand All @@ -1021,8 +1046,8 @@ mangle_exclusive_store(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
dst1 = instr_get_dst(instr, 1);
ASSERT(opnd_is_base_disp(dst0));
opsz = instr_get_opcode(instr) == OP_sc_d ? OPSZ_8 : OPSZ_4;
scratch_reg1 = pick_scratch_reg(dcontext, instr, DR_REG_NULL, &slot1);
scratch_reg2 = pick_scratch_reg(dcontext, instr, scratch_reg1, &slot2);
scratch_reg1 = pick_scratch_reg(dcontext, instr, DR_REG_NULL, DR_REG_NULL, &slot1);
scratch_reg2 = pick_scratch_reg(dcontext, instr, scratch_reg1, DR_REG_NULL, &slot2);

/* Spill scratch registers. */
PRE(ilist, instr, instr_create_save_to_tls(dcontext, scratch_reg1, slot1));
Expand Down

0 comments on commit 57d9fe9

Please sign in to comment.