• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rieske / trans / 27412657980

12 Jun 2026 11:24AM UTC coverage: 89.306% (-0.04%) from 89.343%
27412657980

push

github

rieske
Fix segfault when writing through a register-resident pointer

2 of 2 new or added lines in 1 file covered. (100.0%)

3 existing lines in 1 file now uncovered.

4827 of 5405 relevant lines covered (89.31%)

179503.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.16
/src/codegen/StackMachine.cpp
1
#include "StackMachine.h"
2

3
#include <stdexcept>
4

5
#include "InstructionSet.h"
6

7
namespace {
8
const int MACHINE_WORD_SIZE = 8;
9
const int STACK_ALIGNMENT = 2 * MACHINE_WORD_SIZE;
10
} // namespace
11

12
namespace codegen {
13

14
StackMachine::StackMachine(std::ostream *ostream, std::unique_ptr<InstructionSet> instructionSet, std::unique_ptr<Amd64Registers> registers) :
168✔
15
        assembly{ostream},
168✔
16
        instructionSet{std::move(instructionSet)},
168✔
17
        registers{std::move(registers)} {}
336✔
18

19
void StackMachine::generatePreamble(std::map<std::string, std::string> constants) {
140✔
20
    assembly.raw(instructionSet->preamble(constants));
140✔
21
}
140✔
22

23
void StackMachine::startProcedure(std::string procedureName, std::vector<Value> values, std::vector<Value> arguments) {
190✔
24

25
    emptyGeneralPurposeRegisters();
190✔
26
    assembly.label(instructionSet->label(procedureName));
190✔
27
    assembly << instructionSet->push(registers->getBasePointer());
190✔
28
    assembly << instructionSet->mov(registers->getStackPointer(), registers->getBasePointer());
190✔
29

30
    for (auto& value : values) {
2,460✔
31
        scopeValues.insert({value.getName(), value});
2,270✔
32
    }
33
    std::size_t integerArgumentRegisterIndex{0};
190✔
34
    std::size_t localIndex{scopeValues.size()};
190✔
35
    int argumentIndex{0};
190✔
36
    for (auto& argument : arguments) {
292✔
37
        if (argument.getType() == Type::INTEGRAL && integerArgumentRegisterIndex < registers->getIntegerArgumentRegisters().size()) {
102✔
38
            Value registerArgument{argument.getName(), static_cast<int>(localIndex), argument.getType(), argument.getSizeInBytes()};
62✔
39
            scopeValues.insert({argument.getName(), registerArgument});
62✔
40
            registers->getIntegerArgumentRegisters()[integerArgumentRegisterIndex]->assign(&scopeValues.at(argument.getName()));
62✔
41
            ++integerArgumentRegisterIndex;
62✔
42
            ++localIndex;
62✔
43
        } else {
62✔
44
            Value stackArgument{argument.getName(), argumentIndex, argument.getType(), argument.getSizeInBytes(), true};
40✔
45
            scopeValues.insert({argument.getName(), stackArgument});
40✔
46
            ++argumentIndex;
40✔
47
        }
40✔
48
    }
49
    localVariableStackSize = 0;
190✔
50
    int savedRegistersStack = registers->getCalleeSavedRegisters().size() * MACHINE_WORD_SIZE;
190✔
51
    localVariableStackSize = (scopeValues.size() - argumentIndex) * MACHINE_WORD_SIZE;
190✔
52
    int stackSize = savedRegistersStack + localVariableStackSize;
190✔
53
    if (stackSize % STACK_ALIGNMENT) {
190✔
54
        assembly << instructionSet->sub(registers->getStackPointer(), localVariableStackSize + MACHINE_WORD_SIZE);
114✔
55
    } else {
56
        assembly << instructionSet->sub(registers->getStackPointer(), localVariableStackSize);
76✔
57
    }
58

59
    pushCalleeSavedRegisters();
190✔
60
}
190✔
61

62
void StackMachine::endProcedure() {
184✔
63
    emptyGeneralPurposeRegisters();
184✔
64
    scopeValues.clear();
184✔
65
    calleeSavedRegisters.clear();
184✔
66
}
184✔
67

68
void StackMachine::label(std::string name) {
328✔
69
    spillGeneralPurposeRegisters();
328✔
70
    assembly.label(instructionSet->label(name));
328✔
71
}
328✔
72

73
void StackMachine::jump(JumpCondition jumpCondition, std::string label) {
332✔
74
    switch (jumpCondition) {
332✔
75
    case JumpCondition::IF_EQUAL:
48✔
76
        assembly << instructionSet->je(label);
48✔
77
        break;
48✔
78
    case JumpCondition::IF_NOT_EQUAL:
8✔
79
        assembly << instructionSet->jne(label);
8✔
80
        break;
8✔
81
    case JumpCondition::IF_ABOVE:
36✔
82
        assembly << instructionSet->jg(label);
36✔
83
        break;
36✔
84
    case JumpCondition::IF_BELOW:
30✔
85
        assembly << instructionSet->jl(label);
30✔
86
        break;
30✔
87
    case JumpCondition::IF_ABOVE_OR_EQUAL:
24✔
88
        assembly << instructionSet->jge(label);
24✔
89
        break;
24✔
90
    case JumpCondition::IF_BELOW_OR_EQUAL:
28✔
91
        assembly << instructionSet->jle(label);
28✔
92
        break;
28✔
93
    case JumpCondition::UNCONDITIONAL:
158✔
94
    default:
95
        spillGeneralPurposeRegisters();
158✔
96
        assembly << instructionSet->jmp(label);
158✔
97
    }
98
}
332✔
99

100
void StackMachine::spillGeneralPurposeRegisters() {
486✔
101
    for (auto& reg : registers->getGeneralPurposeRegisters()) {
7,290✔
102
        storeRegisterValue(*reg);
6,804✔
103
    }
486✔
104
}
486✔
105

106
void StackMachine::spillCallerSavedRegisters() {
538✔
107
    for (auto& reg : registers->getCallerSavedRegisters()) {
4,842✔
108
        storeRegisterValue(*reg);
4,304✔
109
    }
538✔
110
}
538✔
111

112
void StackMachine::assignRegisterToSymbol(Register& reg, Value& symbol) {
1,190✔
113
    if (symbol.isStored()) {
1,190✔
114
        storeRegisterValue(reg);
862✔
115
        assembly << instructionSet->mov(memoryBaseRegister(symbol), memoryOffset(symbol), reg);
862✔
116
    } else if (&reg != &symbol.getAssignedRegister()) {
328✔
117
        storeRegisterValue(reg);
324✔
118
        Register& valueRegister = symbol.getAssignedRegister();
324✔
119
        storeRegisterValue(valueRegister);
324✔
120
        assembly << instructionSet->mov(valueRegister, reg);
324✔
121
    }
122
}
1,190✔
123

124
void StackMachine::compare(std::string leftSymbolName, std::string rightSymbolName) {
134✔
125
    auto& leftSymbol = scopeValues.at(leftSymbolName);
134✔
126
    auto& rightSymbol = scopeValues.at(rightSymbolName);
134✔
127

128
    if (leftSymbol.isStored() && rightSymbol.isStored()) {
134✔
129
        Register& rightSymbolRegister = assignRegisterTo(rightSymbol);
82✔
130
        assembly << instructionSet->cmp(memoryBaseRegister(leftSymbol), memoryOffset(leftSymbol), rightSymbolRegister);
82✔
131
    } else if (leftSymbol.isStored()) {
52✔
132
        assembly << instructionSet->cmp(memoryBaseRegister(leftSymbol), memoryOffset(leftSymbol), rightSymbol.getAssignedRegister());
16✔
133
    } else if (rightSymbol.isStored()) {
36✔
134
        assembly << instructionSet->cmp(leftSymbol.getAssignedRegister(), memoryBaseRegister(rightSymbol), memoryOffset(rightSymbol));
20✔
135
    } else {
136
        assembly << instructionSet->cmp(leftSymbol.getAssignedRegister(), rightSymbol.getAssignedRegister());
16✔
137
    }
138
}
134✔
139

140
void StackMachine::zeroCompare(std::string symbolName) {
40✔
141
    auto& symbol = scopeValues.at(symbolName);
40✔
142
    if (symbol.isStored()) {
40✔
143
        assembly << instructionSet->cmp(memoryBaseRegister(symbol), memoryOffset(symbol), 0);
40✔
144
    } else {
145
        assembly << instructionSet->cmp(symbol.getAssignedRegister(), 0);
×
146
    }
147
}
40✔
148

149
void StackMachine::addressOf(std::string operandName, std::string resultName) {
210✔
150
    auto& operand = scopeValues.at(operandName);
210✔
151
    storeInMemory(operand);
210✔
152
    Register& resultRegister = get64BitRegister();
210✔
153
    assembly << instructionSet->mov(memoryBaseRegister(operand), resultRegister);
210✔
154
    int offset = memoryOffset(operand);
210✔
155
    if (offset) {
210✔
156
        assembly << instructionSet->add(resultRegister, offset);
210✔
157
    }
158
    resultRegister.assign(&scopeValues.at(resultName));
210✔
159
}
210✔
160

161
void StackMachine::dereference(std::string operandName, std::string lvalueName, std::string resultName) {
22✔
162
    auto& operand = scopeValues.at(operandName);
22✔
163
    if (operand.isStored()) {
22✔
164
        assignRegisterTo(operand);
4✔
165
    }
166
    Register& resultRegister = get64BitRegisterExcluding(operand.getAssignedRegister());
22✔
167
    assembly << instructionSet->mov(operand.getAssignedRegister(), 0, resultRegister);
22✔
168
    resultRegister.assign(&scopeValues.at(resultName));
22✔
169

170
    Register& lvalueRegister = get64BitRegisterExcluding(operand.getAssignedRegister());
22✔
171
    assembly << instructionSet->mov(operand.getAssignedRegister(), lvalueRegister);
22✔
172
    lvalueRegister.assign(&scopeValues.at(lvalueName));
22✔
173
}
22✔
174

175
void StackMachine::unaryMinus(std::string operandName, std::string resultName) {
80✔
176
    auto& operand = scopeValues.at(operandName);
80✔
177
    if (operand.isStored()) {
80✔
178
        Register& resultRegister = get64BitRegister();
78✔
179
        assembly << instructionSet->mov(memoryBaseRegister(operand), memoryOffset(operand), resultRegister);
78✔
180
        assembly << instructionSet->neg(resultRegister);
78✔
181
        resultRegister.assign(&scopeValues.at(resultName));
78✔
182
    } else {
183
        Register& operandRegister = operand.getAssignedRegister();
2✔
184
        Register& resultRegister = get64BitRegisterExcluding(operand.getAssignedRegister());
2✔
185
        assembly << instructionSet->mov(operandRegister, resultRegister);
2✔
186
        assembly << instructionSet->neg(resultRegister);
2✔
187
        resultRegister.assign(&scopeValues.at(resultName));
2✔
188
    }
189
}
80✔
190

191
void StackMachine::assign(std::string operandName, std::string resultName) {
96✔
192
    auto& operand = scopeValues.at(operandName);
96✔
193
    auto& result = scopeValues.at(resultName);
96✔
194

195
    if (operand.isStored() && result.isStored()) {
96✔
196
        Register& resultRegister = assignRegisterTo(result);
66✔
197
        assembly << instructionSet->mov(memoryBaseRegister(operand), memoryOffset(operand), resultRegister);
66✔
198
    } else if (operand.isStored()) {
30✔
199
        assembly << instructionSet->mov(memoryBaseRegister(operand), memoryOffset(operand), result.getAssignedRegister());
×
200
    } else if (result.isStored()) {
30✔
201
        assembly << instructionSet->mov(operand.getAssignedRegister(), memoryBaseRegister(result), memoryOffset(result));
30✔
202
    } else {
203
        assembly << instructionSet->mov(operand.getAssignedRegister(), result.getAssignedRegister());
×
204
    }
205
}
96✔
206

207
void StackMachine::assignConstant(std::string constant, std::string resultName) {
1,294✔
208
    auto& result = scopeValues.at(resultName);
1,294✔
209
    if (result.isStored()) {
1,294✔
210
        assembly << instructionSet->mov(constant, memoryBaseRegister(result), memoryOffset(result)); // mov dword?
1,294✔
211
    } else {
212
        assembly << instructionSet->mov(constant, result.getAssignedRegister()); // mov dword?
×
213
    }
214
}
1,294✔
215

216
void StackMachine::lvalueAssign(std::string operandName, std::string resultName) {
6✔
217
    auto& operand = scopeValues.at(operandName);
6✔
218
    auto& result = scopeValues.at(resultName);
6✔
219

220
    Register& operandRegister = operand.isStored() ? assignRegisterTo(operand) : operand.getAssignedRegister();
6✔
221
    Register& resultRegister = result.isStored() ? assignRegisterExcluding(result, operandRegister) : result.getAssignedRegister();
6✔
222
    assembly << instructionSet->mov(operandRegister, resultRegister, 0);
6✔
223
}
6✔
224

225
void StackMachine::procedureArgument(std::string argumentName) {
1,164✔
226
    auto argument = &scopeValues.at(argumentName);
1,164✔
227
    if (integerArguments.size() < registers->getIntegerArgumentRegisters().size()) {
1,164✔
228
        integerArguments.push_back(argument);
1,124✔
229
    } else {
230
        stackArguments.insert(stackArguments.begin(), argument);
40✔
231
    }
232
}
1,164✔
233

234
void StackMachine::callProcedure(std::string procedureName) {
538✔
235
    for (std::size_t i = 0; i < integerArguments.size(); ++i) {
1,662✔
236
        assignRegisterToSymbol(*registers->getIntegerArgumentRegisters()[i], *integerArguments[i]);
1,124✔
237
    }
238
    storeRegisterValue(registers->getRetrievalRegister());
538✔
239
    spillCallerSavedRegisters();
538✔
240
    int argumentOffset{0};
538✔
241
    for (auto argument : stackArguments) {
578✔
242
        pushProcedureArgument(*argument, argumentOffset);
40✔
243
        argumentOffset += MACHINE_WORD_SIZE;
40✔
244
    }
245
    integerArguments.clear();
538✔
246
    stackArguments.clear();
538✔
247
    //auto& retrievalRegister = registers->getRetrievalRegister();
248
    //assembly << instructionSet->xor_(retrievalRegister, retrievalRegister);
249
    assembly << instructionSet->call(procedureName);
538✔
250
    if (argumentOffset) {
538✔
251
        assembly << instructionSet->add(registers->getStackPointer(), argumentOffset);
2✔
252
    }
253
}
538✔
254

255
void StackMachine::pushProcedureArgument(Value& symbolToPush, int argumentOffset) {
40✔
256
    if (symbolToPush.isStored()) {
40✔
257
        Register& reg = get64BitRegister();
40✔
258
        assembly << instructionSet->mov(memoryBaseRegister(symbolToPush),
80✔
259
                                        symbolToPush.isFunctionArgument() ? memoryOffset(symbolToPush) : memoryOffset(symbolToPush) + argumentOffset, reg);
80✔
260
        assembly << instructionSet->push(reg);
40✔
261
    } else {
262
        assembly << instructionSet->push(symbolToPush.getAssignedRegister());
×
263
    }
264
}
40✔
265

266
void StackMachine::returnFromProcedure(std::string returnSymbolName) {
196✔
267
    if (!returnSymbolName.empty()) {
196✔
268
        Value& returnSymbol = scopeValues.at(returnSymbolName);
172✔
269
        if (returnSymbol.isStored()) {
172✔
270
            assembly << instructionSet->mov(memoryBaseRegister(returnSymbol), memoryOffset(returnSymbol), registers->getRetrievalRegister());
168✔
271
        } else if (&registers->getRetrievalRegister() != &returnSymbol.getAssignedRegister()) {
4✔
272
            assembly << instructionSet->mov(returnSymbol.getAssignedRegister(), registers->getRetrievalRegister());
4✔
273
        }
274
    }
275
    popCalleeSavedRegisters();
196✔
276
    assembly << instructionSet->leave();
196✔
277
    assembly << instructionSet->ret();
196✔
278
}
196✔
279

280
void StackMachine::retrieveProcedureReturnValue(std::string returnSymbolName) {
532✔
281
    Value& returnSymbol = scopeValues.at(returnSymbolName);
532✔
282
    assembly << instructionSet->mov(registers->getRetrievalRegister(), memoryBaseRegister(returnSymbol), memoryOffset(returnSymbol));
532✔
283
}
532✔
284

285
void StackMachine::xorCommand(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
4✔
286
    Value& leftOperand = scopeValues.at(leftOperandName);
4✔
287
    Value& rightOperand = scopeValues.at(rightOperandName);
4✔
288
    Register& resultRegister = get64BitRegister();
4✔
289

290
    if (leftOperand.isStored() && rightOperand.isStored()) {
4✔
291
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
4✔
292
        assembly << instructionSet->xor_(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
4✔
293
    } else if (leftOperand.isStored()) {
×
294
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
×
295
        assembly << instructionSet->xor_(rightOperand.getAssignedRegister(), resultRegister);
×
296
    } else if (rightOperand.isStored()) {
×
297
        assembly << instructionSet->mov(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
×
298
        assembly << instructionSet->xor_(leftOperand.getAssignedRegister(), resultRegister);
×
299
    } else {
300
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
×
301
        assembly << instructionSet->xor_(rightOperand.getAssignedRegister(), resultRegister);
×
302
    }
303
    resultRegister.assign(&scopeValues.at(resultName));
4✔
304
}
4✔
305

306
void StackMachine::orCommand(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
4✔
307
    Value& leftOperand = scopeValues.at(leftOperandName);
4✔
308
    Value& rightOperand = scopeValues.at(rightOperandName);
4✔
309
    Register& resultRegister = get64BitRegister();
4✔
310

311
    if (leftOperand.isStored() && rightOperand.isStored()) {
4✔
312
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
4✔
313
        assembly << instructionSet->or_(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
4✔
314
    } else if (leftOperand.isStored()) {
×
315
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
×
316
        assembly << instructionSet->or_(rightOperand.getAssignedRegister(), resultRegister);
×
317
    } else if (rightOperand.isStored()) {
×
318
        assembly << instructionSet->mov(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
×
319
        assembly << instructionSet->or_(leftOperand.getAssignedRegister(), resultRegister);
×
320
    } else {
321
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
×
322
        assembly << instructionSet->or_(rightOperand.getAssignedRegister(), resultRegister);
×
323
    }
324
    resultRegister.assign(&scopeValues.at(resultName));
4✔
325
}
4✔
326

327
void StackMachine::andCommand(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
4✔
328
    Value& leftOperand = scopeValues.at(leftOperandName);
4✔
329
    Value& rightOperand = scopeValues.at(rightOperandName);
4✔
330
    Register& resultRegister = get64BitRegister();
4✔
331

332
    if (leftOperand.isStored() && rightOperand.isStored()) {
4✔
333
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
4✔
334
        assembly << instructionSet->and_(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
4✔
335
    } else if (leftOperand.isStored()) {
×
336
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
×
337
        assembly << instructionSet->and_(rightOperand.getAssignedRegister(), resultRegister);
×
338
    } else if (rightOperand.isStored()) {
×
339
        assembly << instructionSet->mov(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
×
340
        assembly << instructionSet->and_(leftOperand.getAssignedRegister(), resultRegister);
×
341
    } else {
342
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
×
343
        assembly << instructionSet->and_(rightOperand.getAssignedRegister(), resultRegister);
×
344
    }
345
    resultRegister.assign(&scopeValues.at(resultName));
4✔
346
}
4✔
347

348
void StackMachine::add(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
22✔
349
    Value& leftOperand = scopeValues.at(leftOperandName);
22✔
350
    Value& rightOperand = scopeValues.at(rightOperandName);
22✔
351
    Register& resultRegister = get64BitRegister();
22✔
352

353
    if (leftOperand.isStored() && rightOperand.isStored()) {
22✔
354
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
12✔
355
        assembly << instructionSet->add(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
12✔
356
    } else if (leftOperand.isStored()) {
10✔
357
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
2✔
358
        assembly << instructionSet->add(rightOperand.getAssignedRegister(), resultRegister);
2✔
359
    } else if (rightOperand.isStored()) {
8✔
360
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
4✔
361
        assembly << instructionSet->add(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
4✔
362
    } else {
363
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
4✔
364
        assembly << instructionSet->add(rightOperand.getAssignedRegister(), resultRegister);
4✔
365
    }
366
    resultRegister.assign(&scopeValues.at(resultName));
22✔
367
}
22✔
368

369
void StackMachine::sub(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
24✔
370
    Value& leftOperand = scopeValues.at(leftOperandName);
24✔
371
    Value& rightOperand = scopeValues.at(rightOperandName);
24✔
372
    Register& resultRegister = get64BitRegister();
24✔
373

374
    if (leftOperand.isStored() && rightOperand.isStored()) {
24✔
375
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
18✔
376
        assembly << instructionSet->sub(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
18✔
377
    } else if (leftOperand.isStored()) {
6✔
378
        assembly << instructionSet->mov(memoryBaseRegister(leftOperand), memoryOffset(leftOperand), resultRegister);
2✔
379
        assembly << instructionSet->sub(rightOperand.getAssignedRegister(), resultRegister);
2✔
380
    } else if (rightOperand.isStored()) {
4✔
381
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
2✔
382
        assembly << instructionSet->sub(memoryBaseRegister(rightOperand), memoryOffset(rightOperand), resultRegister);
2✔
383
    } else {
384
        assembly << instructionSet->mov(leftOperand.getAssignedRegister(), resultRegister);
2✔
385
        assembly << instructionSet->sub(rightOperand.getAssignedRegister(), resultRegister);
2✔
386
    }
387
    resultRegister.assign(&scopeValues.at(resultName));
24✔
388
}
24✔
389

390
void StackMachine::mul(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
10✔
391
    Value& leftOperand = scopeValues.at(leftOperandName);
10✔
392
    Value& rightOperand = scopeValues.at(rightOperandName);
10✔
393
    Value& result = scopeValues.at(resultName);
10✔
394

395
    if (result.getType() != Type::INTEGRAL) {
10✔
396
        throw std::runtime_error{"multiplication of non integers is not implemented"};
×
397
    }
398

399
    Register& multiplicationRegister = registers->getMultiplicationRegister();
10✔
400
    assignRegisterToSymbol(multiplicationRegister, leftOperand);
10✔
401
    if (rightOperand.isStored()) {
10✔
402
        assembly << instructionSet->imul(memoryBaseRegister(rightOperand), memoryOffset(rightOperand));
10✔
403
    } else {
404
        assembly << instructionSet->imul(rightOperand.getAssignedRegister());
×
405
    }
406
    multiplicationRegister.assign(&result);
10✔
407
}
10✔
408

409
void StackMachine::div(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
4✔
410
    Value& leftOperand = scopeValues.at(leftOperandName);
4✔
411
    Value& rightOperand = scopeValues.at(rightOperandName);
4✔
412
    Value& result = scopeValues.at(resultName);
4✔
413

414
    if (result.getType() != Type::INTEGRAL) {
4✔
415
        throw std::runtime_error{"division of non integer types is not implemented"};
×
416
    }
417

418
    Register& multiplicationRegister = registers->getMultiplicationRegister();
4✔
419
    assignRegisterToSymbol(multiplicationRegister, leftOperand);
4✔
420
    storeRegisterValue(registers->getRemainderRegister());
4✔
421
    assembly << instructionSet->xor_(registers->getRemainderRegister(), registers->getRemainderRegister());
4✔
422
    if (rightOperand.isStored()) {
4✔
423
        assembly << instructionSet->idiv(memoryBaseRegister(rightOperand), memoryOffset(rightOperand));
4✔
424
    } else {
425
        assembly << instructionSet->idiv(rightOperand.getAssignedRegister());
×
426
    }
427
    multiplicationRegister.assign(&result);
4✔
428
}
4✔
429

430
void StackMachine::mod(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
4✔
431
    Value& leftOperand = scopeValues.at(leftOperandName);
4✔
432
    Value& rightOperand = scopeValues.at(rightOperandName);
4✔
433
    Value& result = scopeValues.at(resultName);
4✔
434

435
    if (result.getType() != Type::INTEGRAL) {
4✔
436
        throw std::runtime_error{"modular division of non integer types is not implemented"};
×
437
    }
438

439
    Register& multiplicationRegister = registers->getMultiplicationRegister();
4✔
440
    assignRegisterToSymbol(multiplicationRegister, leftOperand);
4✔
441
    storeRegisterValue(registers->getRemainderRegister());
4✔
442
    assembly << instructionSet->xor_(registers->getRemainderRegister(), registers->getRemainderRegister());
4✔
443
    if (rightOperand.isStored()) {
4✔
444
        assembly << instructionSet->idiv(memoryBaseRegister(rightOperand), memoryOffset(rightOperand));
4✔
445
    } else {
446
        assembly << instructionSet->idiv(rightOperand.getAssignedRegister());
×
447
    }
448
    registers->getRemainderRegister().assign(&result);
4✔
449
}
4✔
450

451
void StackMachine::inc(std::string operandName) {
16✔
452
    Value& operand = scopeValues.at(operandName);
16✔
453
    if (operand.isStored()) {
16✔
454
        assembly << instructionSet->inc(memoryBaseRegister(operand), memoryOffset(operand));
12✔
455
    } else {
456
        assembly << instructionSet->inc(operand.getAssignedRegister());
4✔
457
    }
458
}
16✔
459

460
void StackMachine::dec(std::string operandName) {
8✔
461
    Value& operand = scopeValues.at(operandName);
8✔
462
    if (operand.isStored()) {
8✔
463
        assembly << instructionSet->dec(memoryBaseRegister(operand), memoryOffset(operand));
4✔
464
    } else {
465
        assembly << instructionSet->dec(operand.getAssignedRegister());
4✔
466
    }
467
}
8✔
468

469
void StackMachine::shl(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
12✔
470
    // shl r|m imm|cl
471
    Register& counterRegister = getCounterRegister();
12✔
472
    Value& rightOperand = scopeValues.at(rightOperandName);
12✔
473
    assignRegisterToSymbol(counterRegister, rightOperand);
12✔
474

475
    Register& resultRegister = get64BitRegister();
12✔
476
    Value& leftOperand = scopeValues.at(leftOperandName);
12✔
477
    assignRegisterToSymbol(resultRegister, leftOperand);
12✔
478
    // shl resultRegister cl ; the shift argument is put in counter register - rcx
479
    assembly << instructionSet->shl(resultRegister);
12✔
480
    Value& result = scopeValues.at(resultName);
12✔
481
    resultRegister.assign(&result);
12✔
482
}
12✔
483

484
void StackMachine::shr(std::string leftOperandName, std::string rightOperandName, std::string resultName) {
12✔
485
    // shr r|m imm|cl
486
    Register& counterRegister = getCounterRegister();
12✔
487
    Value& rightOperand = scopeValues.at(rightOperandName);
12✔
488
    assignRegisterToSymbol(counterRegister, rightOperand);
12✔
489

490
    Register& resultRegister = get64BitRegister();
12✔
491
    Value& leftOperand = scopeValues.at(leftOperandName);
12✔
492
    assignRegisterToSymbol(resultRegister, leftOperand);
12✔
493
    // shr resultRegister cl ; the shift argument is put in counter register - rcx
494
    assembly << instructionSet->shr(resultRegister);
12✔
495
    Value& result = scopeValues.at(resultName);
12✔
496
    resultRegister.assign(&result);
12✔
497
}
12✔
498

499
void StackMachine::storeRegisterValue(Register& reg) {
13,194✔
500
    if (reg.containsUnstoredValue()) {
13,194✔
501
        assembly << instructionSet->mov(reg, memoryBaseRegister(*reg.getValue()), memoryOffset(*reg.getValue()));
630✔
502
        reg.free();
630✔
503
    }
504
}
13,194✔
505

506
void StackMachine::emptyGeneralPurposeRegisters() {
374✔
507
    for (auto& reg : registers->getGeneralPurposeRegisters()) {
5,610✔
508
        reg->free();
5,236✔
509
    }
374✔
510
}
374✔
511

512
void StackMachine::pushCalleeSavedRegisters() { pushRegisters(registers->getCalleeSavedRegisters(), calleeSavedRegisters); }
190✔
513

514
void StackMachine::popCalleeSavedRegisters() { popRegisters(calleeSavedRegisters); }
196✔
515

516
void StackMachine::pushRegisters(std::vector<Register*> source, std::vector<Register*>& destination) {
190✔
517
    for (auto& reg : source) {
1,140✔
518
        pushRegister(*reg, destination);
950✔
519
    }
520
}
190✔
521

522
void StackMachine::popRegisters(std::vector<Register*> registers) {
196✔
523
    for (auto& reg : registers) {
1,166✔
524
        assembly << instructionSet->pop(*reg);
970✔
525
    }
526
}
196✔
527

528
void StackMachine::pushRegister(Register& reg, std::vector<Register*>& registers) {
950✔
529
    registers.insert(registers.begin(), &reg);
950✔
530
    assembly << instructionSet->push(reg);
950✔
531
}
950✔
532

533
void StackMachine::storeInMemory(Value& symbol) {
210✔
534
    if (!symbol.isStored()) {
210✔
535
        storeRegisterValue(symbol.getAssignedRegister());
2✔
536
    }
537
}
210✔
538

539
int StackMachine::memoryOffset(const Value& symbol) const {
4,350✔
540
    if (symbol.isFunctionArgument()) {
4,350✔
541
        return (symbol.getIndex() + 2) * MACHINE_WORD_SIZE;
40✔
542
    }
543
    return symbol.getIndex() * MACHINE_WORD_SIZE + calleeSavedRegisters.size() * MACHINE_WORD_SIZE;
4,310✔
544
}
545

546
const Register& StackMachine::memoryBaseRegister(const Value& symbol) const {
4,350✔
547
    if (symbol.isFunctionArgument()) {
4,350✔
548
        return registers->getBasePointer();
40✔
549
    }
550
    return registers->getStackPointer();
4,310✔
551
}
552

553
Register& StackMachine::get64BitRegister() {
564✔
554
    for (auto& reg : registers->getGeneralPurposeRegisters()) {
730✔
555
        if (!reg->containsUnstoredValue()) {
730✔
556
            return *reg;
564✔
557
        }
558
    }
564✔
UNCOV
559
    Register& reg = **registers->getGeneralPurposeRegisters().begin();
×
UNCOV
560
    storeRegisterValue(reg);
×
UNCOV
561
    return reg;
×
562
}
563

564
Register& StackMachine::get64BitRegisterExcluding(Register& registerToExclude) {
46✔
565
    for (auto& reg : registers->getGeneralPurposeRegisters()) {
302✔
566
        if (!reg->containsUnstoredValue()) {
298✔
567
            return *reg;
42✔
568
        }
569
    }
46✔
570
    for (auto& reg : registers->getGeneralPurposeRegisters()) {
4✔
571
        if (reg != &registerToExclude) {
4✔
572
            storeRegisterValue(*reg);
4✔
573
            return *reg;
4✔
574
        }
575
    }
4✔
576
    throw std::runtime_error{"unable to get a free register"};
×
577
}
578

579
Register& StackMachine::getCounterRegister() {
24✔
580
    Register& counter = registers->getCounterRegister();
24✔
581
    storeRegisterValue(counter);
24✔
582
    return counter;
24✔
583
}
584

585
Register& StackMachine::assignRegisterTo(Value& symbol) {
154✔
586
    Register& reg = get64BitRegister();
154✔
587
    assembly << instructionSet->mov(memoryBaseRegister(symbol), memoryOffset(symbol), reg);
154✔
588
    reg.assign(&symbol);
154✔
589
    return reg;
154✔
590
}
591

592
Register& StackMachine::assignRegisterExcluding(Value& symbol, Register& registerToExclude) {
×
593
    Register& reg = get64BitRegisterExcluding(registerToExclude);
×
594
    assembly << instructionSet->mov(memoryBaseRegister(symbol), memoryOffset(symbol), reg);
×
595
    reg.assign(&symbol);
×
596
    return reg;
×
597
}
598

599
void StackMachine::setScope(std::vector<Value> variables) {
16✔
600
    for (auto& var : variables) {
64✔
601
        scopeValues.insert({var.getName(), var});
48✔
602
    }
603
}
16✔
604

605
} // namespace codegen
606

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc