diff options
author | Austin Adams <git@austinjadams.com> | 2019-02-04 16:00:30 -0500 |
---|---|---|
committer | Austin Adams <git@austinjadams.com> | 2019-02-04 16:00:30 -0500 |
commit | 94c265ea9eb5fe7969efc88f5c5bc43cb4c00958 (patch) | |
tree | eb679410a7f7ceaa54d4fa4fb4b137c980c33986 | |
parent | 66b7b8fac57f61ecb0d259f0b25830bffdb5f6d5 (diff) | |
download | novice-94c265ea9eb5fe7969efc88f5c5bc43cb4c00958.tar.gz novice-94c265ea9eb5fe7969efc88f5c5bc43cb4c00958.tar.xz |
Codegen: do fewer painful agonizing O(n) lookups
-rw-r--r-- | novice/assembler/codegen/base.ts | 42 | ||||
-rw-r--r-- | novice/assembler/opspec/complx.ts | 8 | ||||
-rw-r--r-- | novice/assembler/opspec/opspec.ts | 2 | ||||
-rw-r--r-- | novice/assembler/opspec/word.ts | 4 |
4 files changed, 39 insertions, 17 deletions
diff --git a/novice/assembler/codegen/base.ts b/novice/assembler/codegen/base.ts index ba202fa..3d4d918 100644 --- a/novice/assembler/codegen/base.ts +++ b/novice/assembler/codegen/base.ts @@ -12,13 +12,22 @@ interface ReassembleVictim { instrIdx: number; } +interface HasOp { op: string; } +type Lut<T extends HasOp> = {[op: string]: T[]}; + class BaseMachineCodeGenerator implements MachineCodeGenerator { - private isa: Isa; - private opSpec: PseudoOpSpec; + protected isa: Isa; + protected opSpec: PseudoOpSpec; + protected instrLut: Lut<InstructionSpec>; + protected aliasLut: Lut<AliasSpec>; + protected opLut: Lut<OpSpec>; public constructor(isa: Isa, opSpec: PseudoOpSpec) { this.isa = isa; this.opSpec = opSpec; + this.instrLut = this.genLut(this.isa.instructions); + this.aliasLut = this.genLut(this.isa.aliases); + this.opLut = this.genLut(this.opSpec.ops); } public gen(asm: Assembly): @@ -91,13 +100,27 @@ class BaseMachineCodeGenerator implements MachineCodeGenerator { return [symbtable, sections]; } + protected genLut<T extends HasOp>(ops: T[]): Lut<T> { + const lut: Lut<T> = {}; + + for (const op of ops) { + if (!(op.op in lut)) { + lut[op.op] = []; + } + lut[op.op].push(op); + } + + return lut; + } + private inflateInstr(instr: Instruction|PseudoOp, pc: number, symbtable: SymbTable|null): [number[], boolean] { if (instr.kind === 'pseudoop') { let match: OpSpec|null = null; + const candidates = this.opLut[instr.op] || []; - for (const op of this.opSpec.ops) { + for (const op of candidates) { if (this.opMatch(instr, op)) { match = op; break; @@ -124,9 +147,9 @@ class BaseMachineCodeGenerator implements MachineCodeGenerator { } } else { // If it's an alias, expand that mf - // TODO: Figure out a more efficient way than this. just a - // hashmap right? - for (const alias of this.isa.aliases) { + const aliasCandidates = this.aliasLut[instr.op] || []; + + for (const alias of aliasCandidates) { if (this.aliasMatch(instr, alias)) { if (!symbtable) { return [new Array<number>(alias.size), true]; @@ -151,10 +174,9 @@ class BaseMachineCodeGenerator implements MachineCodeGenerator { } let match: InstructionSpec|null = null; + const candidates = this.instrLut[instr.op] || []; - // TODO: Figure out a more efficient way than this. just a - // hashmap right? - for (const isaInstr of this.isa.instructions) { + for (const isaInstr of candidates) { if (this.instrMatch(instr, isaInstr)) { match = isaInstr; break; @@ -337,7 +359,7 @@ class BaseMachineCodeGenerator implements MachineCodeGenerator { } private opMatch(pseudoOp: PseudoOp, opSpec: OpSpec): boolean { - return pseudoOp.op === opSpec.name && ( + return pseudoOp.op === opSpec.op && ( !pseudoOp.operand && !opSpec.operands.length || opSpec.operands.length === 1 && !!pseudoOp.operand && pseudoOp.operand.kind === opSpec.operands[0].kind); diff --git a/novice/assembler/opspec/complx.ts b/novice/assembler/opspec/complx.ts index 85bd4bc..3b705e8 100644 --- a/novice/assembler/opspec/complx.ts +++ b/novice/assembler/opspec/complx.ts @@ -2,26 +2,26 @@ import { AsmContext, oneWord, OpOperands, PseudoOpSpec } from './opspec'; const complxOpSpec: PseudoOpSpec = { ops: [ - {name: 'fill', + {op: 'fill', operands: [{kind: 'int', name: 'num'}], asm: (ctx: AsmContext, operands: OpOperands) => // TODO: complain if too big [operands.ints.num & ~(-1 << ctx.isa.mem.addressability)]}, - {name: 'fill', + {op: 'fill', operands: [{kind: 'label', name: 'label'}], size: oneWord, asm: (ctx: AsmContext, operands: OpOperands) => // TODO: complain if nonexistent [ctx.symbtable[operands.labels.label]]}, - {name: 'stringz', + {op: 'stringz', operands: [{kind: 'string', name: 'str'}], asm: (ctx: AsmContext, operands: OpOperands) => // TODO: how is non-ascii handled? probably blow up operands.strings.str.split('').map(c => c.charCodeAt(0)).concat([0])}, - {name: 'blkw', + {op: 'blkw', operands: [{kind: 'int', name: 'count'}], asm: (ctx: AsmContext, operands: OpOperands) => { // TODO: needs to be randomized/uninitialized diff --git a/novice/assembler/opspec/opspec.ts b/novice/assembler/opspec/opspec.ts index 58dce93..d1f3923 100644 --- a/novice/assembler/opspec/opspec.ts +++ b/novice/assembler/opspec/opspec.ts @@ -17,7 +17,7 @@ interface OpOperands { } interface OpSpec { - name: string; + op: string; operands: OpOperandSpec[]; asm: (ctx: AsmContext, operands: OpOperands) => number[]; size?: (isa: Isa) => number; diff --git a/novice/assembler/opspec/word.ts b/novice/assembler/opspec/word.ts index 4125045..d9866ff 100644 --- a/novice/assembler/opspec/word.ts +++ b/novice/assembler/opspec/word.ts @@ -3,13 +3,13 @@ import { AsmContext, oneWord, OpOperands, PseudoOpSpec } from './opspec'; const wordOpSpec: PseudoOpSpec = { ops: [ - {name: 'word', + {op: 'word', operands: [{kind: 'int', name: 'num'}], asm: (ctx: AsmContext, operands: OpOperands) => // TODO: complain if too big [maskTo(operands.ints.num, ctx.isa.mem.addressability)]}, - {name: 'word', + {op: 'word', operands: [{kind: 'label', name: 'label'}], size: oneWord, asm: (ctx: AsmContext, operands: OpOperands) => |