Ok.
Then I guess you can do something like Slang, which is used for the VM. Slang is a restrictive Smalltalk compiling to C.
The slang compiler parses the code using the Smalltalk Compiler parser, then translate the Smalltalk AST to its own AST, do some manipulation based on pragmas available in Slang methods and inlines different things based on a closed world (you can know what method is called at each send site) / frozen state assumptions (The value of literal variable will not change).
Some selectors are specifically mapped to C instructions / macros, for example #cppIf:ifTrue: maps to #IFDEF, or bitShift: maps to signed long bitShift. Comment are translated from Smalltalk to C and they are really useful.
Another interesting thing is that due to inlining part of the allocation / deallocation can be avoided.
You can't really use Slang directly as its implementation is tied with the VM (each time we have a slang bug in the vm code, we choose to either change the slang compiler or the slang code depending on how much work is each task).
I am not saying that slang is a nice language and that you should do something similar. Slang is horrible. But in the case of the VM is has some significant advantages over C++ and method templates.