gcn: Add __builtin_gcn_{get_stack_limit,first_call_this_thread_p}
The new builtins have been added for newlib to reduce dependency on
compiler-internal implementation choices of GCC in newlibs' getreent.c.
gcc/ChangeLog:
* config/gcn/gcn-builtins.def (FIRST_CALL_THIS_THREAD_P,
GET_STACK_LIMIT): Add new builtins.
* config/gcn/gcn.cc (gcn_expand_builtin_1): Expand them.
* config/gcn/gcn.md (prologue_use): Add "register_operand" as
arg to match_operand.
(prologue_use_di): New; DI insn_and_split variant of the former.
Co-Authored-By: Andrew Stubbs <ams@codesourcery.com>
diff --git a/gcc/config/gcn/gcn-builtins.def b/gcc/config/gcn/gcn-builtins.def
index eeeaebf..f1cf30b 100644
--- a/gcc/config/gcn/gcn-builtins.def
+++ b/gcc/config/gcn/gcn-builtins.def
@@ -160,8 +160,12 @@
/* Kernel inputs. */
+DEF_BUILTIN (FIRST_CALL_THIS_THREAD_P, -1, "first_call_this_thread_p", B_INSN,
+ _A1 (GCN_BTI_BOOL), gcn_expand_builtin_1)
DEF_BUILTIN (KERNARG_PTR, -1, "kernarg_ptr", B_INSN, _A1 (GCN_BTI_VOIDPTR),
gcn_expand_builtin_1)
+DEF_BUILTIN (GET_STACK_LIMIT, -1, "get_stack_limit", B_INSN,
+ _A1 (GCN_BTI_VOIDPTR), gcn_expand_builtin_1)
#undef _A1
#undef _A2
diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc
index b3814c2..ea9631e 100644
--- a/gcc/config/gcn/gcn.cc
+++ b/gcc/config/gcn/gcn.cc
@@ -4493,6 +4493,45 @@
emit_insn (gen_gcn_wavefront_barrier ());
return target;
+ case GCN_BUILTIN_GET_STACK_LIMIT:
+ {
+ /* stackbase = (stack_segment_decr & 0x0000ffffffffffff)
+ + stack_wave_offset);
+ seg_size = dispatch_ptr->private_segment_size;
+ stacklimit = stackbase + seg_size*64;
+ with segsize = *(uint32_t *) ((char *) dispatch_ptr
+ + 6*sizeof(int16_t) + 3*sizeof(int32_t));
+ cf. struct hsa_kernel_dispatch_packet_s in the HSA doc. */
+ rtx ptr;
+ if (cfun->machine->args.reg[DISPATCH_PTR_ARG] >= 0
+ && cfun->machine->args.reg[PRIVATE_SEGMENT_BUFFER_ARG] >= 0)
+ {
+ rtx size_rtx = gen_rtx_REG (DImode,
+ cfun->machine->args.reg[DISPATCH_PTR_ARG]);
+ size_rtx = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (DImode, size_rtx,
+ GEN_INT (6*2 + 3*4)));
+ size_rtx = gen_rtx_MULT (SImode, size_rtx, GEN_INT (64));
+
+ ptr = gen_rtx_REG (DImode,
+ cfun->machine->args.reg[PRIVATE_SEGMENT_BUFFER_ARG]);
+ ptr = gen_rtx_AND (DImode, ptr, GEN_INT (0x0000ffffffffffff));
+ ptr = gen_rtx_PLUS (DImode, ptr, size_rtx);
+ if (cfun->machine->args.reg[PRIVATE_SEGMENT_WAVE_OFFSET_ARG] >= 0)
+ {
+ rtx off;
+ off = gen_rtx_REG (SImode,
+ cfun->machine->args.reg[PRIVATE_SEGMENT_WAVE_OFFSET_ARG]);
+ ptr = gen_rtx_PLUS (DImode, ptr, off);
+ }
+ }
+ else
+ {
+ ptr = gen_reg_rtx (DImode);
+ emit_move_insn (ptr, const0_rtx);
+ }
+ return ptr;
+ }
case GCN_BUILTIN_KERNARG_PTR:
{
rtx ptr;
@@ -4506,7 +4545,36 @@
}
return ptr;
}
-
+ case GCN_BUILTIN_FIRST_CALL_THIS_THREAD_P:
+ {
+ /* Stash a marker in the unused upper 16 bits of s[0:1] to indicate
+ whether it was the first call. */
+ rtx result = gen_reg_rtx (BImode);
+ emit_move_insn (result, const0_rtx);
+ if (cfun->machine->args.reg[PRIVATE_SEGMENT_BUFFER_ARG] >= 0)
+ {
+ rtx not_first = gen_label_rtx ();
+ rtx reg = gen_rtx_REG (DImode,
+ cfun->machine->args.reg[PRIVATE_SEGMENT_BUFFER_ARG]);
+ rtx cmp = force_reg (DImode,
+ gen_rtx_LSHIFTRT (DImode, reg, GEN_INT (48)));
+ emit_insn (gen_cstoresi4 (result, gen_rtx_NE (BImode, cmp,
+ GEN_INT(12345)),
+ cmp, GEN_INT(12345)));
+ emit_jump_insn (gen_cjump (not_first, gen_rtx_EQ (BImode, result,
+ const0_rtx),
+ result));
+ emit_move_insn (reg,
+ force_reg (DImode,
+ gen_rtx_IOR (DImode,
+ gen_rtx_AND (DImode, reg,
+ GEN_INT (0x0000ffffffffffffL)),
+ GEN_INT (12345L << 48))));
+ emit_insn (gen_prologue_use (reg));
+ emit_label (not_first);
+ }
+ return result;
+ }
default:
gcc_unreachable ();
}
diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md
index 987b763..a8b9c28 100644
--- a/gcc/config/gcn/gcn.md
+++ b/gcc/config/gcn/gcn.md
@@ -692,11 +692,24 @@
;; {{{ Prologue/Epilogue
(define_insn "prologue_use"
- [(unspec_volatile [(match_operand 0)] UNSPECV_PROLOGUE_USE)]
+ [(unspec_volatile [(match_operand 0 "register_operand")] UNSPECV_PROLOGUE_USE)]
""
""
[(set_attr "length" "0")])
+(define_insn_and_split "prologue_use_di"
+ [(unspec_volatile [(match_operand:DI 0 "register_operand")] UNSPECV_PROLOGUE_USE)]
+ ""
+ "#"
+ "reload_completed"
+ [(unspec_volatile [(match_dup 0)] UNSPECV_PROLOGUE_USE)
+ (unspec_volatile [(match_dup 1)] UNSPECV_PROLOGUE_USE)]
+ {
+ operands[1] = gcn_operand_part (DImode, operands[0], 1);
+ operands[0] = gcn_operand_part (DImode, operands[0], 0);
+ }
+ [(set_attr "length" "0")])
+
(define_expand "prologue"
[(const_int 0)]
""