Ignoring the merits of repeated function calls as a benchmark, this is surprisingly good. A naive scheme implementation I wrote was about 100X slower than Python. Since Arc hasn't yet plucked the low hanging fruit of optimization, I think you folks are fine.
What defmacro does is so simple and elegant. A macro is just a function than returns an expression. I wouldn't want to discard that simplicity in return for a solution to something I know from many years' experience is a non-problem.
Perhaps the pro-hygiene crowd needs to step up and tell us unhygienic types how long they have programmed with unhygienic macros and how often they have run afoul of variable capture. I am reminded of static/dynamic debates in which the pro-static crowd wants it to be taken as a given that it is better to have type errors detected at compile time. There is a prima facie compellingness to such assertions that may not pan out in practice, and at bottom the pro-safety crowd might just be imposing their (sorry) timidity on those of us who prefer to climb unroped in return for getting up the peak faster, which itself does more for safety when the climber is capable. uhoh, here comes my Reinhold Messner analogy....
I regard it more as a lexical binding/dynamic binding debate. DEFMACRO or MAC are like dynamic binding, because the meaning of a macro can be affected by local variable bindings surrounding its site of use, contrary to the intended meaning of the macro writer at the definition site.
I imagine a conservative purity analyzer wouldn't be too difficult to write. Mark a set of primitives as pure. An expression is pure if it is composed of pure primitives or other pure expressions. If an FFI is involved, you'll probably have to manually annotate foreign functions as pure or impure. How does that sound?
A purity analyzer would need to be a little more complex than that - the "=" operator would be pure or impure depending on the scope of the location being set. The simple way to solve that would be to make locations created within any lexical context that is discarded with the completion of the function pure and those without impure, although they may be slightly complicated.
Of course, some situations, such as code that sets unset values in an outside hash table to the default value, may arguably be "pure" functional code, although dealing with such things is outside the domain of a "conservative" purity analyzer.