{
/* Number of bytes saved on the stack for local variables. */
int local_vars_size;
-
- /* Number of bytes saved on the stack for callee-saved
- registers. */
- int callee_saved_reg_size;
};
/* Handle an attribute requiring a FUNCTION_DECL;
bpf_compute_frame_layout (void)
{
int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
- int padding_locals, regno;
+ int padding_locals;
/* Set the space used in the stack by local variables. This is
rounded up to respect the minimum stack alignment. */
cfun->machine->local_vars_size += padding_locals;
- if (TARGET_XBPF)
- {
- /* Set the space used in the stack by callee-saved used
- registers in the current function. There is no need to round
- up, since the registers are all 8 bytes wide. */
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if ((df_regs_ever_live_p (regno)
- && !call_used_or_fixed_reg_p (regno))
- || (cfun->calls_alloca
- && regno == STACK_POINTER_REGNUM))
- cfun->machine->callee_saved_reg_size += 8;
- }
-
/* Check that the total size of the frame doesn't exceed the limit
imposed by eBPF. */
- if ((cfun->machine->local_vars_size
- + cfun->machine->callee_saved_reg_size) > bpf_frame_limit)
+ if (cfun->machine->local_vars_size > bpf_frame_limit)
{
static int stack_limit_exceeded = 0;
void
bpf_expand_prologue (void)
{
- HOST_WIDE_INT size;
-
- size = (cfun->machine->local_vars_size
- + cfun->machine->callee_saved_reg_size);
-
/* The BPF "hardware" provides a fresh new set of registers for each
called function, some of which are initialized to the values of
the arguments passed in the first five registers. In doing so,
- it saves the values of the registers of the caller, and restored
+ it saves the values of the registers of the caller, and restores
them upon returning. Therefore, there is no need to save the
- callee-saved registers here. What is worse, the kernel
- implementation refuses to run programs in which registers are
- referred before being initialized. */
- if (TARGET_XBPF)
- {
- int regno;
- int fp_offset = -cfun->machine->local_vars_size;
-
- /* Save callee-saved hard registes. The register-save-area
- starts right after the local variables. */
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- {
- if ((df_regs_ever_live_p (regno)
- && !call_used_or_fixed_reg_p (regno))
- || (cfun->calls_alloca
- && regno == STACK_POINTER_REGNUM))
- {
- rtx mem;
-
- if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff))
- /* This has been already reported as an error in
- bpf_compute_frame_layout. */
- break;
- else
- {
- mem = gen_frame_mem (DImode,
- plus_constant (DImode,
- hard_frame_pointer_rtx,
- fp_offset - 8));
- emit_move_insn (mem, gen_rtx_REG (DImode, regno));
- fp_offset -= 8;
- }
- }
- }
- }
-
- /* Set the stack pointer, if the function allocates space
- dynamically. Note that the value of %sp should be directly
- derived from %fp, for the kernel verifier to track it as a stack
- accessor. */
- if (cfun->calls_alloca)
- {
- emit_move_insn (stack_pointer_rtx,
- hard_frame_pointer_rtx);
-
- if (size > 0)
- {
- emit_insn (gen_rtx_SET (stack_pointer_rtx,
- gen_rtx_PLUS (Pmode,
- stack_pointer_rtx,
- GEN_INT (-size))));
- }
- }
+ callee-saved registers here. In fact, the kernel implementation
+ refuses to run programs in which registers are referred before
+ being initialized. */
+
+ /* BPF does not support functions that allocate stack space
+ dynamically. This should have been checked already and an error
+ emitted. */
+ gcc_assert (!cfun->calls_alloca);
}
/* Expand to the instructions in a function epilogue. This function
{
/* See note in bpf_expand_prologue for an explanation on why we are
not restoring callee-saved registers in BPF. */
- if (TARGET_XBPF)
- {
- int regno;
- int fp_offset = -cfun->machine->local_vars_size;
-
- /* Restore callee-saved hard registes from the stack. */
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- {
- if ((df_regs_ever_live_p (regno)
- && !call_used_or_fixed_reg_p (regno))
- || (cfun->calls_alloca
- && regno == STACK_POINTER_REGNUM))
- {
- rtx mem;
-
- if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff))
- /* This has been already reported as an error in
- bpf_compute_frame_layout. */
- break;
- else
- {
- mem = gen_frame_mem (DImode,
- plus_constant (DImode,
- hard_frame_pointer_rtx,
- fp_offset - 8));
- emit_move_insn (gen_rtx_REG (DImode, regno), mem);
- fp_offset -= 8;
- }
- }
- }
- }
emit_jump_insn (gen_exit ());
}
{
HOST_WIDE_INT ret;
- if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
- ret = (cfun->machine->local_vars_size
- + cfun->machine->callee_saved_reg_size);
- else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+ if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
ret = 0;
+ else if (from == STACK_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+ ret = -(cfun->machine->local_vars_size);
else
gcc_unreachable ();
#define BPF_R7 7
#define BPF_R8 8
#define BPF_R9 9
-#define BPF_SP BPF_R9
#define BPF_R10 10
#define BPF_FP BPF_R10
+#define BPF_R11 11
+#define BPF_R12 12
+#define BPF_SP BPF_R12
+
/* 11 is not a real eBPF hard register and is eliminated or not used
in the final assembler. See below. */
-#define FIRST_PSEUDO_REGISTER 12
+#define FIRST_PSEUDO_REGISTER 13
/* The registers %r0..%r8 are available for general allocation.
- %r9 is the pseudo-stack pointer.
%r10 is the stack frame, which is read-only.
- %r11 (__arg__) is a fake register that always gets eliminated. */
+ %r11 (__arg__) is a fake register that always gets eliminated.
+ %r12 is the pseudo-stack pointer that always gets eliminated. */
#define FIXED_REGISTERS \
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
/* %r0..%r5 are clobbered by function calls. */
#define CALL_USED_REGISTERS \
- {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1}
+ {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1}
/**** Register Classes. */
{ \
0x00000000, /* NO_REGS */ \
0x00000001, /* R0 */ \
- 0x00000fff, /* ALL_REGS */ \
+ 0x00001fff, /* ALL_REGS */ \
}
/* A C expression whose value is a register class containing hard
/*** Registers That Address the Stack Frame. */
#define FRAME_POINTER_REGNUM 10
-#define STACK_POINTER_REGNUM 9
#define ARG_POINTER_REGNUM 11
+#define STACK_POINTER_REGNUM 12
#define STATIC_CHAIN_REGNUM 8
/*** Registers elimination. */
#define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \
- { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }}
+ { STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM }}
/* Define the offset between two registers, one to be eliminated, and
the other its replacement, at the start of a routine. */
#define REGISTER_NAMES \
{ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \
- "%r8", "%r9", "%fp", "__arg__" }
+ "%r8", "%r9", "%fp", "__arg__", "__sp__" }
#define ADDITIONAL_REGISTER_NAMES \
{ { "%a", 0 }, { "%ctx", 6 }, { "%r10" , 10 } }
"{ja\t0|goto 0}"
[(set_attr "type" "alu")])
+;;;; Stack usage
+
+(define_expand "allocate_stack"
+ [(match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")]
+ ""
+ "
+{
+ error (\"BPF does not support dynamic stack allocation\");
+ emit_insn (gen_nop ());
+ DONE;
+}")
+
;;;; Arithmetic/Logical
;; The arithmetic and logic operations below are defined for SI and DI
--- /dev/null
+/* { dg-do compile } */
+
+int
+foo (int x)
+{
+ int *p = __builtin_alloca (x); /* { dg-error "support" } */
+
+ return p[2];
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+int
+foo (int x)
+{
+ int arr[x]; /* { dg-error "support" } */
+ return arr[3];
+}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+/* The purpose of this test is to make sure that registers r7, r8 and r9 are
+ available for register allocation. r9 used to be reserved as a stack
+ pointer but not any longer. */
+
+int bar ()
+{
+ int a, b, c = 10;
+
+ asm volatile ("#lala %[a] %[c]"
+ :
+ : [a]"r"(&a),
+ [b]"r"(&b),
+ [c]"r"(c)
+ : "r0", "r1", "r2", "r3", "r4", "r5", "memory", "r6"
+ );
+
+ return a + b + c;
+}
+++ /dev/null
-/* { dg-do compile } */
-/* { dg-options "-mxbpf" } */
-
-/* GCC should save and restore callee-saved registers when generating
- code for xBPF. */
-
-int
-foo ()
-{
- register int f asm ("r6");
-
- f = 20;
- return f + 1;
-}
-
-/* { dg-final { scan-assembler "stxdw\t\\\[%fp\\+-8\\\],%r6" } } */
-/* { dg-final { scan-assembler "ldxdw\t%r6,\\\[%fp\\+-8\\\]" } } */
+++ /dev/null
-/* { dg-do compile } */
-/* { dg-options "-mno-xbpf" } */
-
-/* GCC should not save and restore callee-saved registers unless
- generating code for xBPF. */
-
-int
-foo ()
-{
- register int f asm ("r6");
-
- f = 20;
- return f + 1;
-}
-
-/* { dg-final { scan-assembler-not "stxdw\t\\\[%fp\\+-8\\\],%r6" } } */
-/* { dg-final { scan-assembler-not "ldxdw\t%r6,\\\[%fp\\+-8\\\]" } } */
# Return 1 if alloca is supported, 0 otherwise.
proc check_effective_target_alloca {} {
+ if { [istarget bpf-*-*] } {
+ return 0
+ }
if { [istarget nvptx-*-*] } {
return [check_no_compiler_messages alloca assembly {
void f (void*);