case E_V4SFmode:
case E_V8SImode:
case E_V8SFmode:
+ case E_SImode:
fprintf (file, "w");
break;
case E_V2DImode:
case E_V2DFmode:
case E_V4DImode:
case E_V4DFmode:
+ case E_DImode:
fprintf (file, "d");
break;
default:
return feature_mask1 == feature_mask2;
}
+/* Output assembly to materialize the address of the stack canary value
+ into reg. The third argument, tmp, should be and should only be
+ non-NULL if the extreme code model is effective for the canary. If
+ the fourth arugment, load, is true, the canary value is loaded into
+ the register.
+
+ The assembly cannot be splitted due to security reason. */
+void
+loongarch_output_asm_load_canary (rtx reg, rtx canary, rtx tmp)
+{
+ gcc_checking_assert (ssp_operand (canary, VOIDmode));
+ gcc_checking_assert ((!tmp) == ssp_normal_operand (canary, VOIDmode));
+ gcc_checking_assert (register_operand (reg, Pmode));
+
+ rtx op[] = {reg, canary, tmp};
+ bool got = (loongarch_classify_symbol (canary) == SYMBOL_GOT_DISP);
+ bool need_ld = false;
+
+ if (la_opt_explicit_relocs != EXPLICIT_RELOCS_ALWAYS)
+ {
+ if (got)
+ output_asm_insn (tmp ? "la.global\t%0,%2,%1" : "la.global\t%0,%1",
+ op);
+ else
+ output_asm_insn (tmp ? "la.local\t%0,%2,%1" : "la.local\t%0,%1",
+ op);
+
+ need_ld = true;
+ }
+ else
+ {
+ output_asm_insn ("pcalau12i\t%0,%r1", op);
+ if (!tmp)
+ output_asm_insn ("ld.%v0\t%0,%0,%L1", op);
+ else
+ {
+ output_asm_insn ("addi.d\t%2,$r0,%L1", op);
+ output_asm_insn ("lu32i.d\t%2,%R1", op);
+ output_asm_insn ("lu52i.d\t%2,%2,%H1", op);
+ output_asm_insn ("ldx.d\t%0,%0,%2", op);
+ }
+
+ need_ld = got;
+ }
+
+ if (need_ld)
+ output_asm_insn ("ld.%v0\t%0,%0,0", op);
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
UNSPEC_LOAD_SYMBOL_OFFSET64
UNSPEC_LA_PCREL_64_PART1
UNSPEC_LA_PCREL_64_PART2
+
+ UNSPEC_SSP
])
(define_c_enum "unspecv" [
;; QImode values so we can force zero-extension.
(define_mode_iterator BR [(QI "TARGET_64BIT") SI (DI "TARGET_64BIT")])
-(define_expand "cbranch<mode>4"
+(define_expand "@cbranch<mode>4"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operand:BR 1 "register_operand")
operands[0] = loongarch_rewrite_mem_for_simple_ldst (operands[0]);
})
+;; Set and check against stack canary without leaving it in a register.
+;; DO NOT ATTEMPT TO SPLIT THESE INSNS! It's important for security reason
+;; that the canary value does not live beyond the life of this sequence.
+
+(define_insn "@stack_protect_combined_set_normal_<mode>"
+ [(set (match_operand:P 0 "memory_operand" "=m,ZC")
+ (unspec:P [(mem:P (match_operand:P 1 "ssp_normal_operand"))]
+ UNSPEC_SSP))
+ (set (match_scratch:P 2 "=&r,&r") (const_int 0))]
+ ""
+{
+ loongarch_output_asm_load_canary (operands[2], operands[1], NULL_RTX);
+ output_asm_insn (which_alternative ? "stptr.d\t%2,%0" : "st.d\t%2,%0",
+ operands);
+ return "ori\t%2,$r0,0";
+}
+ [(set_attr "type" "store")
+ (set_attr "length" "20")])
+
+(define_insn "@stack_protect_combined_set_extreme_<mode>"
+ [(set (match_operand:P 0 "memory_operand" "=m,ZC")
+ (unspec:P [(mem:P (match_operand:P 1 "ssp_operand"))] UNSPEC_SSP))
+ (set (match_scratch:P 2 "=&r,&r") (const_int 0))
+ (set (match_scratch:P 3 "=&r,&r") (const_int 0))]
+ ""
+{
+ loongarch_output_asm_load_canary (operands[2], operands[1], operands[3]);
+ output_asm_insn (which_alternative ? "stptr.d\t%2,%0" : "st.d\t%2,%0",
+ operands);
+ return "ori\t%2,$r0,0\n\tori\t%3,$r0,0";
+}
+ [(set_attr "type" "store")
+ (set_attr "length" "36")])
+
+(define_insn "@stack_protect_combined_test_internal_<mode>"
+ [(set (match_operand:P 0 "register_operand" "=r,r,&r,&r")
+ (xor:P
+ (match_operand:P 1 "memory_operand" "=m,ZC,m,ZC")
+ (unspec:P
+ [(mem:P (match_operand:P 2 "ssp_operand" "ZE,ZE,ZF,ZF"))]
+ UNSPEC_SSP)))
+ (set (match_scratch:P 3 "=&r,&r,&r,&r") (const_int 0))]
+ ""
+{
+ rtx t = (which_alternative >= 2 ? operands[0] : NULL_RTX);
+ loongarch_output_asm_load_canary (operands[3], operands[2], t);
+ output_asm_insn ((which_alternative & 1) ? "ldptr.d\t%0,%1"
+ : "ld.d\t%0,%1",
+ operands);
+ return "xor\t%0,%0,%3\n\tori\t%3,$r0,0";
+}
+ [(set_attr "type" "load,load,load,load")
+ (set_attr "length" "24,24,36,36")])
+
+(define_expand "stack_protect_combined_set"
+ [(match_operand 0 "memory_operand")
+ (match_operand 1 "memory_operand")]
+ ""
+{
+ rtx canary = XEXP (operands[1], 0);
+ auto fn = (ssp_normal_operand (canary, VOIDmode)
+ ? gen_stack_protect_combined_set_normal
+ : gen_stack_protect_combined_set_extreme);
+
+ emit_insn (fn (Pmode, operands[0], canary));
+ DONE;
+})
+
+(define_expand "stack_protect_combined_test"
+ [(match_operand 0 "memory_operand")
+ (match_operand 1 "memory_operand")
+ (match_operand 2 "")]
+ ""
+{
+ rtx t = gen_reg_rtx (Pmode);
+ rtx canary = XEXP (operands[1], 0);
+ emit_insn (gen_stack_protect_combined_test_internal (Pmode, t,
+ operands[0],
+ canary));
+ rtx cond = gen_rtx_EQ (VOIDmode, t, const0_rtx);
+ emit_jump_insn (gen_cbranch4 (Pmode, cond, t, const0_rtx, operands[2]));
+ DONE;
+})
+
;; Synchronization instructions.
(include "sync.md")