11.1 IR
Cb使用的是树形IR。
cbc --dump-ir if_test.cb
<<IR>> (if_test.cb:1)
variables:
functions:
<<DefinedFunction>> (if_test.cb:2)
name: main
isPrivate: false
type: int(int, char**)
body:
<<CJump>> (if_test.cb:4)
cond:
<<Int>>
type: INT32
value: 1
thenLabel: 123a439b
elseLabel: 7de26db8
<<LabelStmt>> (null)
label: 123a439b
<<CJump>> (if_test.cb:4)
cond:
<<Int>>
type: INT32
value: 2
thenLabel: 1175e2db
elseLabel: 36aa7bc2
<<LabelStmt>> (null)
label: 1175e2db
<<ExprStmt>> (if_test.cb:4)
expr:
<<Call>>
type: INT32
expr:
<<Addr>>
type: INT32
entity: puts
args:
<<Str>>
type: INT32
entry: net.loveruby.cflat.entity.ConstantEntry@76ccd017
<<Jump>> (null)
label: 182decdb
<<LabelStmt>> (null)
label: 36aa7bc2
<<CJump>> (if_test.cb:5)
cond:
<<Int>>
type: INT32
value: 3
thenLabel: 26f0a63f
elseLabel: 4361bd48
<<LabelStmt>> (null)
label: 26f0a63f
<<ExprStmt>> (if_test.cb:5)
expr:
<<Call>>
type: INT32
expr:
<<Addr>>
type: INT32
entity: puts
args:
<<Str>>
type: INT32
entry: net.loveruby.cflat.entity.ConstantEntry@53bd815b
<<Jump>> (null)
label: 2401f4c3
<<LabelStmt>> (null)
label: 4361bd48
<<ExprStmt>> (if_test.cb:6)
expr:
<<Call>>
type: INT32
expr:
<<Addr>>
type: INT32
entity: puts
args:
<<Str>>
type: INT32
entry: net.loveruby.cflat.entity.ConstantEntry@7637f22
<<LabelStmt>> (null)
label: 2401f4c3
<<LabelStmt>> (null)
label: 182decdb
<<LabelStmt>> (null)
label: 7de26db8
<<Return>> (if_test.cb:7)
expr:
<<Int>>
type: INT32
value: 0
中间代码
中间代码的类和属性
- Assign: lhs, rhs
- CJump: cond, thenLabel, elseLabel
- Jump: Label
- Switch: cond, casses, defaultLabel
- LabelStmt: label
- ExprStmt: expr
- Return: expr
- Uni: op, expr
- Bin: op, left, right
- Call: expr, args
- Addr: expr
- Mem: expr 对指针取值
- Var: entity 定义对象
- Int: value
- Str: entry
中间代码中的可行类型: INT8, INT16, INT32
中间代码运算符:
- ADD
- SUB
- MUL
- S_DIV
- U_DIV
- S_MOD
- U_MOD
- BIT_AND
- BIT_OR
- BIT_XOR
- BIT_LSHIFT
- BIT_RSHIFT
- ARITH_RSHIFT
- EQ
- NEQ
- S_GT
- S_GTEQ
- S_LT
- S_LTEQ
- U_GT
- U_GTEQ
- U_LT
- U_LTEQ
- UMINUS
- BIT_NOT
- NOT
- S_CAST
- U_CAST
中间代码的意义
源代码中不同的代码可能转为中间代码后就是相同的,更易于翻译为机器语言和优化
代码
class IRGenerator implements ASTVisitor<Void, Expr> {
private final TypeTable typeTable;
private final ErrorHandler errorHandler;
// #@@range/ctor{
public IRGenerator(TypeTable typeTable, ErrorHandler errorHandler) {
this.typeTable = typeTable;
this.errorHandler = errorHandler;
}
// #@@}
// #@@range/generate{
public IR generate(AST ast) throws SemanticException {
for (DefinedVariable var : ast.definedVariables()) {
if (var.hasInitializer()) {
var.setIR(transformExpr(var.initializer()));
}
}
for (DefinedFunction f : ast.definedFunctions()) {
f.setIR(compileFunctionBody(f));
}
if (errorHandler.errorOccured()) {
throw new SemanticException("IR generation failed.");
}
return ast.ir();
}
// #@@}
//
// Definitions
//
// #@@range/compileFunctionBody{
List<Stmt> stmts;
LinkedList<LocalScope> scopeStack;
LinkedList<Label> breakStack;
LinkedList<Label> continueStack;
Map<String, JumpEntry> jumpMap;
public List<Stmt> compileFunctionBody(DefinedFunction f) {
stmts = new ArrayList<Stmt>();
scopeStack = new LinkedList<LocalScope>();
breakStack = new LinkedList<Label>();
continueStack = new LinkedList<Label>();
jumpMap = new HashMap<String, JumpEntry>();
transformStmt(f.body());
checkJumpLinks(jumpMap);
return stmts;
}
// #@@}
// #@@range/transformStmt_stmt{
private void transformStmt(StmtNode node) {
node.accept(this);
}
// #@@}
// #@@range/transformStmt_expr{
private void transformStmt(ExprNode node) {
node.accept(this);
}
// #@@}
// #@@range/transformExpr{
private int exprNestLevel = 0;
private Expr transformExpr(ExprNode node) {
exprNestLevel++;
Expr e = node.accept(this);
exprNestLevel--;
return e;
}
// #@@}
// #@@range/isStatement{
private boolean isStatement() {
return (exprNestLevel == 0);
}
// #@@}
// #@@range/assign{
private void assign(Location loc, Expr lhs, Expr rhs) {
stmts.add(new Assign(loc, addressOf(lhs), rhs));
}
// #@@}
private DefinedVariable tmpVar(Type t) {
return scopeStack.getLast().allocateTmp(t);
}
private void label(Label label) {
stmts.add(new LabelStmt(null, label));
}
private void jump(Location loc, Label target) {
stmts.add(new Jump(loc, target));
}
private void jump(Label target) {
jump(null, target);
}
private void cjump(Location loc, Expr cond, Label thenLabel, Label elseLabel) {
stmts.add(new CJump(loc, cond, thenLabel, elseLabel));
}
// #@@range/pushBreak{
private void pushBreak(Label label) {
breakStack.add(label);
}
// #@@}
// #@@range/popBreak{
private void popBreak() {
if (breakStack.isEmpty()) {
throw new Error("unmatched push/pop for break stack");
}
breakStack.removeLast();
}
// #@@}
// #@@range/currentBreakTarget{
private Label currentBreakTarget() {
if (breakStack.isEmpty()) {
throw new JumpError("break from out of loop");
}
return breakStack.getLast();
}
// #@@}
private void pushContinue(Label label) {
continueStack.add(label);
}
private void popContinue() {
if (continueStack.isEmpty()) {
throw new Error("unmatched push/pop for continue stack");
}
continueStack.removeLast();
}
private Label currentContinueTarget() {
if (continueStack.isEmpty()) {
throw new JumpError("continue from out of loop");
}
return continueStack.getLast();
}
//
// Statements
//
public Void visit(BlockNode node) {
scopeStack.add(node.scope());
for (DefinedVariable var : node.variables()) {
if (var.hasInitializer()) {
if (var.isPrivate()) {
// static variables
var.setIR(transformExpr(var.initializer()));
}
else {
assign(var.location(),
ref(var), transformExpr(var.initializer()));
}
}
}
for (StmtNode s : node.stmts()) {
transformStmt(s);
}
scopeStack.removeLast();
return null;
}
public Void visit(ExprStmtNode node) {
// do not use transformStmt here, to receive compiled tree.
Expr e = node.expr().accept(this);
if (e != null) {
//stmts.add(new ExprStmt(node.expr().location(), e));
errorHandler.warn(node.location(), "useless expression");
}
return null;
}
// #@@range/If{
public Void visit(IfNode node) {
Label thenLabel = new Label();
Label elseLabel = new Label();
Label endLabel = new Label();
Expr cond = transformExpr(node.cond());
if (node.elseBody() == null) {
// #@@range/If_noelse{
cjump(node.location(), cond, thenLabel, endLabel);
label(thenLabel);
transformStmt(node.thenBody());
label(endLabel);
// #@@}
}
else {
// #@@range/If_withelse{
cjump(node.location(), cond, thenLabel, elseLabel);
label(thenLabel);
transformStmt(node.thenBody());
jump(endLabel);
label(elseLabel);
transformStmt(node.elseBody());
label(endLabel);
// #@@}
}
return null;
}
// #@@}
public Void visit(SwitchNode node) {
List<Case> cases = new ArrayList<Case>();
Label endLabel = new Label();
Label defaultLabel = endLabel;
Expr cond = transformExpr(node.cond());
for (CaseNode c : node.cases()) {
if (c.isDefault()) {
defaultLabel = c.label();
}
else {
for (ExprNode val : c.values()) {
Expr v = transformExpr(val);
cases.add(new Case(((Int)v).value(), c.label()));
}
}
}
stmts.add(new Switch(node.location(), cond, cases, defaultLabel, endLabel));
pushBreak(endLabel);
for (CaseNode c : node.cases()) {
label(c.label());
transformStmt(c.body());
}
popBreak();
label(endLabel);
return null;
}
public Void visit(CaseNode node) {
throw new Error("must not happen");
}
// #@@range/While{
public Void visit(WhileNode node) {
Label begLabel = new Label();
Label bodyLabel = new Label();
Label endLabel = new Label();
label(begLabel);
cjump(node.location(),
transformExpr(node.cond()), bodyLabel, endLabel);
label(bodyLabel);
pushContinue(begLabel);
pushBreak(endLabel);
transformStmt(node.body());
popBreak();
popContinue();
jump(begLabel);
label(endLabel);
return null;
}
// #@@}
public Void visit(DoWhileNode node) {
Label begLabel = new Label();
Label contLabel = new Label(); // before cond (end of body)
Label endLabel = new Label();
pushContinue(contLabel);
pushBreak(endLabel);
label(begLabel);
transformStmt(node.body());
popBreak();
popContinue();
label(contLabel);
cjump(node.location(), transformExpr(node.cond()), begLabel, endLabel);
label(endLabel);
return null;
}
public Void visit(ForNode node) {
Label begLabel = new Label();
Label bodyLabel = new Label();
Label contLabel = new Label();
Label endLabel = new Label();
if (node.init() != null) transformStmt(node.init());
label(begLabel);
cjump(node.location(),
transformExpr(node.cond()), bodyLabel, endLabel);
label(bodyLabel);
pushContinue(contLabel);
pushBreak(endLabel);
transformStmt(node.body());
popBreak();
popContinue();
label(contLabel);
if (node.incr() != null) transformStmt(node.incr());
jump(begLabel);
label(endLabel);
return null;
}
// #@@range/Break{
public Void visit(BreakNode node) {
try {
jump(node.location(), currentBreakTarget());
}
catch (JumpError err) {
error(node, err.getMessage());
}
return null;
}
// #@@}
public Void visit(ContinueNode node) {
try {
jump(node.location(), currentContinueTarget());
}
catch (JumpError err) {
error(node, err.getMessage());
}
return null;
}
public Void visit(LabelNode node) {
try {
stmts.add(new LabelStmt(node.location(),
defineLabel(node.name(), node.location())));
if (node.stmt() != null) {
transformStmt(node.stmt());
}
}
catch (SemanticException ex) {
error(node, ex.getMessage());
}
return null;
}
public Void visit(GotoNode node) {
jump(node.location(), referLabel(node.target()));
return null;
}
public Void visit(ReturnNode node) {
stmts.add(new Return(node.location(),
node.expr() == null ? null : transformExpr(node.expr())));
return null;
}
class JumpEntry {
public Label label;
public long numRefered;
public boolean isDefined;
public Location location;
public JumpEntry(Label label) {
this.label = label;
numRefered = 0;
isDefined = false;
}
}
private Label defineLabel(String name, Location loc)
throws SemanticException {
JumpEntry ent = getJumpEntry(name);
if (ent.isDefined) {
throw new SemanticException(
"duplicated jump labels in " + name + "(): " + name);
}
ent.isDefined = true;
ent.location = loc;
return ent.label;
}
private Label referLabel(String name) {
JumpEntry ent = getJumpEntry(name);
ent.numRefered++;
return ent.label;
}
private JumpEntry getJumpEntry(String name) {
JumpEntry ent = jumpMap.get(name);
if (ent == null) {
ent = new JumpEntry(new Label());
jumpMap.put(name, ent);
}
return ent;
}
private void checkJumpLinks(Map<String, JumpEntry> jumpMap) {
for (Map.Entry<String, JumpEntry> ent : jumpMap.entrySet()) {
String labelName = ent.getKey();
JumpEntry jump = ent.getValue();
if (!jump.isDefined) {
errorHandler.error(jump.location,
"undefined label: " + labelName);
}
if (jump.numRefered == 0) {
errorHandler.warn(jump.location,
"useless label: " + labelName);
}
}
}
//
// Expressions (with branches)
//
public Expr visit(CondExprNode node) {
Label thenLabel = new Label();
Label elseLabel = new Label();
Label endLabel = new Label();
DefinedVariable var = tmpVar(node.type());
Expr cond = transformExpr(node.cond());
cjump(node.location(), cond, thenLabel, elseLabel);
label(thenLabel);
assign(node.thenExpr().location(),
ref(var), transformExpr(node.thenExpr()));
jump(endLabel);
label(elseLabel);
assign(node.elseExpr().location(),
ref(var), transformExpr(node.elseExpr()));
jump(endLabel);
label(endLabel);
return isStatement() ? null : ref(var);
}
public Expr visit(LogicalAndNode node) {
Label rightLabel = new Label();
Label endLabel = new Label();
DefinedVariable var = tmpVar(node.type());
assign(node.left().location(),
ref(var), transformExpr(node.left()));
cjump(node.location(), ref(var), rightLabel, endLabel);
label(rightLabel);
assign(node.right().location(),
ref(var), transformExpr(node.right()));
label(endLabel);
return isStatement() ? null : ref(var);
}
public Expr visit(LogicalOrNode node) {
Label rightLabel = new Label();
Label endLabel = new Label();
DefinedVariable var = tmpVar(node.type());
assign(node.left().location(),
ref(var), transformExpr(node.left()));
cjump(node.location(), ref(var), endLabel, rightLabel);
label(rightLabel);
assign(node.right().location(),
ref(var), transformExpr(node.right()));
label(endLabel);
return isStatement() ? null : ref(var);
}
//
// Expressions (with side effects)
//
// #@@range/Assign{
public Expr visit(AssignNode node) {
Location lloc = node.lhs().location();
Location rloc = node.rhs().location();
if (isStatement()) {
// Evaluate RHS before LHS.
// #@@range/Assign_stmt{
Expr rhs = transformExpr(node.rhs());
assign(lloc, transformExpr(node.lhs()), rhs);
// #@@}
return null;
}
else {
// lhs = rhs -> tmp = rhs, lhs = tmp, tmp
// #@@range/Assign_expr{
DefinedVariable tmp = tmpVar(node.rhs().type());
assign(rloc, ref(tmp), transformExpr(node.rhs()));
assign(lloc, transformExpr(node.lhs()), ref(tmp));
return ref(tmp);
// #@@}
}
}
// #@@}
// #@@range/OpAssign{
public Expr visit(OpAssignNode node) {
// Evaluate RHS before LHS.
Expr rhs = transformExpr(node.rhs());
Expr lhs = transformExpr(node.lhs());
Type t = node.lhs().type();
Op op = Op.internBinary(node.operator(), t.isSigned());
return transformOpAssign(node.location(), op, t, lhs, rhs);
}
// #@@}
public Expr visit(PrefixOpNode node) {
// ++expr -> expr += 1
Type t = node.expr().type();
return transformOpAssign(node.location(),
binOp(node.operator()), t,
transformExpr(node.expr()), imm(t, 1));
}
// #@@range/SuffixOp{
public Expr visit(SuffixOpNode node) {
// #@@range/SuffixOp_init{
Expr expr = transformExpr(node.expr());
Type t = node.expr().type();
Op op = binOp(node.operator());
Location loc = node.location();
// #@@}
if (isStatement()) {
// expr++; -> expr += 1;
transformOpAssign(loc, op, t, expr, imm(t, 1));
return null;
}
else if (expr.isVar()) {
// cont(expr++) -> v = expr; expr = v + 1; cont(v)
DefinedVariable v = tmpVar(t);
assign(loc, ref(v), expr);
assign(loc, expr, bin(op, t, ref(v), imm(t, 1)));
return ref(v);
}
else {
// cont(expr++) -> a = &expr; v = *a; *a = *a + 1; cont(v)
// #@@range/SuffixOp_expr{
DefinedVariable a = tmpVar(pointerTo(t));
DefinedVariable v = tmpVar(t);
assign(loc, ref(a), addressOf(expr));
assign(loc, ref(v), mem(a));
assign(loc, mem(a), bin(op, t, mem(a), imm(t, 1)));
return ref(v);
// #@@}
}
}
// #@@}
// #@@range/transformOpAssign{
private Expr transformOpAssign(Location loc,
Op op, Type lhsType, Expr lhs, Expr rhs) {
if (lhs.isVar()) {
// cont(lhs += rhs) -> lhs = lhs + rhs; cont(lhs)
assign(loc, lhs, bin(op, lhsType, lhs, rhs));
return isStatement() ? null : lhs;
}
else {
// cont(lhs += rhs) -> a = &lhs; *a = *a + rhs; cont(*a)
DefinedVariable a = tmpVar(pointerTo(lhsType));
assign(loc, ref(a), addressOf(lhs));
assign(loc, mem(a), bin(op, lhsType, mem(a), rhs));
return isStatement() ? null : mem(a);
}
}
// #@@}
// #@@range/bin{
private Bin bin(Op op, Type leftType, Expr left, Expr right) {
if (isPointerArithmetic(op, leftType)) {
return new Bin(left.type(), op, left,
new Bin(right.type(), Op.MUL,
right, ptrBaseSize(leftType)));
}
else {
return new Bin(left.type(), op, left, right);
}
}
// #@@}
// #@@range/Funcall{
public Expr visit(FuncallNode node) {
List<Expr> args = new ArrayList<Expr>();
for (ExprNode arg : ListUtils.reverse(node.args())) {
args.add(0, transformExpr(arg));
}
Expr call = new Call(asmType(node.type()),
transformExpr(node.expr()), args);
if (isStatement()) {
stmts.add(new ExprStmt(node.location(), call));
return null;
}
else {
DefinedVariable tmp = tmpVar(node.type());
assign(node.location(), ref(tmp), call);
return ref(tmp);
}
}
// #@@}
//
// Expressions (no side effects)
//
// #@@range/BinaryOp{
public Expr visit(BinaryOpNode node) {
// #@@range/BinaryOp_init_1{
Expr right = transformExpr(node.right());
Expr left = transformExpr(node.left());
Op op = Op.internBinary(node.operator(), node.type().isSigned());
Type t = node.type();
// #@@}
Type r = node.right().type();
Type l = node.left().type();
// #@@range/BinaryOp_ptr{
if (isPointerDiff(op, l, r)) {
// ptr - ptr -> (ptr - ptr) / ptrBaseSize
Expr tmp = new Bin(asmType(t), op, left, right);
return new Bin(asmType(t), Op.S_DIV, tmp, ptrBaseSize(l));
}
else if (isPointerArithmetic(op, l)) {
// ptr + int -> ptr + (int * ptrBaseSize)
return new Bin(asmType(t), op,
left,
new Bin(asmType(r), Op.MUL, right, ptrBaseSize(l)));
}
else if (isPointerArithmetic(op, r)) {
// int + ptr -> (int * ptrBaseSize) + ptr
return new Bin(asmType(t), op,
new Bin(asmType(l), Op.MUL, left, ptrBaseSize(r)),
right);
}
// #@@}
else {
// int + int
// #@@range/BinaryOp_int{
return new Bin(asmType(t), op, left, right);
// #@@}
}
}
// #@@}
// #@@range/UnaryOp{
public Expr visit(UnaryOpNode node) {
if (node.operator().equals("+")) {
// +expr -> expr
return transformExpr(node.expr());
}
else {
return new Uni(asmType(node.type()),
Op.internUnary(node.operator()),
transformExpr(node.expr()));
}
}
// #@@}
// #@@range/Aref{
public Expr visit(ArefNode node) {
Expr expr = transformExpr(node.baseExpr());
Expr offset = new Bin(ptrdiff_t(), Op.MUL,
size(node.elementSize()), transformIndex(node));
Bin addr = new Bin(ptr_t(), Op.ADD, expr, offset);
return mem(addr, node.type());
}
// #@@}
// For multidimension array: t[e][d][c][b][a] ary;
// &ary[a0][b0][c0][d0][e0]
// = &ary + edcb*a0 + edc*b0 + ed*c0 + e*d0 + e0
// = &ary + (((((a0)*b + b0)*c + c0)*d + d0)*e + e0) * sizeof(t)
//
private Expr transformIndex(ArefNode node) {
if (node.isMultiDimension()) {
return new Bin(int_t(), Op.ADD,
transformExpr(node.index()),
new Bin(int_t(), Op.MUL,
new Int(int_t(), node.length()),
transformIndex((ArefNode)node.expr())));
}
else {
return transformExpr(node.index());
}
}
// #@@range/Member{
public Expr visit(MemberNode node) {
Expr expr = addressOf(transformExpr(node.expr()));
Expr offset = ptrdiff(node.offset());
Expr addr = new Bin(ptr_t(), Op.ADD, expr, offset);
// #@@range/Member_ret{
return node.isLoadable() ? mem(addr, node.type()) : addr;
// #@@}
}
// #@@}
// #@@range/PtrMember{
public Expr visit(PtrMemberNode node) {
Expr expr = transformExpr(node.expr());
Expr offset = ptrdiff(node.offset());
Expr addr = new Bin(ptr_t(), Op.ADD, expr, offset);
return node.isLoadable() ? mem(addr, node.type()) : addr;
}
// #@@}
// #@@range/Dereference{
public Expr visit(DereferenceNode node) {
Expr addr = transformExpr(node.expr());
return node.isLoadable() ? mem(addr, node.type()) : addr;
}
// #@@}
public Expr visit(AddressNode node) {
Expr e = transformExpr(node.expr());
return node.expr().isLoadable() ? addressOf(e) : e;
}
public Expr visit(CastNode node) {
if (node.isEffectiveCast()) {
return new Uni(asmType(node.type()),
node.expr().type().isSigned() ? Op.S_CAST : Op.U_CAST,
transformExpr(node.expr()));
}
else if (isStatement()) {
transformStmt(node.expr());
return null;
}
else {
return transformExpr(node.expr());
}
}
public Expr visit(SizeofExprNode node) {
return new Int(size_t(), node.expr().allocSize());
}
public Expr visit(SizeofTypeNode node) {
return new Int(size_t(), node.operand().allocSize());
}
public Expr visit(VariableNode node) {
if (node.entity().isConstant()) {
return transformExpr(node.entity().value());
}
Var var = ref(node.entity());
return node.isLoadable() ? var : addressOf(var);
}
public Expr visit(IntegerLiteralNode node) {
return new Int(asmType(node.type()), node.value());
}
public Expr visit(StringLiteralNode node) {
return new Str(asmType(node.type()), node.entry());
}
//
// Utilities
//
private boolean isPointerDiff(Op op, Type l, Type r) {
return op == Op.SUB && l.isPointer() && r.isPointer();
}
private boolean isPointerArithmetic(Op op, Type operandType) {
switch (op) {
case ADD:
case SUB:
return operandType.isPointer();
default:
return false;
}
}
private Expr ptrBaseSize(Type t) {
return new Int(ptrdiff_t(), t.baseType().size());
}
// unary ops -> binary ops
private Op binOp(String uniOp) {
return uniOp.equals("++") ? Op.ADD : Op.SUB;
}
// #@@range/addressOf{
private Expr addressOf(Expr expr) {
return expr.addressNode(ptr_t());
}
// #@@}
// #@@range/ref{
private Var ref(Entity ent) {
return new Var(varType(ent.type()), ent);
}
// #@@}
// mem(ent) -> (Mem (Var ent))
private Mem mem(Entity ent) {
return new Mem(asmType(ent.type().baseType()), ref(ent));
}
// mem(expr) -> (Mem expr)
// #@@range/mem{
private Mem mem(Expr expr, Type t) {
return new Mem(asmType(t), expr);
}
// #@@}
// #@@range/ptrdiff{
private Int ptrdiff(long n) {
return new Int(ptrdiff_t(), n);
}
// #@@}
// #@@range/size{
private Int size(long n) {
return new Int(size_t(), n);
}
// #@@}
// #@@range/imm{
private Int imm(Type operandType, long n) {
if (operandType.isPointer()) {
return new Int(ptrdiff_t(), n);
}
else {
return new Int(int_t(), n);
}
}
// #@@}
private Type pointerTo(Type t) {
return typeTable.pointerTo(t);
}
private net.loveruby.cflat.asm.Type asmType(Type t) {
if (t.isVoid()) return int_t();
return net.loveruby.cflat.asm.Type.get(t.size());
}
private net.loveruby.cflat.asm.Type varType(Type t) {
if (! t.isScalar()) {
return null;
}
return net.loveruby.cflat.asm.Type.get(t.size());
}
private net.loveruby.cflat.asm.Type int_t() {
return net.loveruby.cflat.asm.Type.get((int)typeTable.intSize());
}
private net.loveruby.cflat.asm.Type size_t() {
return net.loveruby.cflat.asm.Type.get((int)typeTable.longSize());
}
private net.loveruby.cflat.asm.Type ptr_t() {
return net.loveruby.cflat.asm.Type.get((int)typeTable.pointerSize());
}
private net.loveruby.cflat.asm.Type ptrdiff_t() {
return net.loveruby.cflat.asm.Type.get((int)typeTable.longSize());
}
private void error(Node n, String msg) {
errorHandler.error(n.location(), msg);
}
}
11.4 没有副作用的表达式转换
对Uni来说,"+expr()"可以直接转化为"exor()",抛掉"+"
对Bin来说,指针运算直接在转成IR的先进行处理,比如ptr1 - ptr2就会被处理为(ptr1 -ptr2) / ptrBaseSize
11.5 左值转换
注意左值有的时候也需要运算并转化为更长的中间代码,比如a[1] = 123,就需要把a[1]翻译为&(a + 偏移)
此外,结构体成员变量也需要翻译为结构体指针的偏移
最后,函数和数组在被隐式当成指针的时候要特殊处理
11.6 存在副作用的表达式的转换
在Cb中,赋值表达式如 = , += , /= 还有自增,自减,调用函数等都是有副作用的,这种表达式不能随意更改相对执行顺序。
Cb需要将这类代码转化为具有副作用的中间代码。
这里有副作用的中间代码有两类: Assign类和Call类。
Call是Expr类的子类,只能在ExprStmt下方或者Assign右值的下方出现。
在转化的过程中,需要注意将有副作用的部分和获取返回值的部分分开,避免reevaluate/recall,这可以通过临时变量处理。
比如对于f(*ptr++ =g(7))这样一句调用,如果翻译成:
expr_00 = *ptr
expr_01 = expr_00++
expr_02 = assign(Mem(expr_01), Call(g, 7))
f(expr_02)
那么就可能会导致expr_02自身计算一遍,f这里再算一遍,最后得到的结果会有错。
所以要引入临时变量
expr_00 = addr(*ptr)
tmp_var = expr_00
mem(expr_00) = mem(expr_00) + 1
tmp_var02 = Call(g, 7)
Mem(tmp_var) = tmp_var_02
f(tmp_var02)
具体来说,就是将func(lhs = rhs)转化为tmp = rhs; lhs = tmp; func(tmp)
相当于告诉编译器先做rhs = lhs并且将lhs对应的结果转化为单独变量,再去做func这个逻辑。这种策略称为continuation
总之,需要引入临时变量存储返回值。