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.

111 lines
3.4 KiB

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