aboutsummaryrefslogtreecommitdiff
path: root/src/helpers/function.S
blob: eeada7c6798a462db2d1442643511e79cea1687c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#ifndef __STDC_VERSION__

.set .L_FUNCTION_IS_IN_FUNCTION_DEFINITION, 0
.set .L_FUNCTION_LOCALS_ALLOCATED, 0

.macro _function_require_function
  .if .L_FUNCTION_IS_IN_FUNCTION_DEFINITION == 0
    .error "No active function definition."
  .endif
.endm

.macro _function_require_no_function
  .if .L_FUNCTION_IS_IN_FUNCTION_DEFINITION == 1
    .error "A function is already being defined."
  .endif
.endm

.macro _function_require_locals
  _function_require_function
  .if .L_FUNCTION_LOCALS_ALLOCATED == 0
    .error "Local variables have not been allocated."
  .endif
.endm

.macro _function_require_no_locals
  _function_require_function
  .if .L_FUNCTION_LOCALS_ALLOCATED == 1
    .error "Local variables have already been allocated."
  .endif
.endm

.macro _function_local_variable scope, name, size
  _function_require_function
  .set .L\scope\()_FRAME_OFFSET, .L\scope\()_FRAME_OFFSET + \size
  .equ .L\scope\()_\name\(), -.L\scope\()_FRAME_OFFSET
.endm

.macro _function_allocate_local_variables scope
  _function_require_no_locals
  .set .L_FUNCTION_LOCALS_ALLOCATED, 1
  .equ .L\scope\()_FRAME_SIZE, (.L\scope\()_FRAME_OFFSET + 15) & -16
  .if .L\scope\()_FRAME_SIZE > 0
    sub $.L\scope\()_FRAME_SIZE, %rsp
  .endif
.endm

.macro _function_load_local scope, name, register
  _function_require_locals
  mov .L\scope\()_\name\()(%rbp), \register
.endm

.macro _function_store_local scope, register, name
  _function_require_locals
  mov \register, .L\scope\()_\name\()(%rbp)
.endm

.macro _function_address_of_local scope, name, register
  _function_require_locals
  lea .L\scope\()_\name\()(%rbp), \register
.endm



.macro function_begin name
  _function_require_no_function

  .set .L_FUNCTION_IS_IN_FUNCTION_DEFINITION, 1
  .set .L_FUNCTION_LOCALS_ALLOCATED, 0

  .macro define_local var_name, var_size
    _function_local_variable \name, \var_name, \var_size
  .endm

  .macro allocate_locals
    _function_allocate_local_variables \name
  .endm

  .macro address_of_local var_name, register
    _function_address_of_local \name, \var_name, \register
  .endm

  .macro load_local var_name, register
    _function_load_local \name, \var_name, \register
  .endm

  .macro store_local register, var_name
    _function_store_local \name, \register, \var_name
  .endm

  .macro function_exit
    jmp .Lexit_\name
  .endm

  .macro function_end
    .if .L\name\()_FRAME_OFFSET > 0
      _function_require_locals
    .endif

    .Lexit_\name:
      leave
      .cfi_def_cfa %rsp, 8
      ret
      .cfi_endproc
      .size \name, .-\name
      .set .L_FUNCTION_IS_IN_FUNCTION_DEFINITION, 0
      .set .L_FUNCTION_LOCALS_ALLOCATED, 0
      .purgem allocate_locals
      .purgem address_of_local
      .purgem function_end
      .purgem function_exit
      .purgem load_local
      .purgem define_local
      .purgem store_local
  .endm

  .globl \name
  .type \name, @function
  \name:
    .cfi_startproc
    push %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    mov %rsp, %rbp
    .cfi_def_cfa_register %rbp
    .set .L\name\()_FRAME_OFFSET, 0
.endm

#endif