@jhlagado/azm 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -69
- package/dist/src/api-artifacts.d.ts +20 -0
- package/dist/src/api-artifacts.js +165 -0
- package/dist/src/api-compile.d.ts +8 -2
- package/dist/src/api-compile.js +31 -230
- package/dist/src/api-register-contracts.d.ts +9 -0
- package/dist/src/api-register-contracts.js +77 -0
- package/dist/src/api-tooling.d.ts +2 -2
- package/dist/src/api-tooling.js +1 -1
- package/dist/src/assembly/address-planning.d.ts +1 -2
- package/dist/src/assembly/address-planning.js +119 -218
- package/dist/src/assembly/address-symbols.d.ts +12 -0
- package/dist/src/assembly/address-symbols.js +118 -0
- package/dist/src/assembly/fixup-emission.js +30 -48
- package/dist/src/assembly/program-emission.js +163 -164
- package/dist/src/cli/artifact-files.d.ts +15 -0
- package/dist/src/cli/artifact-files.js +86 -0
- package/dist/src/cli/parse-args.d.ts +6 -5
- package/dist/src/cli/parse-args.js +162 -136
- package/dist/src/cli/run.js +4 -1
- package/dist/src/cli/usage.d.ts +1 -0
- package/dist/src/cli/usage.js +33 -0
- package/dist/src/cli/write-artifacts.js +18 -91
- package/dist/src/core/compile.js +51 -274
- package/dist/src/core/conditional-assembly.d.ts +6 -0
- package/dist/src/core/conditional-assembly.js +181 -0
- package/dist/src/expansion/op-constant-expression.d.ts +3 -0
- package/dist/src/expansion/op-constant-expression.js +52 -0
- package/dist/src/expansion/op-expand-selected.d.ts +5 -0
- package/dist/src/expansion/op-expand-selected.js +143 -0
- package/dist/src/expansion/op-expansion.d.ts +5 -53
- package/dist/src/expansion/op-expansion.js +85 -815
- package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
- package/dist/src/expansion/op-instruction-instantiation.js +194 -0
- package/dist/src/expansion/op-local-labels.d.ts +8 -0
- package/dist/src/expansion/op-local-labels.js +166 -0
- package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
- package/dist/src/expansion/op-operand-splitting.js +44 -0
- package/dist/src/expansion/op-operands.d.ts +53 -0
- package/dist/src/expansion/op-operands.js +66 -0
- package/dist/src/expansion/op-selection.d.ts +18 -0
- package/dist/src/expansion/op-selection.js +172 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/model/diagnostic.d.ts +4 -0
- package/dist/src/model/diagnostic.js +4 -0
- package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
- package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
- package/dist/src/outputs/asm80-expressions.d.ts +5 -0
- package/dist/src/outputs/asm80-expressions.js +47 -0
- package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
- package/dist/src/outputs/asm80-instruction-operands.js +38 -0
- package/dist/src/outputs/asm80-instructions.d.ts +5 -0
- package/dist/src/outputs/asm80-instructions.js +272 -0
- package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
- package/dist/src/outputs/asm80-ld-operands.js +157 -0
- package/dist/src/outputs/asm80-strings.d.ts +4 -0
- package/dist/src/outputs/asm80-strings.js +14 -0
- package/dist/src/outputs/d8-files.d.ts +10 -0
- package/dist/src/outputs/d8-files.js +103 -0
- package/dist/src/outputs/d8-helpers.d.ts +21 -0
- package/dist/src/outputs/d8-helpers.js +136 -0
- package/dist/src/outputs/hex.js +26 -18
- package/dist/src/outputs/types.d.ts +16 -10
- package/dist/src/outputs/write-asm80.js +68 -597
- package/dist/src/outputs/write-d8.js +6 -216
- package/dist/src/register-contracts/accept-output.d.ts +2 -0
- package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
- package/dist/src/register-contracts/analyze-helpers.js +162 -0
- package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
- package/dist/src/register-contracts/analyze.js +73 -0
- package/dist/src/register-contracts/annotate.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
- package/dist/src/register-contracts/annotations.d.ts +8 -0
- package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
- package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
- package/dist/src/register-contracts/boundaryHints.js +24 -0
- package/dist/src/register-contracts/carriers.d.ts +2 -0
- package/dist/src/register-contracts/constants.d.ts +4 -0
- package/dist/src/register-contracts/constants.js +51 -0
- package/dist/src/register-contracts/controlFlow.d.ts +5 -0
- package/dist/src/register-contracts/controlFlow.js +55 -0
- package/dist/src/register-contracts/fix.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/fix.js +47 -30
- package/dist/src/register-contracts/instruction-head.d.ts +2 -0
- package/dist/src/register-contracts/instruction-head.js +3 -0
- package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
- package/dist/src/register-contracts/instruction-operands.js +101 -0
- package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
- package/dist/src/register-contracts/instruction-predicates.js +44 -0
- package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
- package/dist/src/register-contracts/interfaceContracts.js +68 -0
- package/dist/src/register-contracts/liveness.d.ts +3 -0
- package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
- package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
- package/dist/src/register-contracts/operand-register-name.js +13 -0
- package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
- package/dist/src/{register-care → register-contracts}/profiles.js +2 -2
- package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
- package/dist/src/register-contracts/programModel-boundaries.js +64 -0
- package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
- package/dist/src/register-contracts/programModel-routines.js +128 -0
- package/dist/src/register-contracts/programModel.d.ts +3 -0
- package/dist/src/register-contracts/programModel.js +14 -0
- package/dist/src/register-contracts/report.d.ts +5 -0
- package/dist/src/{register-care → register-contracts}/report.js +34 -17
- package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
- package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
- package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
- package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
- package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
- package/dist/src/register-contracts/smartCommentParsing.js +80 -0
- package/dist/src/register-contracts/smartComments.d.ts +5 -0
- package/dist/src/register-contracts/smartComments.js +92 -0
- package/dist/src/register-contracts/summaries.d.ts +12 -0
- package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
- package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
- package/dist/src/register-contracts/summary-boundary.js +40 -0
- package/dist/src/register-contracts/summary-contract.d.ts +2 -0
- package/dist/src/register-contracts/summary-contract.js +45 -0
- package/dist/src/register-contracts/summary-result.d.ts +7 -0
- package/dist/src/register-contracts/summary-result.js +122 -0
- package/dist/src/register-contracts/summary-state.d.ts +23 -0
- package/dist/src/register-contracts/summary-state.js +88 -0
- package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
- package/dist/src/register-contracts/summary-token-transfer.js +67 -0
- package/dist/src/register-contracts/summary.d.ts +3 -0
- package/dist/src/register-contracts/summary.js +266 -0
- package/dist/src/register-contracts/tooling.d.ts +57 -0
- package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
- package/dist/src/register-contracts/types.d.ts +188 -0
- package/dist/src/semantics/binary-operators.d.ts +2 -0
- package/dist/src/semantics/binary-operators.js +15 -0
- package/dist/src/semantics/byte-functions.d.ts +2 -0
- package/dist/src/semantics/byte-functions.js +7 -0
- package/dist/src/semantics/constant-operator-types.d.ts +10 -0
- package/dist/src/semantics/constant-operator-types.js +1 -0
- package/dist/src/semantics/constant-operators.d.ts +3 -0
- package/dist/src/semantics/constant-operators.js +3 -0
- package/dist/src/semantics/diagnostics.d.ts +3 -0
- package/dist/src/semantics/diagnostics.js +10 -0
- package/dist/src/semantics/expression-evaluation.d.ts +11 -19
- package/dist/src/semantics/expression-evaluation.js +22 -334
- package/dist/src/semantics/layout-evaluation.d.ts +23 -0
- package/dist/src/semantics/layout-evaluation.js +202 -0
- package/dist/src/semantics/layout-format.d.ts +5 -0
- package/dist/src/semantics/layout-format.js +31 -0
- package/dist/src/semantics/layout-path.d.ts +24 -0
- package/dist/src/semantics/layout-path.js +58 -0
- package/dist/src/semantics/unary-operators.d.ts +2 -0
- package/dist/src/semantics/unary-operators.js +8 -0
- package/dist/src/source/line-comment-scanner.d.ts +1 -0
- package/dist/src/source/line-comment-scanner.js +51 -0
- package/dist/src/source/strip-line-comment.js +8 -44
- package/dist/src/syntax/directive-aliases.js +36 -22
- package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
- package/dist/src/syntax/expression-tokenizer.js +310 -0
- package/dist/src/syntax/parse-directive-statement.d.ts +14 -0
- package/dist/src/syntax/parse-directive-statement.js +307 -0
- package/dist/src/syntax/parse-expression.d.ts +2 -2
- package/dist/src/syntax/parse-expression.js +7 -568
- package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
- package/dist/src/syntax/parse-layout-declarations.js +180 -0
- package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
- package/dist/src/syntax/parse-layout-expression.js +175 -0
- package/dist/src/syntax/parse-line.js +4 -272
- package/dist/src/syntax/parse-token-expression.d.ts +3 -0
- package/dist/src/syntax/parse-token-expression.js +133 -0
- package/dist/src/tooling/case-style.js +47 -30
- package/dist/src/z80/effect-groups.d.ts +38 -0
- package/dist/src/z80/effect-groups.js +265 -0
- package/dist/src/z80/effect-units.d.ts +18 -0
- package/dist/src/z80/effect-units.js +165 -0
- package/dist/src/z80/effects.d.ts +1 -1
- package/dist/src/z80/effects.js +94 -557
- package/dist/src/z80/encode-core.d.ts +2 -0
- package/dist/src/z80/encode-core.js +42 -0
- package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
- package/dist/src/z80/encode-ld-helpers.js +172 -0
- package/dist/src/z80/encode-ld.d.ts +2 -0
- package/dist/src/z80/encode-ld.js +285 -0
- package/dist/src/z80/encode.js +190 -542
- package/dist/src/z80/ld-support.d.ts +3 -0
- package/dist/src/z80/ld-support.js +146 -0
- package/dist/src/z80/operand-split-state.d.ts +8 -0
- package/dist/src/z80/operand-split-state.js +46 -0
- package/dist/src/z80/operand-split.d.ts +1 -0
- package/dist/src/z80/operand-split.js +13 -0
- package/dist/src/z80/parse-basic.d.ts +4 -0
- package/dist/src/z80/parse-basic.js +39 -0
- package/dist/src/z80/parse-branch.d.ts +4 -0
- package/dist/src/z80/parse-branch.js +218 -0
- package/dist/src/z80/parse-conditions.d.ts +6 -0
- package/dist/src/z80/parse-conditions.js +10 -0
- package/dist/src/z80/parse-exchange.d.ts +2 -0
- package/dist/src/z80/parse-exchange.js +30 -0
- package/dist/src/z80/parse-instruction.js +224 -1010
- package/dist/src/z80/parse-io-control.d.ts +5 -0
- package/dist/src/z80/parse-io-control.js +108 -0
- package/dist/src/z80/parse-ld.d.ts +2 -0
- package/dist/src/z80/parse-ld.js +83 -0
- package/dist/src/z80/parse-operands.d.ts +41 -0
- package/dist/src/z80/parse-operands.js +259 -0
- package/docs/reference/cli.md +42 -35
- package/docs/reference/tooling-api.md +20 -16
- package/package.json +1 -1
- package/dist/src/register-care/accept-output.d.ts +0 -2
- package/dist/src/register-care/analyze.js +0 -166
- package/dist/src/register-care/annotate.d.ts +0 -11
- package/dist/src/register-care/annotations.d.ts +0 -8
- package/dist/src/register-care/boundaryHints.d.ts +0 -3
- package/dist/src/register-care/boundaryHints.js +0 -80
- package/dist/src/register-care/carriers.d.ts +0 -2
- package/dist/src/register-care/controlFlow.d.ts +0 -5
- package/dist/src/register-care/controlFlow.js +0 -38
- package/dist/src/register-care/fix.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.js +0 -129
- package/dist/src/register-care/liveness.d.ts +0 -3
- package/dist/src/register-care/programModel.d.ts +0 -3
- package/dist/src/register-care/programModel.js +0 -266
- package/dist/src/register-care/report.d.ts +0 -5
- package/dist/src/register-care/routine-summaries.d.ts +0 -6
- package/dist/src/register-care/smartComments.d.ts +0 -5
- package/dist/src/register-care/smartComments.js +0 -243
- package/dist/src/register-care/summaries.d.ts +0 -12
- package/dist/src/register-care/summary.d.ts +0 -3
- package/dist/src/register-care/summary.js +0 -474
- package/dist/src/register-care/tooling.d.ts +0 -43
- package/dist/src/register-care/types.d.ts +0 -172
- /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
- /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
- /package/dist/src/{register-care → register-contracts}/types.js +0 -0
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
import { getZ80InstructionEffect } from '../z80/effects.js';
|
|
2
|
-
import { instructionHead, instructionOperand, instructionOperandCount, isAccumulatorSelfOperand, isImmediateZeroOperand, isPureTokenTransferInstruction, isRegisterOperand, isUnconditionalReturnInstruction, regName, } from './instruction-shape.js';
|
|
3
|
-
import { precedingCServiceName } from './boundaryHints.js';
|
|
4
|
-
import { expandCarrierList } from './carriers.js';
|
|
5
|
-
import { rstServiceTargetName, rstTargetName } from './profiles.js';
|
|
6
|
-
const FLAG_UNIT_LIST = ['carry', 'zero', 'sign', 'parity', 'halfCarry'];
|
|
7
|
-
const TRACKED_UNITS = [
|
|
8
|
-
'A',
|
|
9
|
-
'B',
|
|
10
|
-
'C',
|
|
11
|
-
'D',
|
|
12
|
-
'E',
|
|
13
|
-
'H',
|
|
14
|
-
'L',
|
|
15
|
-
'IXH',
|
|
16
|
-
'IXL',
|
|
17
|
-
'IYH',
|
|
18
|
-
'IYL',
|
|
19
|
-
...FLAG_UNIT_LIST,
|
|
20
|
-
];
|
|
21
|
-
const GENERAL_REGISTER_UNITS = new Set(['A', 'B', 'C', 'D', 'E', 'H', 'L']);
|
|
22
|
-
const CONTRACT_FLAG_UNITS = new Set(['carry', 'zero']);
|
|
23
|
-
const STACK_POINTER_UNITS = new Set(['SPH', 'SPL']);
|
|
24
|
-
const REGISTER_PAIRS = [
|
|
25
|
-
['B', 'C'],
|
|
26
|
-
['D', 'E'],
|
|
27
|
-
['H', 'L'],
|
|
28
|
-
];
|
|
29
|
-
function unique(items) {
|
|
30
|
-
return [...new Set(items)];
|
|
31
|
-
}
|
|
32
|
-
function isTrackedUnit(unit) {
|
|
33
|
-
return TRACKED_UNITS.includes(unit);
|
|
34
|
-
}
|
|
35
|
-
function getRegisterUnits(name) {
|
|
36
|
-
return expandCarrierList([name]);
|
|
37
|
-
}
|
|
38
|
-
function readToken(tokens, unit) {
|
|
39
|
-
return tokens.get(unit) ?? { origin: 'unknown' };
|
|
40
|
-
}
|
|
41
|
-
function semanticReadOrigins(tokens, units) {
|
|
42
|
-
const origins = [];
|
|
43
|
-
for (const unit of units) {
|
|
44
|
-
if (!isTrackedUnit(unit)) {
|
|
45
|
-
origins.push(unit);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const token = readToken(tokens, unit);
|
|
49
|
-
if (token.origin !== 'unknown' && token.origin !== 'produced')
|
|
50
|
-
origins.push(token.origin);
|
|
51
|
-
}
|
|
52
|
-
return origins;
|
|
53
|
-
}
|
|
54
|
-
function markProducedReadsConsumed(tokens, consumedProduced, reads, writes, item) {
|
|
55
|
-
for (const unit of reads) {
|
|
56
|
-
if (!isTrackedUnit(unit) || writes.has(unit))
|
|
57
|
-
continue;
|
|
58
|
-
if (item !== undefined && instructionHead(item) === 'cp' && unit === 'A')
|
|
59
|
-
continue;
|
|
60
|
-
if (readToken(tokens, unit).origin === 'produced')
|
|
61
|
-
consumedProduced.add(unit);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function tokenPreservesUnit(token, unit) {
|
|
65
|
-
return token?.origin === unit;
|
|
66
|
-
}
|
|
67
|
-
function isOpaqueBoundary(item, effect) {
|
|
68
|
-
if (effect.control.kind === 'call' || effect.control.kind === 'rst')
|
|
69
|
-
return true;
|
|
70
|
-
return (effect.control.kind === 'jump' &&
|
|
71
|
-
(instructionHead(item) === 'jp' || instructionHead(item) === 'jp-cc') &&
|
|
72
|
-
!effect.control.conditional &&
|
|
73
|
-
Boolean(effect.control.target) &&
|
|
74
|
-
!effect.control.target?.startsWith('.'));
|
|
75
|
-
}
|
|
76
|
-
function boundarySummary(routine, index, summaries) {
|
|
77
|
-
const item = routine.instructions[index];
|
|
78
|
-
if (!item)
|
|
79
|
-
return undefined;
|
|
80
|
-
const effect = getZ80InstructionEffect(item.instruction);
|
|
81
|
-
if (effect.control.kind === 'call' && effect.control.target) {
|
|
82
|
-
return summaries.get(effect.control.target);
|
|
83
|
-
}
|
|
84
|
-
if (effect.control.kind === 'jump' &&
|
|
85
|
-
(instructionHead(item) === 'jp' || instructionHead(item) === 'jp-cc') &&
|
|
86
|
-
effect.control.target &&
|
|
87
|
-
!effect.control.target.startsWith('.') &&
|
|
88
|
-
!routine.labels.includes(effect.control.target)) {
|
|
89
|
-
return summaries.get(effect.control.target);
|
|
90
|
-
}
|
|
91
|
-
if (effect.control.kind === 'rst' && effect.control.vector !== undefined) {
|
|
92
|
-
const service = precedingCServiceName(routine.instructions[index - 1]);
|
|
93
|
-
if (service) {
|
|
94
|
-
const serviceSummary = summaries.get(rstServiceTargetName(effect.control.vector, service));
|
|
95
|
-
if (serviceSummary)
|
|
96
|
-
return serviceSummary;
|
|
97
|
-
}
|
|
98
|
-
return summaries.get(rstTargetName(effect.control.vector));
|
|
99
|
-
}
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
|
-
function relationKey(relation) {
|
|
103
|
-
return `${relation.out.join(',')}<- ${relation.from.join(',')}`;
|
|
104
|
-
}
|
|
105
|
-
function addRelation(out, relation) {
|
|
106
|
-
if (relation.out.length === 0 || relation.from.length === 0)
|
|
107
|
-
return;
|
|
108
|
-
const key = relationKey(relation);
|
|
109
|
-
if (!out.some((existing) => relationKey(existing) === key))
|
|
110
|
-
out.push(relation);
|
|
111
|
-
}
|
|
112
|
-
function addContractRelation(out, relation) {
|
|
113
|
-
if (relation.out.length === 0)
|
|
114
|
-
return;
|
|
115
|
-
const key = relationKey(relation);
|
|
116
|
-
if (!out.some((existing) => relationKey(existing) === key))
|
|
117
|
-
out.push(relation);
|
|
118
|
-
}
|
|
119
|
-
function pairRelation(tokens, out) {
|
|
120
|
-
const from = [];
|
|
121
|
-
for (const unit of out) {
|
|
122
|
-
const token = tokens.get(unit);
|
|
123
|
-
if (!token || token.origin === 'unknown' || token.origin === 'produced')
|
|
124
|
-
return undefined;
|
|
125
|
-
from.push(token.origin);
|
|
126
|
-
}
|
|
127
|
-
if (out.every((unit, idx) => unit === from[idx]))
|
|
128
|
-
return undefined;
|
|
129
|
-
if (out.some((unit, idx) => unit === from[idx]))
|
|
130
|
-
return undefined;
|
|
131
|
-
return { out, from };
|
|
132
|
-
}
|
|
133
|
-
function producedPairRelation(tokens, consumedProduced, out) {
|
|
134
|
-
if (out.some((unit) => tokens.get(unit)?.origin !== 'produced' || consumedProduced.has(unit))) {
|
|
135
|
-
return undefined;
|
|
136
|
-
}
|
|
137
|
-
return { out, from: [] };
|
|
138
|
-
}
|
|
139
|
-
function withImpliedFlagUnits(units) {
|
|
140
|
-
return unique(units);
|
|
141
|
-
}
|
|
142
|
-
function contractOutRelation(contractIn, contractOut) {
|
|
143
|
-
if (contractOut.length === 0)
|
|
144
|
-
return undefined;
|
|
145
|
-
return {
|
|
146
|
-
out: contractOut,
|
|
147
|
-
from: contractIn.length === contractOut.length ? contractIn : [],
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function isUnconditionalReturn(item) {
|
|
151
|
-
return isUnconditionalReturnInstruction(item);
|
|
152
|
-
}
|
|
153
|
-
function isPureTokenTransfer(item) {
|
|
154
|
-
return isPureTokenTransferInstruction(item);
|
|
155
|
-
}
|
|
156
|
-
function isCarryClearBeforeSbcHl(item, next) {
|
|
157
|
-
const head = instructionHead(item).toLowerCase();
|
|
158
|
-
if (head !== 'or' && head !== 'and')
|
|
159
|
-
return false;
|
|
160
|
-
if (!isAccumulatorSelfOperand(item))
|
|
161
|
-
return false;
|
|
162
|
-
return (next !== undefined &&
|
|
163
|
-
instructionHead(next) === 'sbc' &&
|
|
164
|
-
isRegisterOperand(next, 0, 'HL'));
|
|
165
|
-
}
|
|
166
|
-
function intentOutputUnits(item) {
|
|
167
|
-
const head = instructionHead(item).toLowerCase();
|
|
168
|
-
if (head === 'scf' || head === 'ccf')
|
|
169
|
-
return ['carry'];
|
|
170
|
-
if (head === 'cp')
|
|
171
|
-
return isImmediateZeroOperand(item) ? ['A', 'carry', 'zero'] : ['carry', 'zero'];
|
|
172
|
-
if ((head === 'or' || head === 'and' || head === 'xor') && isAccumulatorSelfOperand(item)) {
|
|
173
|
-
return ['A', 'carry', 'zero'];
|
|
174
|
-
}
|
|
175
|
-
return [];
|
|
176
|
-
}
|
|
177
|
-
function isMechanicalResidueWrite(item, unit) {
|
|
178
|
-
const head = instructionHead(item).toLowerCase();
|
|
179
|
-
if (head === 'djnz')
|
|
180
|
-
return unit === 'B';
|
|
181
|
-
if (head === 'ldi' || head === 'ldir' || head === 'ldd' || head === 'lddr') {
|
|
182
|
-
return (unit === 'B' || unit === 'C' || unit === 'D' || unit === 'E' || unit === 'H' || unit === 'L');
|
|
183
|
-
}
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
function applyPureTokenTransfer(tokens, consumedProduced, item) {
|
|
187
|
-
const inst = item.instruction;
|
|
188
|
-
const head = instructionHead(item).toLowerCase();
|
|
189
|
-
if (head === 'ld' && instructionOperandCount(inst) === 2) {
|
|
190
|
-
const dst = instructionOperand(inst, 0);
|
|
191
|
-
const src = instructionOperand(inst, 1);
|
|
192
|
-
const dstName = regName(dst);
|
|
193
|
-
if (dstName === undefined)
|
|
194
|
-
return [];
|
|
195
|
-
const dstUnits = getRegisterUnits(dstName);
|
|
196
|
-
if (!dstUnits)
|
|
197
|
-
return [];
|
|
198
|
-
const srcName = regName(src);
|
|
199
|
-
const srcUnits = srcName ? getRegisterUnits(srcName) : undefined;
|
|
200
|
-
if (srcUnits && srcUnits.length === dstUnits.length) {
|
|
201
|
-
dstUnits.forEach((unit, index) => {
|
|
202
|
-
tokens.set(unit, readToken(tokens, srcUnits[index]));
|
|
203
|
-
if (readToken(tokens, srcUnits[index]).origin === 'produced') {
|
|
204
|
-
consumedProduced.add(srcUnits[index]);
|
|
205
|
-
}
|
|
206
|
-
consumedProduced.delete(unit);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
for (const unit of dstUnits) {
|
|
211
|
-
tokens.set(unit, { origin: 'produced' });
|
|
212
|
-
consumedProduced.delete(unit);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return dstUnits;
|
|
216
|
-
}
|
|
217
|
-
if (head === 'ex' && instructionOperandCount(inst) === 2) {
|
|
218
|
-
const left = instructionOperand(inst, 0);
|
|
219
|
-
const right = instructionOperand(inst, 1);
|
|
220
|
-
const leftName = regName(left);
|
|
221
|
-
const rightName = regName(right);
|
|
222
|
-
if (leftName === undefined || rightName === undefined)
|
|
223
|
-
return [];
|
|
224
|
-
const leftUnits = getRegisterUnits(leftName);
|
|
225
|
-
const rightUnits = getRegisterUnits(rightName);
|
|
226
|
-
if (!leftUnits || !rightUnits || leftUnits.length !== rightUnits.length)
|
|
227
|
-
return [];
|
|
228
|
-
const leftTokens = leftUnits.map((unit) => readToken(tokens, unit));
|
|
229
|
-
const rightTokens = rightUnits.map((unit) => readToken(tokens, unit));
|
|
230
|
-
leftUnits.forEach((unit, index) => tokens.set(unit, rightTokens[index] ?? { origin: 'unknown' }));
|
|
231
|
-
rightUnits.forEach((unit, index) => tokens.set(unit, leftTokens[index] ?? { origin: 'unknown' }));
|
|
232
|
-
return unique([...leftUnits, ...rightUnits]);
|
|
233
|
-
}
|
|
234
|
-
return [];
|
|
235
|
-
}
|
|
236
|
-
function applyKnownBoundarySummary(tokens, consumedProduced, intendedProduced, directMayWrite, summary) {
|
|
237
|
-
for (const relation of summary.valueRelations) {
|
|
238
|
-
const sameCarrierRelation = relation.out.length === relation.from.length &&
|
|
239
|
-
relation.out.every((unit, index) => unit === relation.from[index]);
|
|
240
|
-
relation.out.forEach((unit, index) => {
|
|
241
|
-
if (!sameCarrierRelation &&
|
|
242
|
-
relation.from.length === relation.out.length &&
|
|
243
|
-
relation.from[index]) {
|
|
244
|
-
tokens.set(unit, readToken(tokens, relation.from[index]));
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
tokens.set(unit, { origin: 'produced' });
|
|
248
|
-
consumedProduced.delete(unit);
|
|
249
|
-
if (CONTRACT_FLAG_UNITS.has(unit))
|
|
250
|
-
intendedProduced.add(unit);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
for (const unit of summary.mayWrite) {
|
|
255
|
-
if (STACK_POINTER_UNITS.has(unit))
|
|
256
|
-
continue;
|
|
257
|
-
if (isTrackedUnit(unit)) {
|
|
258
|
-
tokens.set(unit, { origin: 'unknown' });
|
|
259
|
-
consumedProduced.delete(unit);
|
|
260
|
-
intendedProduced.delete(unit);
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
directMayWrite.push(unit);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
export function inferRoutineSummary(routine, boundarySummaries = new Map()) {
|
|
268
|
-
const tokens = new Map();
|
|
269
|
-
for (const unit of TRACKED_UNITS)
|
|
270
|
-
tokens.set(unit, { origin: unit });
|
|
271
|
-
const stack = [];
|
|
272
|
-
const mayRead = [];
|
|
273
|
-
const directMayWrite = [];
|
|
274
|
-
const consumedProduced = new Set();
|
|
275
|
-
const intendedProduced = new Set();
|
|
276
|
-
let stackBalanced = true;
|
|
277
|
-
let hasUnknownStackEffect = false;
|
|
278
|
-
for (let index = 0; index < routine.instructions.length; index += 1) {
|
|
279
|
-
const item = routine.instructions[index];
|
|
280
|
-
const effect = getZ80InstructionEffect(item.instruction);
|
|
281
|
-
const knownBoundary = boundarySummary(routine, index, boundarySummaries);
|
|
282
|
-
const carryClearBeforeSbcHl = isCarryClearBeforeSbcHl(item, routine.instructions[index + 1]);
|
|
283
|
-
const expectedTerminalReturn = index === routine.instructions.length - 1 && isUnconditionalReturn(item);
|
|
284
|
-
const effectWrites = new Set(effect.writes);
|
|
285
|
-
const instructionIntentOutputs = carryClearBeforeSbcHl ? [] : intentOutputUnits(item);
|
|
286
|
-
const semanticReads = carryClearBeforeSbcHl
|
|
287
|
-
? effect.reads.filter((unit) => unit !== 'A')
|
|
288
|
-
: effect.reads;
|
|
289
|
-
if (effect.stack.kind !== 'push' && !isPureTokenTransfer(item)) {
|
|
290
|
-
mayRead.push(...semanticReadOrigins(tokens, semanticReads));
|
|
291
|
-
markProducedReadsConsumed(tokens, consumedProduced, semanticReads, effectWrites, item);
|
|
292
|
-
}
|
|
293
|
-
if (instructionHead(item).toLowerCase() === 'djnz') {
|
|
294
|
-
for (const unit of TRACKED_UNITS) {
|
|
295
|
-
if (readToken(tokens, unit).origin === 'produced')
|
|
296
|
-
consumedProduced.add(unit);
|
|
297
|
-
intendedProduced.delete(unit);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
if (knownBoundary) {
|
|
301
|
-
mayRead.push(...semanticReadOrigins(tokens, knownBoundary.mayRead));
|
|
302
|
-
markProducedReadsConsumed(tokens, consumedProduced, knownBoundary.mayRead, new Set());
|
|
303
|
-
}
|
|
304
|
-
if (effect.stack.kind === 'push') {
|
|
305
|
-
stack.push(effect.stack.units.map((unit) => readToken(tokens, unit)));
|
|
306
|
-
}
|
|
307
|
-
else if (effect.stack.kind === 'pop') {
|
|
308
|
-
const popped = stack.pop();
|
|
309
|
-
if (!popped) {
|
|
310
|
-
stackBalanced = false;
|
|
311
|
-
for (const unit of effect.stack.units) {
|
|
312
|
-
tokens.set(unit, { origin: 'unknown' });
|
|
313
|
-
intendedProduced.delete(unit);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
else if (popped.length !== effect.stack.units.length) {
|
|
317
|
-
for (const unit of effect.stack.units) {
|
|
318
|
-
tokens.set(unit, { origin: 'unknown' });
|
|
319
|
-
consumedProduced.delete(unit);
|
|
320
|
-
intendedProduced.delete(unit);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
effect.stack.units.forEach((unit, idx) => {
|
|
325
|
-
tokens.set(unit, popped[idx] ?? { origin: 'unknown' });
|
|
326
|
-
consumedProduced.delete(unit);
|
|
327
|
-
intendedProduced.delete(unit);
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
else if (effect.stack.kind === 'exchangeTop') {
|
|
332
|
-
hasUnknownStackEffect = true;
|
|
333
|
-
for (const unit of effect.stack.units) {
|
|
334
|
-
tokens.set(unit, { origin: 'unknown' });
|
|
335
|
-
consumedProduced.delete(unit);
|
|
336
|
-
intendedProduced.delete(unit);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
else if (effect.stack.kind === 'unknown' &&
|
|
340
|
-
!expectedTerminalReturn &&
|
|
341
|
-
(!knownBoundary || !knownBoundary.stackBalanced || knownBoundary.hasUnknownStackEffect)) {
|
|
342
|
-
hasUnknownStackEffect = true;
|
|
343
|
-
}
|
|
344
|
-
const transferWrites = new Set(isPureTokenTransfer(item) ? applyPureTokenTransfer(tokens, consumedProduced, item) : []);
|
|
345
|
-
if (knownBoundary) {
|
|
346
|
-
applyKnownBoundarySummary(tokens, consumedProduced, intendedProduced, directMayWrite, knownBoundary);
|
|
347
|
-
}
|
|
348
|
-
else if (isOpaqueBoundary(item, effect)) {
|
|
349
|
-
for (const unit of TRACKED_UNITS) {
|
|
350
|
-
tokens.set(unit, { origin: 'unknown' });
|
|
351
|
-
consumedProduced.delete(unit);
|
|
352
|
-
intendedProduced.delete(unit);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
for (const unit of effect.writes) {
|
|
356
|
-
if (STACK_POINTER_UNITS.has(unit))
|
|
357
|
-
continue;
|
|
358
|
-
if (effect.stack.kind === 'pop' && effect.stack.units.includes(unit) && isTrackedUnit(unit)) {
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
if (transferWrites.has(unit) && isTrackedUnit(unit))
|
|
362
|
-
continue;
|
|
363
|
-
if (unit === 'A' &&
|
|
364
|
-
(instructionHead(item).toLowerCase() === 'or' || instructionHead(item).toLowerCase() === 'and') &&
|
|
365
|
-
isAccumulatorSelfOperand(item)) {
|
|
366
|
-
if (!carryClearBeforeSbcHl)
|
|
367
|
-
intendedProduced.add(unit);
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
if (isTrackedUnit(unit)) {
|
|
371
|
-
tokens.set(unit, { origin: isMechanicalResidueWrite(item, unit) ? 'unknown' : 'produced' });
|
|
372
|
-
consumedProduced.delete(unit);
|
|
373
|
-
if (instructionIntentOutputs.includes(unit))
|
|
374
|
-
intendedProduced.add(unit);
|
|
375
|
-
else
|
|
376
|
-
intendedProduced.delete(unit);
|
|
377
|
-
}
|
|
378
|
-
else {
|
|
379
|
-
directMayWrite.push(unit);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
for (const unit of instructionIntentOutputs) {
|
|
383
|
-
if (!isTrackedUnit(unit) || effectWrites.has(unit))
|
|
384
|
-
continue;
|
|
385
|
-
intendedProduced.add(unit);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
if (stack.length !== 0)
|
|
389
|
-
stackBalanced = false;
|
|
390
|
-
const mayWrite = [...directMayWrite];
|
|
391
|
-
const preserved = [];
|
|
392
|
-
const valueRelations = [];
|
|
393
|
-
const outputUnits = new Set();
|
|
394
|
-
for (const pair of REGISTER_PAIRS) {
|
|
395
|
-
const relation = producedPairRelation(tokens, consumedProduced, pair);
|
|
396
|
-
if (relation) {
|
|
397
|
-
addContractRelation(valueRelations, relation);
|
|
398
|
-
for (const unit of pair)
|
|
399
|
-
outputUnits.add(unit);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
for (const unit of TRACKED_UNITS) {
|
|
403
|
-
if (outputUnits.has(unit))
|
|
404
|
-
continue;
|
|
405
|
-
const current = tokens.get(unit);
|
|
406
|
-
const eligibleProduced = current?.origin === 'produced' &&
|
|
407
|
-
(GENERAL_REGISTER_UNITS.has(unit) ||
|
|
408
|
-
(CONTRACT_FLAG_UNITS.has(unit) && intendedProduced.has(unit)));
|
|
409
|
-
const eligiblePreservedIntent = current?.origin === unit && GENERAL_REGISTER_UNITS.has(unit) && intendedProduced.has(unit);
|
|
410
|
-
if ((eligibleProduced || eligiblePreservedIntent) && !consumedProduced.has(unit)) {
|
|
411
|
-
addContractRelation(valueRelations, {
|
|
412
|
-
out: [unit],
|
|
413
|
-
from: eligiblePreservedIntent ? [unit] : [],
|
|
414
|
-
});
|
|
415
|
-
outputUnits.add(unit);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
for (const unit of TRACKED_UNITS) {
|
|
419
|
-
const current = tokens.get(unit);
|
|
420
|
-
if (tokenPreservesUnit(current, unit)) {
|
|
421
|
-
preserved.push(unit);
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
if (outputUnits.has(unit))
|
|
425
|
-
continue;
|
|
426
|
-
mayWrite.push(unit);
|
|
427
|
-
}
|
|
428
|
-
for (const pair of REGISTER_PAIRS) {
|
|
429
|
-
const relation = pairRelation(tokens, pair);
|
|
430
|
-
if (relation)
|
|
431
|
-
addRelation(valueRelations, relation);
|
|
432
|
-
}
|
|
433
|
-
mayRead.push(...valueRelations.flatMap((relation) => relation.from));
|
|
434
|
-
return {
|
|
435
|
-
name: routine.name,
|
|
436
|
-
mayRead: unique(mayRead),
|
|
437
|
-
mayWrite: unique(mayWrite),
|
|
438
|
-
preserved: unique(preserved),
|
|
439
|
-
valueRelations,
|
|
440
|
-
stackBalanced,
|
|
441
|
-
hasUnknownStackEffect,
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
export function applyRoutineContract(summary, contract) {
|
|
445
|
-
const contractIn = withImpliedFlagUnits(contract.in);
|
|
446
|
-
const contractOut = withImpliedFlagUnits(contract.out);
|
|
447
|
-
const contractClobbers = withImpliedFlagUnits(contract.clobbers);
|
|
448
|
-
const contractPreserves = withImpliedFlagUnits(contract.preserves);
|
|
449
|
-
const outputSet = new Set(contractOut);
|
|
450
|
-
const preservedSet = new Set(contractPreserves);
|
|
451
|
-
const inferredWrites = withImpliedFlagUnits(summary.mayWrite);
|
|
452
|
-
const baseMayWrite = contract.complete
|
|
453
|
-
? inferredWrites.filter((unit) => FLAG_UNIT_LIST.includes(unit))
|
|
454
|
-
: inferredWrites;
|
|
455
|
-
const mayWrite = baseMayWrite.filter((unit) => !outputSet.has(unit) && !preservedSet.has(unit));
|
|
456
|
-
for (const unit of contractClobbers) {
|
|
457
|
-
if (!outputSet.has(unit) && !preservedSet.has(unit) && !mayWrite.includes(unit)) {
|
|
458
|
-
mayWrite.push(unit);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
const mayWriteSet = new Set(withImpliedFlagUnits(mayWrite));
|
|
462
|
-
const preserved = unique([...summary.preserved, ...contractPreserves]).filter((unit) => !outputSet.has(unit) && !mayWriteSet.has(unit));
|
|
463
|
-
const valueRelations = [...summary.valueRelations];
|
|
464
|
-
const relation = contractOutRelation(contractIn, contractOut);
|
|
465
|
-
if (relation)
|
|
466
|
-
addContractRelation(valueRelations, relation);
|
|
467
|
-
return {
|
|
468
|
-
...summary,
|
|
469
|
-
mayRead: unique(contractIn),
|
|
470
|
-
mayWrite,
|
|
471
|
-
preserved,
|
|
472
|
-
valueRelations,
|
|
473
|
-
};
|
|
474
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { Diagnostic } from '../model/diagnostic.js';
|
|
2
|
-
import type { LoadedProgram } from '../tooling/api.js';
|
|
3
|
-
import type { AnalyzeRegisterCareOptions, RegisterCareOutputCandidate, RegisterCareUnit } from './types.js';
|
|
4
|
-
export interface RegisterCareTextEdit {
|
|
5
|
-
file: string;
|
|
6
|
-
line: number;
|
|
7
|
-
column: number;
|
|
8
|
-
text: string;
|
|
9
|
-
}
|
|
10
|
-
export interface RegisterCareCodeAction {
|
|
11
|
-
title: string;
|
|
12
|
-
kind: 'quickfix';
|
|
13
|
-
edit: RegisterCareTextEdit;
|
|
14
|
-
}
|
|
15
|
-
export interface RegisterCareCandidateDiagnostic {
|
|
16
|
-
kind: 'register-care-output-candidate';
|
|
17
|
-
severity: 'info';
|
|
18
|
-
file: string;
|
|
19
|
-
line: number;
|
|
20
|
-
column: number;
|
|
21
|
-
routine: string;
|
|
22
|
-
carriers: RegisterCareUnit[];
|
|
23
|
-
autoFixable: boolean;
|
|
24
|
-
message: string;
|
|
25
|
-
codeAction?: RegisterCareCodeAction;
|
|
26
|
-
}
|
|
27
|
-
export interface AnalyzeRegisterCareForToolsOptions extends Omit<AnalyzeRegisterCareOptions, 'emitReport' | 'emitInterface' | 'emitAnnotations' | 'fixRegisterContracts'> {
|
|
28
|
-
emitReport?: boolean;
|
|
29
|
-
emitInterface?: boolean;
|
|
30
|
-
/** Back-compat alias for registerCareProfile used by some tooling integrations. */
|
|
31
|
-
profile?: AnalyzeRegisterCareOptions['registerCareProfile'];
|
|
32
|
-
}
|
|
33
|
-
export interface AnalyzeRegisterCareForToolsResult {
|
|
34
|
-
diagnostics: Diagnostic[];
|
|
35
|
-
outputCandidates: RegisterCareOutputCandidate[];
|
|
36
|
-
candidateDiagnostics: RegisterCareCandidateDiagnostic[];
|
|
37
|
-
codeActions: RegisterCareCodeAction[];
|
|
38
|
-
reportText?: string;
|
|
39
|
-
interfaceText?: string;
|
|
40
|
-
}
|
|
41
|
-
export declare function codeActionForOutputCandidate(candidate: RegisterCareOutputCandidate): RegisterCareCodeAction;
|
|
42
|
-
export declare function diagnosticForOutputCandidate(candidate: RegisterCareOutputCandidate): RegisterCareCandidateDiagnostic;
|
|
43
|
-
export declare function analyzeRegisterCareForTools(loaded: LoadedProgram, options: AnalyzeRegisterCareForToolsOptions): AnalyzeRegisterCareForToolsResult;
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import type { Z80Instruction } from '../z80/instruction.js';
|
|
2
|
-
export type RegisterCareMode = 'off' | 'audit' | 'warn' | 'error' | 'strict';
|
|
3
|
-
export type RegisterCareUnit = 'A' | 'B' | 'C' | 'D' | 'E' | 'H' | 'L' | 'IXH' | 'IXL' | 'IYH' | 'IYL' | 'SPH' | 'SPL' | 'carry' | 'zero' | 'sign' | 'parity' | 'halfCarry';
|
|
4
|
-
export type SmartComment = {
|
|
5
|
-
kind: 'extern';
|
|
6
|
-
name: string;
|
|
7
|
-
} | {
|
|
8
|
-
kind: 'end';
|
|
9
|
-
} | {
|
|
10
|
-
kind: 'in';
|
|
11
|
-
carriers: RegisterCareUnit[];
|
|
12
|
-
name?: string;
|
|
13
|
-
} | {
|
|
14
|
-
kind: 'out';
|
|
15
|
-
carriers: RegisterCareUnit[];
|
|
16
|
-
name?: string;
|
|
17
|
-
} | {
|
|
18
|
-
kind: 'clobbers';
|
|
19
|
-
carriers: RegisterCareUnit[];
|
|
20
|
-
} | {
|
|
21
|
-
kind: 'preserves';
|
|
22
|
-
carriers: RegisterCareUnit[];
|
|
23
|
-
} | {
|
|
24
|
-
kind: 'expectOut';
|
|
25
|
-
carriers: RegisterCareUnit[];
|
|
26
|
-
name?: string;
|
|
27
|
-
};
|
|
28
|
-
export interface LocatedSmartComment {
|
|
29
|
-
file: string;
|
|
30
|
-
line: number;
|
|
31
|
-
comment: SmartComment;
|
|
32
|
-
}
|
|
33
|
-
export interface RoutineContract {
|
|
34
|
-
name: string;
|
|
35
|
-
in: RegisterCareUnit[];
|
|
36
|
-
out: RegisterCareUnit[];
|
|
37
|
-
clobbers: RegisterCareUnit[];
|
|
38
|
-
preserves: RegisterCareUnit[];
|
|
39
|
-
complete?: boolean;
|
|
40
|
-
}
|
|
41
|
-
export interface RegisterCareInstruction {
|
|
42
|
-
instruction: Z80Instruction;
|
|
43
|
-
file: string;
|
|
44
|
-
line: number;
|
|
45
|
-
column: number;
|
|
46
|
-
labels: string[];
|
|
47
|
-
constants?: ReadonlyMap<string, number>;
|
|
48
|
-
}
|
|
49
|
-
export interface RegisterCareRoutine {
|
|
50
|
-
name: string;
|
|
51
|
-
labels: string[];
|
|
52
|
-
entryLabels: string[];
|
|
53
|
-
instructions: RegisterCareInstruction[];
|
|
54
|
-
constants?: ReadonlyMap<string, number>;
|
|
55
|
-
span: {
|
|
56
|
-
file: string;
|
|
57
|
-
start: {
|
|
58
|
-
line: number;
|
|
59
|
-
column: number;
|
|
60
|
-
};
|
|
61
|
-
end: {
|
|
62
|
-
line: number;
|
|
63
|
-
column: number;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
export interface RegisterCareDirectCall {
|
|
68
|
-
target: string;
|
|
69
|
-
subject: string;
|
|
70
|
-
file: string;
|
|
71
|
-
line: number;
|
|
72
|
-
column: number;
|
|
73
|
-
}
|
|
74
|
-
export interface RegisterCareProgramModel {
|
|
75
|
-
routines: RegisterCareRoutine[];
|
|
76
|
-
directCalls: RegisterCareDirectCall[];
|
|
77
|
-
directBoundaries: RegisterCareDirectCall[];
|
|
78
|
-
}
|
|
79
|
-
export type StackEffect = {
|
|
80
|
-
kind: 'none';
|
|
81
|
-
} | {
|
|
82
|
-
kind: 'push';
|
|
83
|
-
units: RegisterCareUnit[];
|
|
84
|
-
} | {
|
|
85
|
-
kind: 'pop';
|
|
86
|
-
units: RegisterCareUnit[];
|
|
87
|
-
} | {
|
|
88
|
-
kind: 'exchangeTop';
|
|
89
|
-
units: RegisterCareUnit[];
|
|
90
|
-
} | {
|
|
91
|
-
kind: 'unknown';
|
|
92
|
-
};
|
|
93
|
-
export type ControlEffect = {
|
|
94
|
-
kind: 'fallthrough';
|
|
95
|
-
} | {
|
|
96
|
-
kind: 'call';
|
|
97
|
-
target?: string;
|
|
98
|
-
conditional: boolean;
|
|
99
|
-
} | {
|
|
100
|
-
kind: 'rst';
|
|
101
|
-
vector?: number;
|
|
102
|
-
} | {
|
|
103
|
-
kind: 'return';
|
|
104
|
-
conditional: boolean;
|
|
105
|
-
} | {
|
|
106
|
-
kind: 'jump';
|
|
107
|
-
target?: string;
|
|
108
|
-
conditional: boolean;
|
|
109
|
-
} | {
|
|
110
|
-
kind: 'unknown';
|
|
111
|
-
};
|
|
112
|
-
export interface InstructionEffect {
|
|
113
|
-
reads: RegisterCareUnit[];
|
|
114
|
-
writes: RegisterCareUnit[];
|
|
115
|
-
stack: StackEffect;
|
|
116
|
-
control: ControlEffect;
|
|
117
|
-
}
|
|
118
|
-
export interface ValueRelation {
|
|
119
|
-
out: RegisterCareUnit[];
|
|
120
|
-
from: RegisterCareUnit[];
|
|
121
|
-
}
|
|
122
|
-
export interface RoutineSummary {
|
|
123
|
-
name: string;
|
|
124
|
-
mayRead: RegisterCareUnit[];
|
|
125
|
-
mayWrite: RegisterCareUnit[];
|
|
126
|
-
mayOutput?: RegisterCareUnit[];
|
|
127
|
-
preserved: RegisterCareUnit[];
|
|
128
|
-
valueRelations: ValueRelation[];
|
|
129
|
-
stackBalanced: boolean;
|
|
130
|
-
hasUnknownStackEffect?: boolean;
|
|
131
|
-
outputCandidates?: RegisterCareUnit[];
|
|
132
|
-
}
|
|
133
|
-
export interface RegisterCareOutputCandidate {
|
|
134
|
-
file: string;
|
|
135
|
-
line: number;
|
|
136
|
-
column: number;
|
|
137
|
-
routine: string;
|
|
138
|
-
carriers: RegisterCareUnit[];
|
|
139
|
-
autoFixable?: boolean;
|
|
140
|
-
message: string;
|
|
141
|
-
}
|
|
142
|
-
export interface RegisterCareConflict {
|
|
143
|
-
file: string;
|
|
144
|
-
line: number;
|
|
145
|
-
column: number;
|
|
146
|
-
callTarget: string;
|
|
147
|
-
carriers: RegisterCareUnit[];
|
|
148
|
-
message: string;
|
|
149
|
-
}
|
|
150
|
-
export interface RegisterCareReportModel {
|
|
151
|
-
entryFile: string;
|
|
152
|
-
mode: RegisterCareMode;
|
|
153
|
-
profile?: string;
|
|
154
|
-
summaries: RoutineSummary[];
|
|
155
|
-
conflicts: RegisterCareConflict[];
|
|
156
|
-
outputCandidates?: RegisterCareOutputCandidate[];
|
|
157
|
-
unknownCalls: string[];
|
|
158
|
-
}
|
|
159
|
-
export interface AnalyzeRegisterCareOptions {
|
|
160
|
-
mode: RegisterCareMode;
|
|
161
|
-
emitReport: boolean;
|
|
162
|
-
emitInterface: boolean;
|
|
163
|
-
emitAnnotations?: boolean;
|
|
164
|
-
fixRegisterContracts?: boolean;
|
|
165
|
-
registerCareProfile?: 'mon3';
|
|
166
|
-
interfaceContracts?: RoutineContract[];
|
|
167
|
-
acceptedOutputCandidates?: ReadonlyMap<string, RegisterCareUnit[]>;
|
|
168
|
-
}
|
|
169
|
-
export interface RegisterCareAnnotationFile {
|
|
170
|
-
readonly path: string;
|
|
171
|
-
readonly text: string;
|
|
172
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|