Hi! On Sat, Jan 13, 2018 at 10:53:57PM -0600, Bill Schmidt wrote: > This patch adds a new option for the compiler to produce only "safe" indirect > jumps, in the sense that these jumps are deliberately mispredicted to inhibit > speculative execution. For now, this option is undocumented; this may change > at some future date. It is intended eventually for the linker to also honor > this flag when creating PLT stubs, for example.
I think we settled on calling the option -mmispredict-indirect-jumps; please let me know if you still agree with that. Or have thought of a better name :-) > In addition to the new option, I've included changes to indirect calls for > the ELFv2 ABI when the option is specified. In place of bctrl, we generate > a "crset eq" followed by a beqctrl-. Using the CR0.eq bit is safe since CR0 > is volatile over the call. And CR0 is unused by the call; compare to CR1 (on older ABIs) for example. > I've also added code to replace uses of bctr when the new option is specified, > with the sequence > > crset 4x[CRb]+2 > beqctr- CRb > b . > > where CRb is an available condition register field. This applies to all > subtargets, and in particular is not restricted to ELFv2. The use cases > covered here are computed gotos and switch statements. > > NOT yet covered by this patch: indirect calls for ELFv1. That will come > later. Would be nice to have it for all ABIs, even. > Please let me know if there is a better way to represent the crset without > an unspec. See the various patterns using cr%q. I'm not sure they can generate creqv (i.e. crset) currently, but that could be added (like crnot is there already, for example). If you don't use unspec (or maybe unspec_volatile) it can be optimised away though. Maybe it is best not to put the crset into its own insn, just make it part of the bigger pattern, with an appropriate clobber? > For the indirect jump, I don't see a way around it due to the > expected form of indirect jumps in cfganal.c. I'm not sure what you are getting at here, could you explain a bit? > (define_expand "indirect_jump" > - [(set (pc) (match_operand 0 "register_operand"))]) > + [(set (pc) (match_operand 0 "register_operand"))] > + "" > +{ > + /* We need to reserve a CR when forcing a mispredicted jump. */ > + if (rs6000_safe_indirect_jumps) { > + rtx ccreg = gen_reg_rtx (CCmode); > + emit_insn (gen_rtx_SET (ccreg, > + gen_rtx_UNSPEC (CCmode, > + gen_rtvec (1, const0_rtx), > + UNSPEC_CRSET_EQ))); > + rtvec v = rtvec_alloc (2); > + RTVEC_ELT (v, 0) = operands[0]; > + RTVEC_ELT (v, 1) = ccreg; > + emit_jump_insn (gen_rtx_SET (pc_rtx, > + gen_rtx_UNSPEC (Pmode, v, > + UNSPEC_COMP_GOTO_CR))); > + DONE; > + } > +}) > > (define_insn "*indirect_jump<mode>" > [(set (pc) > (match_operand:P 0 "register_operand" "c,*l"))] > - "" > + "!rs6000_safe_indirect_jumps" > "b%T0" > [(set_attr "type" "jmpreg")]) > > +(define_insn "*indirect_jump<mode>_safe" > + [(set (pc) > + (unspec:P [(match_operand:P 0 "register_operand" "c,*l") > + (match_operand:CC 1 "cc_reg_operand" "y,y")] > + UNSPEC_COMP_GOTO_CR))] > + "rs6000_safe_indirect_jumps" > + "beq%T0- %1\;b ." > + [(set_attr "type" "jmpreg") > + (set_attr "length" "8")]) > + > +(define_insn "*set_cr_eq" > + [(set (match_operand:CC 0 "cc_reg_operand" "=y") > + (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))] > + "rs6000_safe_indirect_jumps" > + "crset %E0" > + [(set_attr "type" "cr_logical")]) So merge this latter insn into the previous, making the CC a clobber? Like (not tested): +(define_insn "indirect_jump<mode>_mispredict" + [(set (pc) + (match_operand:P 0 "register_operand" "c,*l") + (clobber (match_operand:CC 1 "cc_reg_operand" "y,y"))] + "rs6000_safe_indirect_jumps" + "crset %E1\;beq%T0- %1\;b ." + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) and then change the indirect_jump pattern to simply select between the normal and mispredict patterns? > +(define_expand "tablejumpsi_safe" And then similar for tablejump. Segher