Это зависит от компилятора. И некоторые этапы в некоторых компиляторах не будут иметь соответствующих этапов в других компиляторах. Так что на ваш вопрос нет однозначного ответа.
Но обычно это делается после того, как дерево разбора для функции создано, но до того, как код фактически сгенерирован или выполнено много оптимизаций. Это наиболее оптимальное место для этого, потому что вы хотите, чтобы оптимизатор работал с максимальным объемом информации.
Делать это как макропроцессор препроцессора было бы вообще слишком рано. В этом случае у компилятора не будет достаточно информации, чтобы выполнить соответствующую проверку типов, а также проще делать ошибки, которые вызывают побочные эффекты более одного раза и т. Д.
И GMan предоставил отличную ссылку на Википедию в комментарии, в которой более подробно рассказывается о процессе вставки , чем я здесь. Мой ответ, как правило, верен, но вариантов очень много, даже больше, чем я думал.