Thanks to Leo and Chip's hard work, the multi-step compilation strategy of Exp->PAST->PIR->PBC paid off, with lots of help from WriterT/ReaderT/GADT/Fundep and other constructs.
This generates, according to Leo, 100% correct PIR code:
% ./pugs -C PIR -e 'say "Hello, World!"' % parrot dump.ast Hello, World!
Also because it's now a Proper Compiler, we have nice compile-time warnings too:
% ./pugs -C PIR -e '"Hello, World!"' *** Literal value used in constant expression: VStr "Hello, World!"
Just for the record, the PIR code generated by say "Hello, World" looks like this:
.namespace ['main']
.sub main @MAIN
    new_pad 0
    #line "" 1
    $P100 = new .PerlUndef
    $P100 = "Hello, World!"
    $P0 = find_name "&say"
    set_args '(0)', $P100
    invokecc $P0
.end
 
With the two relevant primitives at the top (but can also be autoloaded, etc):
.sub "&print"
    get_params '(0b1000)', $P0
    $S0 = join '', $P0
    print $S0
.end
.sub "&say"
    get_params '(0b1000)', $P0
    $P1 = find_name '&print'
    set_args '(0b1000)', $P0
    invokecc $P1
    print "\n"
.end
Not bad for one day's coding work. :-)
However, with constrained subtypes, junctive activation, parameterised roles, default parameter expressions that refers to previously bound variables etc, I have fully abandoned this "Perl 6 is just a thin wrapper over Parrot; a compiler is just a pretty-printing parser" notion.
The scarily high irregularity in PIR (there are seven different meaning of expr = expr, for example) made establishing an AST a very unenviable task, and most of time today is spent on it.  Fortunately, the attempt to add types to PIR paid off, and Leo/Chip are aggresively eliminating those obsolete and/or plain wrong constructs.
But still, we 1)survived 2)made it work. Can't ask for more!