## translate-treecode-to-machcode-pwrpc32-g.pkg
#
# CONTEXT:
#
# The Mythryl compiler code representations used are, in order:
#
# 1) Raw Syntax is the initial frontend code representation.
# 2) Deep Syntax is the second and final frontend code representation.
# 3) Lambdacode (polymorphically typed lambda calculus) is the first backend code representation, used only transitionally.
# 4) Anormcode (A-Normal format, which preserves expression tree structure) is the second backend code representation, and the first used for optimization.
# 5) Nextcode ("continuation-passing style", a single-assignment basic-block-graph form where call and return are essentially the same) is the third and chief backend tophalf code representation.
# 6) Treecode is the backend tophalf/lowhalf transitional code representation. It is typically slightly specialized for each target architecture, e.g. Intel32 (x86).
# 7) Machcode abstracts the target architecture machine instructions. It gets specialized for each target architecture.
# 8) Execode is absolute executable binary machine instructions for the target architecture.
#
# For general context, see
#
# src/A.COMPILER-PASSES.OVERVIEW
#
# This module implements translation from Treecode to
# abstract PWRPC32 machine instructions. This is essentially
# an instruction selection task.
#
# Our runtime invocation is from
#
#
src/lib/compiler/back/low/main/main/translate-nextcode-to-treecode-g.pkg# Compiled by:
#
src/lib/compiler/back/low/pwrpc32/backend-pwrpc32.lib# I've substantially modified this code generator to support the new Treecode.
#
# -- Allen Leung
# We are invoked from:
#
#
src/lib/compiler/back/low/main/pwrpc32/backend-lowhalf-pwrpc32.pkg#DO set_control "compiler::trap_int_overflow" "TRUE";
stipulate
package lbl = codelabel; # codelabel is from
src/lib/compiler/back/low/code/codelabel.pkg package lem = lowhalf_error_message; # lowhalf_error_message is from
src/lib/compiler/back/low/control/lowhalf-error-message.pkg package rkj = registerkinds_junk; # registerkinds_junk is from
src/lib/compiler/back/low/code/registerkinds-junk.pkg package tcp = treecode_pith; # treecode_pith is from
src/lib/compiler/back/low/treecode/treecode-pith.pkg package w32 = one_word_unt; # one_word_unt is from
src/lib/std/one-word-unt.pkgherein
generic package translate_treecode_to_machcode_pwrpc32_g (
#
package mcf: Machcode_Pwrpc32; # Machcode_Pwrpc32 is from
src/lib/compiler/back/low/pwrpc32/code/machcode-pwrpc32.codemade.api package pop: Pseudo_Instructions_Pwrpc32 # Pseudo_Instructions_Pwrpc32 is from
src/lib/compiler/back/low/pwrpc32/treecode/pseudo-instructions-pwrpc32.api where # "pop" == "pseudo_instructions".
mcf == mcf; # "mcf" == "machcode_form" (abstract machine code).
package txc
: Treecode_Extension_Compiler # Treecode_Extension_Compiler is from
src/lib/compiler/back/low/treecode/treecode-extension-compiler.api where # "txc" == "treecode_extension_compiler".
mcf == mcf # "mcf" == "machcode_form" (abstract machine code).
also tcf == mcf::tcf; # "tcf" == "treecode_form".
# Support 64 bit mode?
# This should be set to FALSE for Mythryl #
#
bit64mode: Bool; # 64-bit issue
#
# Cost of multiplication in cycles
mult_cost: Ref( Int );
)
: (weak) Translate_Treecode_To_Machcode # Translate_Treecode_To_Machcode is from
src/lib/compiler/back/low/treecode/translate-treecode-to-machcode.api {
# Export to client packages:
#
package tcs = txc::tcs; # "tcs" == "treecode_stream".
package mcf = mcf; # "mcf" == "machcode_form" (abstract machine code).
package mcg = txc::mcg; # "mcg" == "machcode_controlflow_graph".
stipulate
package tcf = mcf::tcf; # "tcf" == "treecode_form".
package rgk = mcf::rgk; # "rgk" == "registerkinds".
package lcn = lowhalf_notes; # lowhalf_notes is from
src/lib/compiler/back/low/code/lowhalf-notes.pkg herein
fun error msg
=
lem::error("translate_treecode_to_machcode_pwrpc32_g", msg);
Codebuffer = tcs::Treecode_Codebuffer (mcf::Machine_Op, rkj::cls::Codetemplists, mcg::Machcode_Controlflow_Graph);
Treecode_Codebuffer = tcs::Treecode_Codebuffer (tcf::Void_Expression, List(tcf::Expression), mcg::Machcode_Controlflow_Graph);
my (int_width, natural_widths)
=
if bit64mode (64,[32, 64]);
else (32,[32 ]);
fi;
package tct # Exported to client packages.
=
treecode_transforms_g ( # treecode_transforms_g is from
src/lib/compiler/back/low/treecode/treecode-transforms-g.pkg #
package tcf = tcf;
package rgk = rgk;
#
int_bitsize = int_width;
natural_widths = natural_widths;
#
Rep = SE
| ZE | NEITHER;
rep = NEITHER;
);
#########################
# Special instructions
fun mtlr r = mcf::MTSPR { rs=>r, spr=>rgk::lr };
fun mflr r = mcf::MFSPR { rt=>r, spr=>rgk::lr };
cr0 = rgk::get_ith_hardware_register_of_kind rkj::FLAGS_REGISTER 0;
ret = mcf::BCLR { bo=>mcf::ALWAYS, bf=>cr0, bit=>mcf::LT, lk=>FALSE, labels => [] };
fun slli32 { r, i, d }
=
mcf::ROTATEI { oper=>mcf::RLWINM, ra=>d, rs=>r, sh=>mcf::IMMED_OP i, mb=>0, me=>THE (31-i) };
fun srli32 { r, i, d }
=
mcf::ROTATEI { oper=>mcf::RLWINM, ra=>d, rs=>r, sh=>mcf::IMMED_OP (int::(%) (32-i, 32)), mb=>i, me=>THE (31) };
fun copy' { dst, src, tmp }
=
mcf::COPY { kind => rkj::INT_REGISTER, size_in_bits => 32, dst, src, tmp };
fun fcopy' { dst, src, tmp }
=
mcf::COPY { kind => rkj::FLOAT_REGISTER, size_in_bits => 64, dst, src, tmp };
#########################
# Integer multiplication
#
generic package multiply32_g
=
stipulate
package rkj = registerkinds_junk; # registerkinds_junk is from
src/lib/compiler/back/low/code/registerkinds-junk.pkg herein
treecode_mult_g ( # treecode_mult_g is from
src/lib/compiler/back/low/treecode/treecode-mult-g.pkg #
package mcf = mcf;
package tcf = tcf;
#
int_width = 32;
#
Arg = { r1: rkj::Codetemp_Info, r2: rkj::Codetemp_Info, d: rkj::Codetemp_Info };
Argi = { r: rkj::Codetemp_Info, i: Int, d: rkj::Codetemp_Info };
#
fun mov { r, d } = copy' { dst => [d], src => [r], tmp=>NULL };
fun add { r1, r2, d } = mcf::arith { oper=>mcf::ADD, ra=>r1, rb=>r2, rt=>d, rc=>FALSE, oe=>FALSE };
#
fun slli { r, i, d } = [mcf::BASE_OP (slli32 { r, i, d } )];
fun srli { r, i, d } = [mcf::BASE_OP (srli32 { r, i, d } )];
#
fun srai { r, i, d } = [mcf::arithi { oper=>mcf::SRAWI, rt=>d, ra=>r, im=>mcf::IMMED_OP i } ];
)
end;
package mulu32 = multiply32_g
(trapping = FALSE;
mult_cost = mult_cost;
fun addv { r1, r2, d } =[mcf::arith { oper=>mcf::ADD, ra=>r1, rb=>r2, rt=>d, rc=>FALSE, oe=>FALSE } ];
fun subv { r1, r2, d } =[mcf::arith { oper=>mcf::SUBF, ra=>r2, rb=>r1, rt=>d, rc=>FALSE, oe=>FALSE } ];
sh1addv = NULL;
sh2addv = NULL;
sh3addv = NULL;
)
(signed = FALSE;);
package muls32 = multiply32_g
(trapping = FALSE;
mult_cost = mult_cost;
fun addv { r1, r2, d } =[mcf::arith { oper=>mcf::ADD, ra=>r1, rb=>r2, rt=>d, rc=>FALSE, oe=>FALSE } ];
fun subv { r1, r2, d } =[mcf::arith { oper=>mcf::SUBF, ra=>r2, rb=>r1, rt=>d, rc=>FALSE, oe=>FALSE } ];
sh1addv = NULL;
sh2addv = NULL;
sh3addv = NULL;
)
(signed = TRUE;);
package mult32 = multiply32_g
(trapping = TRUE;
mult_cost = mult_cost;
fun addv { r1, r2, d } = error "Mult32::addv";
fun subv { r1, r2, d } = error "Mult32::subv";
sh1addv = NULL;
sh2addv = NULL;
sh3addv = NULL;
)
(signed = TRUE;);
fun make_treecode_to_machcode_codebuffer
#
buf
#
# 'buf' is our interface to
#
#
src/lib/compiler/back/low/mcg/make-machcode-codebuffer-g.pkg #
# which constructs a machine-code graph driven by our 'put commands:
# basically we do a lot of
#
# buf.put_op
#
# calls to construct the graph and then one
#
# resultgraph = buf.get_completed_cccomponent
#
# call to get the resulting machcode controlflow graph.
=
{ put_base_op = buf.put_op o mcf::BASE_OP;
# Annotate an instruction:
#
fun annotate (op, []) => op;
annotate (op, note ! notes) => annotate (mcf::NOTE { op, note }, notes);
end;
fun mark'(instruction, notes) = buf.put_op (annotate (instruction, notes));
fun mark (instruction, notes) = buf.put_op (annotate (mcf::BASE_OP instruction, notes));
# Label where trap is generated.
# For overflow trapping instructions, we generate a branch
# to this label.
my trap_label: Ref( Null_Or( lbl::Codelabel ) ) = REF NULL;
zero_r = rgk::r0;
issue_int_codetemp = rgk::make_int_codetemp_info;
issue_float_codetemp = rgk::make_float_codetemp_info;
make_flag_codetemp = rgk::make_codetemp_info_of_kind rkj::FLAGS_REGISTER;
fun lt (x, y) = tcf::mi::lt (32, x, y);
fun le (x, y) = tcf::mi::le (32, x, y);
fun to_int mi = tcf::mi::to_int (32, mi);
fun li i = tcf::mi::from_int (32, i);
fun signed16 mi = le(-0x8000, mi) and lt (mi, 0x8000);
fun signed12 mi = le(-0x800, mi) and lt (mi, 0x800);
fun unsigned16 mi = le (0, mi) and lt (mi, 0x10000);
fun unsigned5 mi = le (0, mi) and lt (mi, 32);
fun unsigned6 mi = le (0, mi) and lt (mi, 64);
fun move (rs, rd, notes)
=
if (not (rkj::codetemps_are_same_color (rs, rd)))
#
mark'(copy' { dst => [rd], src => [rs], tmp=>NULL }, notes);
fi;
fun fmove (fs, fd, notes)
=
if (not (rkj::codetemps_are_same_color (fs, fd)))
#
mark' (fcopy' { dst => [fd], src => [fs], tmp => NULL }, notes);
fi;
fun ccmove (ccs, ccd, notes)
=
if (not (rkj::codetemps_are_same_color (ccd, ccs)))
#
mark (mcf::MCRF { bf=>ccd, bfa=>ccs }, notes);
fi;
fun copy (dst, src, notes)
=
mark'( copy' { dst, src,
tmp => case dst [_] => NULL;
_ => THE (mcf::DIRECT (issue_int_codetemp ()));
esac
},
notes
);
fun fcopy (dst, src, notes)
=
mark' ( fcopy' { dst, src,
tmp=>case dst [_] => NULL;
_ => THE (mcf::FDIRECT (issue_float_codetemp()));
esac
},
notes
);
fun put_branch { bo, bf, bit, address, lk }
=
{ fall_thr_lab = lbl::make_anonymous_codelabel();
fall_thr_operand = mcf::LABEL_OP (tcf::LABEL fall_thr_lab);
put_base_op (mcf::BC { bo, bf, bit, address, lk, fall=>fall_thr_operand } );
buf.put_private_label fall_thr_lab;
};
fun split n
=
{ wtoi = one_word_unt::to_int_x;
w = tcf::mi::to_unt1 (32, n);
hi = w32::(>>>) (w, 0u16);
lo = w32::bitwise_and (w, 0u65535);
my (high, low)
=
if (w32::(<) (lo, 0u32768)) (hi, lo);
else (hi+0u1, lo - 0u65536);
fi;
(wtoi high, wtoi low);
};
fun load_immed_hi_lo (0, lo, rt, notes)
=>
mark (mcf::ARITHI { oper=>mcf::ADDI, rt, ra=>zero_r, im=>mcf::IMMED_OP lo }, notes);
load_immed_hi_lo (hi, lo, rt, notes)
=>
{ mark (mcf::ARITHI { oper=>mcf::ADDIS, rt, ra=>zero_r, im=>mcf::IMMED_OP hi }, notes);
if (lo != 0)
#
put_base_op (mcf::ARITHI { oper=>mcf::ADDI, rt, ra=>rt, im=>mcf::IMMED_OP lo } );
fi;
};
end;
fun load_immed (n, rt, notes)
=
if (signed16 n)
mark (mcf::ARITHI { oper=>mcf::ADDI, rt, ra=>zero_r, im=>mcf::IMMED_OP (to_int (n)) }, notes);
else
my (hi, lo) = split n;
load_immed_hi_lo (hi, lo, rt, notes);
fi;
fun load_label_expression (lambda_expression, rt, notes)
=
mark (mcf::ARITHI { oper=>mcf::ADDI, rt, ra=>zero_r, im=>mcf::LABEL_OP lambda_expression }, notes);
fun immed_operand range (e1, e2 as tcf::LITERAL i)
=>
(expr e1, if (range i ) mcf::IMMED_OP (to_int i); else mcf::REG_OP (expr e2);fi);
immed_operand _ (e1, x as tcf::LATE_CONSTANT _) => (expr e1, mcf::LABEL_OP x);
immed_operand _ (e1, x as tcf::LABEL _) => (expr e1, mcf::LABEL_OP x);
immed_operand _ (e1, tcf::LABEL_EXPRESSION lambda_expression)
=>
(expr e1, mcf::LABEL_OP lambda_expression);
immed_operand _ (e1, e2)
=>
(expr e1, mcf::REG_OP (expr e2));
end
also
fun comm_immed_operand range (e1 as tcf::LITERAL _, e2)
=>
immed_operand range (e2, e1);
comm_immed_operand range (e1 as tcf::LATE_CONSTANT _, e2)
=>
immed_operand range (e2, e1);
comm_immed_operand range (e1 as tcf::LABEL _, e2)
=>
immed_operand range (e2, e1);
comm_immed_operand range (e1 as tcf::LABEL_EXPRESSION _, e2)
=>
immed_operand range (e2, e1);
comm_immed_operand range arg
=>
immed_operand range arg;
end
also
fun e_comm_imm range (oper, operi, e1, e2, rt, notes)
=
case (comm_immed_operand range (e1, e2))
(ra, mcf::REG_OP rb)
=>
mark (mcf::ARITH { oper, ra, rb, rt, rc=>FALSE, oe=>FALSE }, notes);
(ra, operand)
=>
mark (mcf::ARITHI { oper=>operi, ra, im=>operand, rt }, notes);
esac
# Compute a base/displacement effective address
#
also
fun address (size, tcf::ADD(_, e, tcf::LITERAL i))
=>
{ ra = expr e;
if (size i)
(ra, mcf::IMMED_OP (to_int i));
else
my (hi, lo) = split i;
tmp_r = issue_int_codetemp ();
put_base_op (mcf::ARITHI { oper=>mcf::ADDIS, rt=>tmp_r, ra, im=>mcf::IMMED_OP hi } );
(tmp_r, mcf::IMMED_OP lo);
fi;
};
address (size, tcf::ADD (type, tcf::LITERAL i, e))
=>
address (size, tcf::ADD (type, e, tcf::LITERAL i));
address (size, expression as tcf::SUB (type, e, tcf::LITERAL i))
=>
(address (size, tcf::ADD (type, e, tcf::LITERAL (tcf::mi::negt (32, i))))
except
OVERFLOW = (expr expression, mcf::IMMED_OP 0));
address (size, tcf::ADD(_, e1, e2))
=>
(expr e1, mcf::REG_OP (expr e2));
address (size, e)
=>
(expr e, mcf::IMMED_OP 0);
end
# Convert lowhalf to registerset:
also
fun registerset lowhalf
=
g (lowhalf, rgk::empty_codetemplists)
where
add_ccreg = rkj::cls::add_codetemp_to_appropriate_kindlist;
fun g ([], acc) => acc;
#
g (tcf::INT_EXPRESSION (tcf::CODETEMP_INFO (_, r)) ! regs, acc) => g (regs, rgk::add_codetemp_info_to_appropriate_kindlist (r, acc));
g (tcf::FLOAT_EXPRESSION (tcf::CODETEMP_INFO_FLOAT(_, f)) ! regs, acc) => g (regs, rgk::add_codetemp_info_to_appropriate_kindlist (f, acc));
#
g (tcf::FLAG_EXPRESSION (tcf::CC (_, cc)) ! regs, acc) => g (regs, add_ccreg (cc, acc)); # "cc" is "condition code" -- zero/parity/overflow/... flag stuff.
g (tcf::FLAG_EXPRESSION (tcf::FCC(_, cc)) ! regs, acc) => g (regs, add_ccreg (cc, acc));
#
g(_ ! regs, acc) => g (regs, acc);
end;
end
# Translate a void_expression, and annotate it
#
also
fun void_expression (tcf::LOAD_INT_REGISTER(_, rd, e), notes) => do_expr (e, rd, notes);
void_expression (tcf::LOAD_FLOAT_REGISTER(_, fd, e), notes) => do_float_expression (e, fd, notes);
void_expression (tcf::LOAD_INT_REGISTER_FROM_FLAGS_REGISTER (ccd, flag_expression), notes) => do_flag_expression (flag_expression, ccd, notes);
void_expression (tcf::MOVE_INT_REGISTERS(_, dst, src), notes) => copy (dst, src, notes);
void_expression (tcf::MOVE_FLOAT_REGISTERS(_, dst, src), notes) => fcopy (dst, src, notes);
void_expression (tcf::GOTO (tcf::LABEL_EXPRESSION lambda_expression, labs), notes)
=>
mark (mcf::BB { address=>mcf::LABEL_OP lambda_expression, lk=>FALSE }, notes);
void_expression (tcf::GOTO (x as (tcf::LABEL _
| tcf::LATE_CONSTANT _), labs), notes)
=>
mark (mcf::BB { address=>mcf::LABEL_OP x, lk=>FALSE }, notes);
void_expression (tcf::GOTO (int_expression, labs), notes)
=>
{ rs = expr (int_expression);
put_base_op (mtlr (rs));
mark (mcf::BCLR { bo=>mcf::ALWAYS, bf=>cr0, bit=>mcf::LT, lk=>FALSE, labels=>labs }, notes);
};
void_expression (tcf::CALL { funct, targets, defs, uses, region, pops, ... }, notes)
=>
call (funct, targets, defs, uses, region, [], notes, pops);
void_expression (tcf::FLOW_TO (tcf::CALL { funct, targets, defs, uses, region, pops, ... },
cut_to), notes) =>
call (funct, targets, defs, uses, region, cut_to, notes, pops);
void_expression (tcf::RET flow, notes) => mark (ret, notes);
void_expression (tcf::STORE_INT (type, ea, data, mem), notes) => store (type, ea, data, mem, notes);
void_expression (tcf::STORE_FLOAT (type, ea, data, mem), notes) => fstore (type, ea, data, mem, notes);
void_expression (tcf::IF_GOTO (cc, lab), notes) => branch (cc, lab, notes);
void_expression (tcf::DEFINE l, _) => buf.put_private_label l;
void_expression (tcf::LIVE s, notes) => mark'(mcf::LIVE { regs=>registerset s, spilled=>rgk::empty_codetemplists }, notes);
void_expression (tcf::DEAD s, notes) => mark'(mcf::DEAD { regs=>registerset s, spilled=>rgk::empty_codetemplists }, notes);
void_expression (tcf::NOTE (s, a), notes) => void_expression (s, a ! notes);
void_expression (tcf::EXT s, notes) => txc::compile_sext (reducer()) { void_expression=>s, notes };
void_expression (s, _) => do_stmts (tct::compile_void_expression s);
end
also
fun call (funct, targets, defs, uses, ramregion, cuts_to, notes, 0)
=>
{ defs = registerset (defs);
uses = registerset (uses);
put_base_op (mtlr (expr funct));
mark (mcf::CALL { def=>defs, uses, cuts_to, ramregion }, notes);
};
call _
=>
error "pops!=0 not implemented";
end
also
fun branch (tcf::CMP(_, _, tcf::LITERAL _, tcf::LITERAL _), _, _) => error "branch (LITERAL, LITERAL)";
branch (tcf::CMP (type, cc, e1 as tcf::LITERAL _, e2), lab, notes)
=>
{ cc' = tcp::swap_cond cc;
branch (tcf::CMP (type, cc', e2, e1), lab, notes);
};
branch (cmp as tcf::CMP (type, cond, e1, e2), lab, notes)
=>
{ my (bo, cf)
=
case cond
#
tcf::LT => (mcf::TRUE, mcf::LT);
tcf::LE => (mcf::FALSE, mcf::GT);
tcf::EQ => (mcf::TRUE, mcf::EQ);
tcf::NE => (mcf::FALSE, mcf::EQ);
tcf::GT => (mcf::TRUE, mcf::GT);
tcf::GE => (mcf::FALSE, mcf::LT);
tcf::LTU => (mcf::TRUE, mcf::LT);
tcf::LEU => (mcf::FALSE, mcf::GT);
tcf::GTU => (mcf::TRUE, mcf::GT);
tcf::GEU => (mcf::FALSE, mcf::LT);
#
(tcf::SETCC
| tcf::MISC_COND _) => error "branch (CMP)";
esac;
ccreg = if TRUE cr0;
else make_flag_codetemp();
fi; # XXX
address = mcf::LABEL_OP (tcf::LABEL lab);
fun default ()
=
{ do_flag_expression (cmp, ccreg, []);
put_branch { bo, bf=>ccreg, bit=>cf, address, lk=>FALSE };
};
case (e1, e2)
(tcf::BITWISE_AND(_, a1, a2), tcf::LITERAL z)
=>
if (z == 0 )
case (comm_immed_operand unsigned16 (a1, a2))
(ra, mcf::REG_OP rb)
=>
put_base_op (mcf::ARITH { oper=>mcf::AND, ra, rb, rt=>issue_int_codetemp (), rc=>TRUE, oe=>FALSE } );
(ra, operand)
=>
put_base_op (mcf::ARITHI { oper=>mcf::ANDI_RC, ra, im=>operand, rt=>issue_int_codetemp () } );
esac;
branch (tcf::CC (cond, cr0), lab, notes);
else
default();
fi;
_ => default();
esac;
};
branch (tcf::CC (cc, cr), lab, notes)
=>
{ address=mcf::LABEL_OP (tcf::LABEL lab);
fun branch (bo, bit)
=
put_branch { bo, bf=>cr, bit, address, lk=>FALSE };
case cc
tcf::EQ => branch (mcf::TRUE, mcf::EQ);
tcf::NE => branch (mcf::FALSE, mcf::EQ);
(tcf::LT
| tcf::LTU) => branch (mcf::TRUE, mcf::LT);
(tcf::LE
| tcf::LEU) => branch (mcf::FALSE, mcf::GT);
(tcf::GE
| tcf::GEU) => branch (mcf::FALSE, mcf::LT);
(tcf::GT
| tcf::GTU) => branch (mcf::TRUE, mcf::GT);
(tcf::SETCC
| tcf::MISC_COND _) => error "branch (CC)";
esac;
};
branch (cmp as tcf::FCMP (fty, cond, _, _), lab, notes)
=>
{ ccreg = if TRUE cr0;
else make_flag_codetemp();
fi; # XXX
lab_op = mcf::LABEL_OP (tcf::LABEL lab);
fun branch (bo, bf, bit)
=
put_branch { bo, bf, bit, address=>lab_op, lk=>FALSE };
fun test2bits (bit1, bit2)
=
{ ba=(ccreg, bit1);
bb=(ccreg, bit2);
bt=(ccreg, mcf::FL);
put_base_op (mcf::CCARITH { oper=>mcf::CROR, bt, ba, bb } );
branch (mcf::TRUE, ccreg, mcf::FL);
};
do_flag_expression (cmp, ccreg, []);
case cond
#
tcf::FEQ => branch (mcf::TRUE, ccreg, mcf::FE);
tcf::FNEU => branch (mcf::FALSE, ccreg, mcf::FE);
tcf::FUO => branch (mcf::TRUE, ccreg, mcf::FU);
tcf::FGLE => branch (mcf::FALSE, ccreg, mcf::FU);
tcf::FGT => branch (mcf::TRUE, ccreg, mcf::FG);
tcf::FGE => test2bits (mcf::FG, mcf::FE);
tcf::FGTU => test2bits (mcf::FU, mcf::FG);
tcf::FGEU => branch (mcf::FALSE, ccreg, mcf::FL);
tcf::FLT => branch (mcf::TRUE, ccreg, mcf::FL);
tcf::FLE => test2bits (mcf::FL, mcf::FE);
tcf::FLTU => test2bits (mcf::FU, mcf::FL);
tcf::FLEU => branch (mcf::FALSE, ccreg, mcf::FG);
tcf::FNE => test2bits (mcf::FL, mcf::FG);
tcf::FEQU => test2bits (mcf::FU, mcf::FE);
(tcf::SETFCC
| tcf::MISC_FCOND _) => error "branch (FCMP)";
esac;
};
branch _ => error "branch";
end
also
fun do_void_expression s
=
void_expression (s,[])
also
fun do_stmts ss
=
apply do_void_expression ss
# Emit an integer store:
#
also
fun store (type, ea, data, ramregion, notes)
=
{ my (st, size)
=
case (type, tct::tsz::size ea)
#
(8, 32) => (mcf::STB, signed16);
(8, 64) => (mcf::STBE, signed12);
(16, 32) => (mcf::STH, signed16);
(16, 64) => (mcf::STHE, signed12);
(32, 32) => (mcf::STW, signed16);
(32, 64) => (mcf::STWE, signed12);
(64, 64) => (mcf::STDE, signed12);
_ => error "store";
esac;
my (r, disp) = address (size, ea);
mark (mcf::ST { st, rs=>expr data, ra=>r, d=>disp, ramregion }, notes); }
# Emit a floating point store:
#
also
fun fstore (type, ea, data, ramregion, notes)
=
{ my (st, size)
=
case (type, tct::tsz::size ea)
#
(32, 32) => (mcf::STFS, signed16);
(32, 64) => (mcf::STFSE, signed12);
(64, 32) => (mcf::STFD, signed16);
(64, 64) => (mcf::STFDE, signed12);
_ => error "fstore";
esac;
my (r, disp) = address (size, ea);
mark (mcf::STF { st, fs=>float_expression data, ra=>r, d=>disp, ramregion }, notes); }
also
fun subf_immed (i, ra, rt, notes)
=
if (signed16 i )
mark (mcf::ARITHI { oper=>mcf::SUBFIC, rt, ra, im=>mcf::IMMED_OP (to_int i) }, notes);
else
mark (mcf::ARITH { oper=>mcf::SUBF, rt, ra, rb=>expr (tcf::LITERAL i),
rc=>FALSE, oe=>FALSE }, notes);
fi
# Generate an arithmetic instruction
#
also
fun arith (oper, e1, e2, rt, notes)
=
mark (mcf::ARITH { oper, ra=>expr e1, rb=>expr e2, rt, oe=>FALSE, rc=>FALSE },
notes)
# Generate a trapping instruction
also
fun arith_trapping (oper, e1, e2, rt, notes)
=
{ ra = expr e1; rb = expr e2;
mark (mcf::ARITH { oper, ra, rb, rt, oe=>TRUE, rc=>TRUE }, notes);
overflow_trap();
}
# Generate an overflow trap:
#
also
fun overflow_trap ()
=
{ label = case *trap_label
NULL => { l = lbl::make_anonymous_codelabel();
trap_label := THE l;
l;
};
THE l => l;
esac;
put_branch { bo=>mcf::TRUE, bf=>cr0, bit=>mcf::SO, lk=>FALSE,
address=>mcf::LABEL_OP (tcf::LABEL label) };
}
# Generate a load and annotate the instruction
#
also
fun load (ld32, ld64, ea, ramregion, rt, notes)
=
{ my (ld, size)
=
if (bit64mode and tct::tsz::size ea == 64 )
(ld64, signed12);
else (ld32, signed16);
fi;
my (r, disp) = address (size, ea);
mark (mcf::LL { ld, rt, ra=>r, d=>disp, ramregion }, notes);
}
# Generate a RIGHT_SHIFT shift operation
# and annotate the instruction:
#
also
fun sra (oper, operi, e1, e2, rt, notes)
=
case (immed_operand unsigned5 (e1, e2))
(ra, mcf::REG_OP rb)
=>
mark (mcf::ARITH { oper, rt, ra, rb, rc=>FALSE, oe=>FALSE }, notes);
(ra, rb)
=>
mark (mcf::ARITHI { oper=>operi, rt, ra, im=>rb }, notes);
esac
# Generate a RIGHT_SHIFT_U shift operation
# and annotate the instruction:
#
also
fun srl32 (e1, e2, rt, notes)
=
case (immed_operand unsigned5 (e1, e2))
(ra, mcf::IMMED_OP n)
=>
mark (srli32 { r=>ra, i=>n, d=>rt }, notes);
(ra, rb)
=>
mark (mcf::ARITH { oper=>mcf::SRW, rt, ra, rb=>reduce_opn rb,
rc=>FALSE, oe=>FALSE }, notes);
esac
also
fun sll32 (e1, e2, rt, notes)
=
case (immed_operand unsigned5 (e1, e2))
(ra, rb as mcf::IMMED_OP n)
=>
mark (slli32 { r=>ra, i=>n, d=>rt }, notes);
(ra, rb)
=>
mark (mcf::ARITH { oper=>mcf::SLW, rt, ra, rb=>reduce_opn rb,
rc=>FALSE, oe=>FALSE }, notes);
esac
# Generate a subtract operation:
#
also
fun subtract (type, e1, e2 as tcf::LITERAL i, rt, notes)
=>
do_expr (tcf::ADD (type, e1, tcf::LITERAL (tcf::mi::negt (32, i))), rt, notes)
except
OVERFLOW
=
mark (mcf::ARITH { oper=>mcf::SUBF, rt, ra=>expr e2,
rb=>expr e1, oe=>FALSE, rc=>FALSE }, notes);
subtract (type, tcf::LITERAL i, e2, rt, notes)
=>
subf_immed (i, expr e2, rt, notes);
subtract (type, x as (tcf::LATE_CONSTANT _
| tcf::LABEL _), e2, rt, notes)
=>
mark (mcf::ARITHI { oper=>mcf::SUBFIC, rt, ra=>expr e2,
im=>mcf::LABEL_OP x }, notes);
subtract (type, e1, e2, rt, notes)
=>
{ rb = expr e1; ra = expr e2;
mark (mcf::ARITH { oper=>mcf::SUBF, rt, ra, rb, rc=>FALSE, oe=>FALSE }, notes);
};
end
# Generate optimized multiplication code:
#
also
fun multiply (type, oper, operi, gen_mult, e1, e2, rt, notes)
=
{ fun nonconst (e1, e2)
=
[annotate(
case (comm_immed_operand signed16 (e1, e2))
(ra, mcf::REG_OP rb) =>
mcf::arith { oper, ra, rb, rt, oe=>FALSE, rc=>FALSE };
(ra, im) => mcf::arithi { oper=>operi, ra, im, rt }; esac,
notes)];
fun const (e, i)
=
{ r = expr e;
gen_mult { r, i=>to_int (i), d=>rt }
except
_ = nonconst (tcf::CODETEMP_INFO (type, r), tcf::LITERAL i);
};
ops = case (e1, e2)
(_, tcf::LITERAL i) => const (e1, i);
(tcf::LITERAL i, _) => const (e2, i);
_ => nonconst (e1, e2);
esac;
apply buf.put_op ops;
}
also
fun divu32 x = mulu32::divide { mode=>tcf::ROUND_TO_ZERO, void_expression=>do_void_expression } x
also
fun divs32 x = muls32::divide { mode=>tcf::ROUND_TO_ZERO, void_expression=>do_void_expression } x
also
fun divt32 x = mult32::divide { mode=>tcf::ROUND_TO_ZERO, void_expression=>do_void_expression } x
# Generate optimized division code:
#
also
fun divide (type, oper, gen_div, e1, e2, rt, overflow, notes)
=
{ fun nonconst (e1, e2)
=
{ mark (mcf::ARITH { oper, ra=>expr e1, rb=>expr e2, rt,
oe=>overflow, rc=>overflow }, notes);
if overflow overflow_trap(); fi;
};
fun const (e, i)
=
{ r = expr e;
#
apply buf.put_op (gen_div { r, i=>to_int (i), d=>rt } )
except
_ = nonconst (tcf::CODETEMP_INFO (type, r), tcf::LITERAL i);
};
case (e1, e2)
#
(_, tcf::LITERAL i) => const (e1, i);
_ => nonconst (e1, e2);
esac;
}
# Reduce an operand into a register:
#
also
fun reduce_opn (mcf::REG_OP r)
=>
r;
reduce_opn opn
=>
{ rt = issue_int_codetemp ();
put_base_op (mcf::ARITHI { oper=>mcf::ADDI, rt, ra=>zero_r, im=>opn } );
rt;
};
end
# Reduce an expression, and return
# the register holding the value.
#
also
fun expr (int_expression as tcf::CODETEMP_INFO(_, r))
=>
if (rkj::codetemps_are_same_color (rgk::lr, r) )
rt = issue_int_codetemp ();
do_expr (int_expression, rt, []);
rt;
else
r;
fi;
expr (int_expression)
=>
{ rt = issue_int_codetemp ();
do_expr (int_expression, rt, []);
rt;
};
end
# do_expr (e, rt, notes) --
# Reduce the expression e, assign it to rd,
# and annotate the expression with notes
#
also
fun do_expr (e, rt, notes)
=
if (rkj::codetemps_are_same_color (rt, rgk::lr))
#
rt = issue_int_codetemp ();
do_expr (e, rt,[]);
mark (mtlr rt, notes);
else
case e
tcf::CODETEMP_INFO(_, rs) => if (rkj::codetemps_are_same_color (rs, rgk::lr)) mark (mflr rt, notes);
else move (rs, rt, notes);
fi;
tcf::LITERAL i => load_immed (i, rt, notes);
tcf::LABEL_EXPRESSION lambda_expression => load_label_expression (lambda_expression, rt, notes);
tcf::LATE_CONSTANT _ => load_label_expression (e, rt, notes);
tcf::LABEL _ => load_label_expression (e, rt, notes);
# All data widths:
#
tcf::ADD(_, e1, e2) => e_comm_imm signed16 (mcf::ADD, mcf::ADDI, e1, e2, rt, notes);
tcf::SUB (type, e1, e2) => subtract (type, e1, e2, rt, notes);
# Special PWRPC32 bit operations:
#
tcf::BITWISE_AND(_, e1, tcf::BITWISE_NOT(_, e2)) => arith (mcf::ANDC, e1, e2, rt, notes);
tcf::BITWISE_OR(_, e1, tcf::BITWISE_NOT(_, e2)) => arith (mcf::ORC, e1, e2, rt, notes);
tcf::BITWISE_XOR(_, e1, tcf::BITWISE_NOT(_, e2)) => arith (mcf::EQV, e1, e2, rt, notes);
tcf::BITWISE_EQV(_, e1, e2) => arith (mcf::EQV, e1, e2, rt, notes);
tcf::BITWISE_AND(_, tcf::BITWISE_NOT(_, e1), e2) => arith (mcf::ANDC, e2, e1, rt, notes);
tcf::BITWISE_OR(_, tcf::BITWISE_NOT(_, e1), e2) => arith (mcf::ORC, e2, e1, rt, notes);
tcf::BITWISE_XOR(_, tcf::BITWISE_NOT(_, e1), e2) => arith (mcf::EQV, e2, e1, rt, notes);
tcf::BITWISE_NOT(_, tcf::BITWISE_AND(_, e1, e2)) => arith (mcf::NAND, e1, e2, rt, notes);
tcf::BITWISE_NOT(_, tcf::BITWISE_OR(_, e1, e2)) => arith (mcf::NOR, e1, e2, rt, notes);
tcf::BITWISE_NOT(_, tcf::BITWISE_XOR(_, e1, e2)) => arith (mcf::EQV, e1, e2, rt, notes);
tcf::BITWISE_AND(_, e1, e2)
=>
e_comm_imm unsigned16 (mcf::AND, mcf::ANDI_RC, e1, e2, rt, notes);
tcf::BITWISE_OR (_, e1, e2) => e_comm_imm unsigned16 (mcf::OR, mcf::ORI, e1, e2, rt, notes);
tcf::BITWISE_XOR(_, e1, e2) => e_comm_imm unsigned16 (mcf::XOR, mcf::XORI, e1, e2, rt, notes);
# 32 bit support:
#
tcf::MULU (32, e1, e2) => multiply (32, mcf::MULLW, mcf::MULLI,
mulu32::multiply, e1, e2, rt, notes);
tcf::DIVU (32, e1, e2) => divide (32, mcf::DIVWU, divu32, e1, e2, rt, FALSE, notes);
tcf::MULS (32, e1, e2) => multiply (32, mcf::MULLW, mcf::MULLI,
muls32::multiply, e1, e2, rt, notes);
tcf::DIVS (tcf::d::ROUND_TO_ZERO, 32, e1, e2) # d:: is a special rounding mode just for divide instructions.
=>
# On the PWRPC32 we turn overflow checking on despite this
# being DIVS. That's because divide-by-zero is also
# indicated through "overflow" instead of causing a trap.
#
divide (32, mcf::DIVW, divs32, e1, e2, rt,
TRUE /* !! */,
notes);
tcf::ADD_OR_TRAP (32, e1, e2) => arith_trapping (mcf::ADD, e1, e2, rt, notes);
tcf::SUB_OR_TRAP (32, e1, e2) => arith_trapping (mcf::SUBF, e2, e1, rt, notes);
tcf::MULS_OR_TRAP (32, e1, e2) => arith_trapping (mcf::MULLW, e1, e2, rt, notes);
tcf::DIVS_OR_TRAP (tcf::d::ROUND_TO_ZERO, 32, e1, e2)
=>
divide (32, mcf::DIVW, divt32, e1, e2, rt, TRUE, notes);
tcf::RIGHT_SHIFT (32, e1, e2) => sra (mcf::SRAW, mcf::SRAWI, e1, e2, rt, notes);
tcf::RIGHT_SHIFT_U (32, e1, e2) => srl32 (e1, e2, rt, notes);
tcf::LEFT_SHIFT (32, e1, e2) => sll32 (e1, e2, rt, notes);
# 64 bit support
tcf::RIGHT_SHIFT (64, e1, e2) => sra (mcf::SRAD, mcf::SRADI, e1, e2, rt, notes);
# tcf::RIGHT_SHIFT_U (64, e1, e2) => srl (32, mcf::SRD, mcf::RLDINM, e1, e2, rt, notes)
# tcf::LEFT_SHIFT (64, e1, e2) => sll (32, mcf::SLD, mcf::RLDINM, e1, e2, rt, notes)
# loads
tcf::LOAD (8, ea, ramregion) => load (mcf::LBZ, mcf::LBZE, ea, ramregion, rt, notes);
tcf::LOAD (16, ea, ramregion) => load (mcf::LHZ, mcf::LHZE, ea, ramregion, rt, notes);
tcf::LOAD (32, ea, ramregion) => load (mcf::LWZ, mcf::LWZE, ea, ramregion, rt, notes);
tcf::LOAD (64, ea, ramregion) => load (mcf::LDE, mcf::LDE, ea, ramregion, rt, notes);
# Conditional expression
tcf::CONDITIONAL_LOAD expression
=>
do_stmts (tct::compile_cond { expression, notes, rd=>rt } );
# Misc
tcf::LET (s, e) => { do_void_expression s; do_expr (e, rt, notes);};
tcf::RNOTE (e, lcn::MARKREG f) => { f rt; do_expr (e, rt, notes);};
tcf::RNOTE (e, a) => do_expr (e, rt, a ! notes);
tcf::REXT e => txc::compile_rext (reducer()) { e, rd=>rt, notes };
e => do_expr (tct::compile_int_expression e, rt, notes);
esac;
fi
# Generate a floating point load:
#
also
fun fload (ld32, ld64, ea, ramregion, ft, notes)
=
{ my (ld, size)
=
if (bit64mode and tct::tsz::size ea == 64) (ld64, signed12);
else (ld32, signed16);
fi;
my (r, disp) = address (size, ea);
mark (mcf::LF { ld, ft, ra=>r, d=>disp, ramregion }, notes);
}
# Generate a floating-point binary operation:
#
also
fun fbinary (oper, e1, e2, ft, notes)
=
mark (mcf::FARITH { oper, fa=>float_expression e1, fb=>float_expression e2, ft, rc=>FALSE }, notes)
# Generate a floating-point 3-operand operation
# These are of the form
# +/- e1 * e3 +/- e2
#
also
fun f3 (oper, e1, e2, e3, ft, notes)
=
mark (mcf::FARITH3 { oper, fa=>float_expression e1, fb=>float_expression e2, fc=>float_expression e3,
ft, rc=>FALSE }, notes)
# Generate a floating-point unary operation
also
fun funary (oper, e, ft, notes)
=
mark (mcf::FUNARY { oper, ft, fb=>float_expression e, rc=>FALSE }, notes)
# Reduce the expression float_expression,
# return the register that holds
# the value.
#
also
fun float_expression (tcf::CODETEMP_INFO_FLOAT(_, f))
=>
f;
float_expression e
=>
{ ft = issue_float_codetemp();
#
do_float_expression (e, ft, []);
#
ft;
};
end
# do_expr (float_expression, ft, notes) --
# Reduce the expression float_expression,
# and assign it to ft. Also annotate float_expression.
#
also
fun do_float_expression (e, ft, notes)
=
case e
tcf::CODETEMP_INFO_FLOAT(_, fs) => fmove (fs, ft, notes);
# Single precision support
tcf::FLOAD (32, ea, ramregion) => fload (mcf::LFS, mcf::LFSE, ea, ramregion, ft, notes);
# special 3 operand floating point arithmetic
tcf::FADD (32, tcf::FMUL (32, a, c), b) => f3 (mcf::FMADDS, a, b, c, ft, notes);
tcf::FADD (32, b, tcf::FMUL (32, a, c)) => f3 (mcf::FMADDS, a, b, c, ft, notes);
tcf::FSUB (32, tcf::FMUL (32, a, c), b) => f3 (mcf::FMSUBS, a, b, c, ft, notes);
tcf::FSUB (32, b, tcf::FMUL (32, a, c)) => f3 (mcf::FNMSUBS, a, b, c, ft, notes);
tcf::FNEG (32, tcf::FADD (32, tcf::FMUL (32, a, c), b)) => f3 (mcf::FNMADDS, a, b, c, ft, notes);
tcf::FNEG (32, tcf::FADD (32, b, tcf::FMUL (32, a, c))) => f3 (mcf::FNMADDS, a, b, c, ft, notes);
tcf::FSUB (32, tcf::FNEG (32, tcf::FMUL (32, a, c)), b) => f3 (mcf::FNMADDS, a, b, c, ft, notes);
tcf::FADD (32, e1, e2) => fbinary (mcf::FADDS, e1, e2, ft, notes);
tcf::FSUB (32, e1, e2) => fbinary (mcf::FSUBS, e1, e2, ft, notes);
tcf::FMUL (32, e1, e2) => fbinary (mcf::FMULS, e1, e2, ft, notes);
tcf::FDIV (32, e1, e2) => fbinary (mcf::FDIVS, e1, e2, ft, notes);
# Double precision support
tcf::FLOAD (64, ea, ramregion) => fload (mcf::LFD, mcf::LFDE, ea, ramregion, ft, notes);
# special 3 operand floating point arithmetic
tcf::FADD (64, tcf::FMUL (64, a, c), b) => f3 (mcf::FMADD, a, b, c, ft, notes);
tcf::FADD (64, b, tcf::FMUL (64, a, c)) => f3 (mcf::FMADD, a, b, c, ft, notes);
tcf::FSUB (64, tcf::FMUL (64, a, c), b) => f3 (mcf::FMSUB, a, b, c, ft, notes);
tcf::FSUB (64, b, tcf::FMUL (64, a, c)) => f3 (mcf::FNMSUB, a, b, c, ft, notes);
tcf::FNEG (64, tcf::FADD (64, tcf::FMUL (64, a, c), b)) => f3 (mcf::FNMADD, a, b, c, ft, notes);
tcf::FNEG (64, tcf::FADD (64, b, tcf::FMUL (64, a, c))) => f3 (mcf::FNMADD, a, b, c, ft, notes);
tcf::FSUB (64, tcf::FNEG (64, tcf::FMUL (64, a, c)), b) => f3 (mcf::FNMADD, a, b, c, ft, notes);
tcf::FADD (64, e1, e2) => fbinary (mcf::FADD, e1, e2, ft, notes);
tcf::FSUB (64, e1, e2) => fbinary (mcf::FSUB, e1, e2, ft, notes);
tcf::FMUL (64, e1, e2) => fbinary (mcf::FMUL, e1, e2, ft, notes);
tcf::FDIV (64, e1, e2) => fbinary (mcf::FDIV, e1, e2, ft, notes);
tcf::INT_TO_FLOAT (64, _, e) => apply buf.put_op (pop::cvti2d { reg=>expr e, fd=>ft } );
# Single/double precision support:
#
tcf::FABS((32
|64), e) => funary (mcf::FABS, e, ft, notes);
tcf::FNEG((32
|64), e) => funary (mcf::FNEG, e, ft, notes);
tcf::FSQRT (32, e) => funary (mcf::FSQRTS, e, ft, notes);
tcf::FSQRT (64, e) => funary (mcf::FSQRT, e, ft, notes);
tcf::FLOAT_TO_FLOAT (64, 32, e) => do_float_expression (e, ft, notes); # 32->64 is a nop
tcf::FLOAT_TO_FLOAT (32, 32, e) => do_float_expression (e, ft, notes);
tcf::FLOAT_TO_FLOAT (64, 64, e) => do_float_expression (e, ft, notes);
#
tcf::FLOAT_TO_FLOAT (32, 64, e) => funary (mcf::FRSP, e, ft, notes);
# Misc
tcf::FNOTE (e, lcn::MARKREG f) => { f ft; do_float_expression (e, ft, notes);};
tcf::FNOTE (e, a) => do_float_expression (e, ft, a ! notes);
tcf::FEXT e => txc::compile_fext (reducer()) { e, fd=>ft, notes };
_ => error "doFexpr";
esac
also
fun cc_expr (tcf::CC (_, cc)) => cc; # "cc" == "condition code", i.e. a bit in the flags register, like Z(ero)/P(arity)/O(verflow)/...
cc_expr (tcf::FCC (_, cc)) => cc;
#
cc_expr flag_expression
=>
{ cc = make_flag_codetemp ();
#
do_flag_expression (flag_expression, cc,[]);
#
cc;
};
end
# Reduce a flag expression
# and assign the result to ccd
#
also
fun do_flag_expression (flag_expression, ccd, notes)
=
case flag_expression
#
tcf::CMP (type, cc, e1, e2)
=>
{ my (opnds, cmp)
=
case cc
#
(tcf::LT
| tcf::LE | tcf::EQ | tcf::NE | tcf::GT | tcf::GE)
=>
(immed_operand signed16, mcf::CMP);
_ =>
(immed_operand unsigned16, mcf::CMPL);
esac;
my (operand_a, operand_b)
=
opnds (e1, e2);
l = case type
32 => FALSE;
64 => TRUE;
_ => error "do_flag_expression";
esac;
mark (mcf::COMPARE { cmp, l, bf=>ccd, ra=>operand_a, rb=>operand_b }, notes);
};
tcf::FCMP (fty, fcc, e1, e2)
=>
mark (mcf::FCOMPARE { cmp=>mcf::FCMPU, bf=>ccd, fa=>float_expression e1, fb=>float_expression e2 }, notes);
tcf::CC(_, cc) => ccmove (cc, ccd, notes);
tcf::CCNOTE (cc, lcn::MARKREG f) => { f ccd; do_flag_expression (cc, ccd, notes); };
tcf::CCNOTE (cc, a) => do_flag_expression (cc, ccd, a ! notes);
tcf::CCEXT e
=>
txc::compile_ccext (reducer()) { e, ccd, notes };
_ => error "do_flag_expression: Not implemented";
esac
also
fun put_trap ()
=
put_base_op (mcf::TW { to=>31, ra=>zero_r, si=>mcf::IMMED_OP 0 } )
also
fun start_new_cccomponent' _
=
{ trap_label := NULL;
#
buf.start_new_cccomponent 0; # The '0' is a dummy value here; in other contexts it is used to pre-size the codesegment buffer.
}
also
fun get_completed_cccomponent' a
=
{ case *trap_label
#
NULL => ();
#
THE label => { buf.put_private_label label;
#
put_trap ();
#
trap_label := NULL;
};
esac;
buf.get_completed_cccomponent a;
}
also
fun reducer ()
=
tcs::REDUCER
{ reduce_int_expression => expr,
reduce_float_expression => float_expression,
reduce_flag_expression => cc_expr,
reduce_void_expression => void_expression,
operand => (\\ _ = error "operand"),
#
reduce_operand => reduce_opn,
address_of => (\\ _ = error "address_of"),
put_op => buf.put_op o annotate,
treecode_stream => self (),
#
codestream => buf
}
also
fun self ()
=
{
start_new_cccomponent => start_new_cccomponent',
get_completed_cccomponent => get_completed_cccomponent',
put_op => do_void_expression,
#
put_pseudo_op => buf.put_pseudo_op,
put_private_label => buf.put_private_label,
put_public_label => buf.put_public_label,
put_comment => buf.put_comment,
put_bblock_note => buf.put_bblock_note,
get_notes => buf.get_notes,
#
put_fn_liveout_info => \\ lowhalf = buf.put_fn_liveout_info (registerset lowhalf)
};
self ();
};
end;
};
end;
## COPYRIGHT (c) 2002 Bell Labs, Lucent Technologies
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.