A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.3 KiB

  1. import type { AssignStmt, Expr, Stmt } from "../ast"
  2. import { R8 } from "../sm83/cpu"
  3. import { Loc, LocType } from "./loc"
  4. import { Operand, AbsInsn2, AbsInsn3, CopyInsn, GotoInsn, UnaryInsn, BinaryInsn, LabelInsn } from "./insn"
  5. export class IRState {
  6. nextID: number
  7. insns: Array<AbsInsn2>
  8. constructor() {
  9. this.nextID = 0
  10. this.insns = []
  11. }
  12. temp(): Loc {
  13. return Loc.temp(`t${this.nextID++}`)
  14. }
  15. }
  16. export const convertIR = (stmts: Array<Stmt>): Array<AbsInsn2> => {
  17. const state: IRState = new IRState()
  18. stmts.forEach(stmt => {
  19. switch (stmt.stmt_type) {
  20. case 'assign':
  21. convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr)
  22. break
  23. case 'label':
  24. state.insns.push(LabelInsn(stmt.args.name))
  25. break
  26. case 'goto':
  27. state.insns.push(GotoInsn(stmt.args.name))
  28. break
  29. }
  30. })
  31. return state.insns
  32. }
  33. export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => {
  34. const threeAddress = convertExpr3(state, dest, expr)
  35. threeAddress.forEach(ssa => {
  36. switch (ssa.type) {
  37. case 'copy':
  38. state.insns.push(ssa)
  39. break
  40. case 'unary':
  41. state.insns.push(
  42. CopyInsn(Loc.reg(R8.A), ssa.source),
  43. UnaryInsn(Loc.reg(R8.A), ssa.op, Loc.reg(R8.A)),
  44. CopyInsn(ssa.dest, Loc.reg(R8.A)),
  45. )
  46. break
  47. case 'binary':
  48. let source1 = ssa.source1
  49. if (typeof source1 !== 'number' && source1.type === LocType.VARIABLE) {
  50. source1 = state.temp()
  51. state.insns.push(
  52. CopyInsn(Loc.reg(R8.A), ssa.source1),
  53. CopyInsn(source1, Loc.reg(R8.A)),
  54. )
  55. }
  56. state.insns.push(
  57. CopyInsn(Loc.reg(R8.A), ssa.source),
  58. UnaryInsn(Loc.reg(R8.A), ssa.op, source1),
  59. CopyInsn(ssa.dest, Loc.reg(R8.A)),
  60. )
  61. break
  62. }
  63. })
  64. }
  65. export const convertExpr3 = (state: IRState, dest: Loc, expr: Expr): Array<AbsInsn3> => {
  66. let expr_stmts: Array<AbsInsn3> = []
  67. const getSource = (expr: Expr): [Operand, Array<AbsInsn3>] => {
  68. if (typeof expr === "number") {
  69. return [expr, []]
  70. } else if (typeof expr === "string") {
  71. return [Loc.vari(expr), []]
  72. }
  73. const source = state.temp()
  74. const stmts = convertExpr3(state, source, expr)
  75. return [source, stmts]
  76. }
  77. if (typeof expr === "number") {
  78. expr_stmts.push(CopyInsn(dest, expr))
  79. } else if (typeof expr === "string") {
  80. expr_stmts.push(CopyInsn(dest, Loc.vari(expr)))
  81. } else if (expr.type === "unary") {
  82. const [source, stmts] = getSource(expr.arg)
  83. stmts.push(UnaryInsn(dest, expr.op, source))
  84. expr_stmts = stmts
  85. } else {
  86. const [left_source, left_stmts] = getSource(expr.left)
  87. const [right_source, right_stmts] = getSource(expr.right)
  88. expr_stmts = [...left_stmts, ...right_stmts, BinaryInsn(dest, left_source, expr.op, right_source)]
  89. }
  90. return expr_stmts
  91. }