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
|
#define NUM_REGS 30
// Apply `macro` to "all" registers. Skip x18 since it's reserved, and x30 since
// it's the link register.
#define ALL_REGS(macro) \
macro( 0) \
macro( 1) \
macro( 2) \
macro( 3) \
macro( 4) \
macro( 5) \
macro( 6) \
macro( 7) \
macro( 8) \
macro( 9) \
macro(10) \
macro(11) \
macro(12) \
macro(13) \
macro(14) \
macro(15) \
macro(16) \
macro(17) \
macro(19) \
macro(20) \
macro(21) \
macro(22) \
macro(23) \
macro(24) \
macro(25) \
macro(26) \
macro(27) \
macro(28)
// Apply `macro` with the given parameters to all registers that have
// specialized entrypoints. That's the same as ALL_REGS, minus x0 (the standard
// entrypoint covers that), x16/x17 (temporary registers used as linker glue),
// and x29 (the link register).
#define FUNCTION_REGS(macro, ...) \
macro( 1, __VA_ARGS__) \
macro( 2, __VA_ARGS__) \
macro( 3, __VA_ARGS__) \
macro( 4, __VA_ARGS__) \
macro( 5, __VA_ARGS__) \
macro( 6, __VA_ARGS__) \
macro( 7, __VA_ARGS__) \
macro( 8, __VA_ARGS__) \
macro( 9, __VA_ARGS__) \
macro(10, __VA_ARGS__) \
macro(11, __VA_ARGS__) \
macro(12, __VA_ARGS__) \
macro(13, __VA_ARGS__) \
macro(14, __VA_ARGS__) \
macro(15, __VA_ARGS__) \
macro(19, __VA_ARGS__) \
macro(20, __VA_ARGS__) \
macro(21, __VA_ARGS__) \
macro(22, __VA_ARGS__) \
macro(23, __VA_ARGS__) \
macro(24, __VA_ARGS__) \
macro(25, __VA_ARGS__) \
macro(26, __VA_ARGS__) \
macro(27, __VA_ARGS__) \
macro(28, __VA_ARGS__)
// Apply `macro` to each function that gets specialized entrypoints. Also pass
// 1 if the function is a retain variant, and 0 if it's a release variant.
#define ALL_FUNCTIONS(macro) \
macro(swift_retain, 1) \
macro(swift_release, 0) \
macro(swift_bridgeObjectRetain, 1) \
macro(swift_bridgeObjectRelease, 0)
// Emit declarations for variables called xN stored in xN, initialized with
// regs[N].
#define PASS_REGS_HELPER(num) \
register void *x ## num asm ("x" #num) = regs[num];
#define PASS_REGS ALL_REGS(PASS_REGS_HELPER)
// Emit an entry in an asm inputs list containing "r" (xN).
#define REG_INPUTS_HELPER(num) \
"r" (x ## num),
#define REG_INPUTS ALL_REGS(REG_INPUTS_HELPER)
// Make a function called call_function_xN that calls function_xN with registers
// set to the contents of the given registers array.
#define MAKE_CALL_FUNC(reg, func) \
static inline void call_##func##_x##reg(void **regs) { \
PASS_REGS \
asm("bl _" #func "_x" #reg : : REG_INPUTS "i"(0)); \
}
// Make a call_function_xN for each specialized function and register.
#define MAKE_ALL_CALL_FUNCS(function, isRetain) \
FUNCTION_REGS(MAKE_CALL_FUNC, function)
ALL_FUNCTIONS(MAKE_ALL_CALL_FUNCS)
// Call `call` with each call_function_xN function created above, as well as the
// base function name, the register it operates on, and whether it's a retain
// function.
static inline void foreachRRFunction(void (*call)(void (*)(void **regs),
const char *name, int reg,
int isRetain)) {
#define CALL_ONE_FUNCTION(reg, function, isRetain) \
call(call_##function##_x##reg, #function, reg, isRetain);
#define CALL_WITH_FUNCTIONS(function, isRetain) \
FUNCTION_REGS(CALL_ONE_FUNCTION, function, isRetain)
ALL_FUNCTIONS(CALL_WITH_FUNCTIONS)
}
|