Skip to content

Commit f951a99

Browse files
committed
Assembler: implement GAS modifiers
%lo,%hi,%pcrel_lo_%pcrel_hi
1 parent 03f22d8 commit f951a99

File tree

12 files changed

+216
-110
lines changed

12 files changed

+216
-110
lines changed

src/assembler/fixmatheval.cpp

Lines changed: 117 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
#include "fixmatheval.h"
22

3+
#include "common/math/bit_ops.h"
4+
#include "memory/address.h"
5+
36
#include <climits>
47
#include <utility>
58

69
using namespace fixmatheval;
710

11+
// Consumes part of string that is a valid symbol name, returns it and removes it from the input
12+
// string.
13+
QStringView tokenize_symbol(QStringView &expression) {
14+
QStringView symbol = expression;
15+
int i = 0;
16+
for (QChar ch : expression) {
17+
if (!(ch.isLetterOrNumber() || (ch == '_'))) { break; }
18+
i++;
19+
}
20+
expression = expression.mid(i);
21+
return symbol;
22+
}
23+
824
FmeSymbolDb::~FmeSymbolDb() = default;
925

1026
bool FmeSymbolDb::getValue(FmeValue &value, QString name) {
@@ -48,9 +64,14 @@ FmeNodeConstant::FmeNodeConstant(FmeValue value) : FmeNode(INT_MAX) {
4864

4965
FmeNodeConstant::~FmeNodeConstant() = default;
5066

51-
bool FmeNodeConstant::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
52-
(void)symdb;
53-
(void)error;
67+
bool FmeNodeConstant::eval(
68+
FmeValue &value,
69+
FmeSymbolDb *symdb,
70+
QString &error,
71+
machine::Address inst_addr) {
72+
std::ignore = symdb;
73+
std::ignore = error;
74+
std::ignore = inst_addr;
5475
value = this->value;
5576
return true;
5677
}
@@ -65,15 +86,19 @@ FmeNodeSymbol::FmeNodeSymbol(QString &name) : FmeNode(INT_MAX) {
6586

6687
FmeNodeSymbol::~FmeNodeSymbol() = default;
6788

68-
bool FmeNodeSymbol::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
89+
bool FmeNodeSymbol::eval(
90+
FmeValue &value,
91+
FmeSymbolDb *symdb,
92+
QString &error,
93+
machine::Address inst_addr) {
94+
std::ignore = inst_addr;
95+
6996
if (!symdb) {
7097
error = QString("no symbol table to find value for %1").arg(name);
7198
return false;
7299
}
73100
bool ok = symdb->getValue(value, name);
74-
if (!ok) {
75-
error = QString("value for symbol \"%1\" not found").arg(name);
76-
}
101+
if (!ok) { error = QString("value for symbol \"%1\" not found").arg(name); }
77102
return ok;
78103
}
79104

@@ -83,7 +108,7 @@ QString FmeNodeSymbol::dump() {
83108

84109
FmeNodeUnaryOp::FmeNodeUnaryOp(
85110
int priority,
86-
FmeValue (*op)(FmeValue &a),
111+
FmeValue (*op)(FmeValue &a, machine::Address inst_addr),
87112
QString description)
88113
: FmeNode(priority) {
89114
this->operand_a = nullptr;
@@ -98,15 +123,12 @@ FmeNodeUnaryOp::~FmeNodeUnaryOp() {
98123
bool FmeNodeUnaryOp::FmeNodeUnaryOp::eval(
99124
FmeValue &value,
100125
FmeSymbolDb *symdb,
101-
QString &error) {
126+
QString &error,
127+
machine::Address inst_addr) {
102128
FmeValue value_a;
103-
if (!operand_a) {
104-
return false;
105-
}
106-
if (!operand_a->eval(value_a, symdb, error)) {
107-
return false;
108-
}
109-
value = op(value_a);
129+
if (!operand_a) { return false; }
130+
if (!operand_a->eval(value_a, symdb, error, inst_addr)) { return false; }
131+
value = op(value_a, inst_addr);
110132
return true;
111133
}
112134

@@ -120,8 +142,7 @@ bool FmeNodeUnaryOp::insert(FmeNode *node) {
120142
}
121143

122144
QString FmeNodeUnaryOp::dump() {
123-
return "(" + description + " " + (operand_a ? operand_a->dump() : "nullptr")
124-
+ ")";
145+
return "(" + description + " " + (operand_a ? operand_a->dump() : "nullptr") + ")";
125146
}
126147

127148
FmeNodeBinaryOp::FmeNodeBinaryOp(
@@ -141,14 +162,16 @@ FmeNodeBinaryOp::~FmeNodeBinaryOp() {
141162
delete operand_b;
142163
}
143164

144-
bool FmeNodeBinaryOp::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
165+
bool FmeNodeBinaryOp::eval(
166+
FmeValue &value,
167+
FmeSymbolDb *symdb,
168+
QString &error,
169+
machine::Address inst_addr) {
145170
FmeValue value_a;
146171
FmeValue value_b;
147-
if (!operand_a || !operand_b) {
148-
return false;
149-
}
150-
if (!operand_a->eval(value_a, symdb, error)
151-
|| !operand_b->eval(value_b, symdb, error)) {
172+
if (!operand_a || !operand_b) { return false; }
173+
if (!operand_a->eval(value_a, symdb, error, inst_addr)
174+
|| !operand_b->eval(value_b, symdb, error, inst_addr)) {
152175
return false;
153176
}
154177
value = op(value_a, value_b);
@@ -165,8 +188,8 @@ bool FmeNodeBinaryOp::insert(FmeNode *node) {
165188
}
166189

167190
QString FmeNodeBinaryOp::dump() {
168-
return "(" + (operand_a ? operand_a->dump() : "nullptr") + " " + description
169-
+ " " + (operand_b ? operand_b->dump() : "nullptr") + ")";
191+
return "(" + (operand_a ? operand_a->dump() : "nullptr") + " " + description + " "
192+
+ (operand_b ? operand_b->dump() : "nullptr") + ")";
170193
}
171194

172195
FmeExpression::FmeExpression() : FmeNode(0) {
@@ -185,11 +208,9 @@ bool FmeExpression::parse(const QString &expression, QString &error) {
185208
QString optxtx;
186209
for (i = 0; true; i++) {
187210
QChar ch {};
188-
if (i < expression.size()) {
189-
ch = expression.at(i);
190-
}
191-
if (!(ch.isLetterOrNumber() || (ch == '_'))
192-
|| (i >= expression.size())) {
211+
if (i < expression.size()) { ch = expression.at(i); }
212+
if (!(ch.isLetterOrNumber() || (ch == '_')) || (i >= expression.size())) {
213+
if (ch.isSpace()) { continue; }
193214
if (in_word) {
194215
FmeNode *new_node = nullptr;
195216
QString word = expression.mid(word_start, i - word_start);
@@ -212,63 +233,80 @@ bool FmeExpression::parse(const QString &expression, QString &error) {
212233

213234
in_word = false;
214235
is_unary = false;
215-
if (i >= expression.size()) {
216-
break;
217-
}
218236
}
219-
if (ch.isSpace()) {
220-
continue;
221-
}
222-
FmeValue (*binary_op)(FmeValue & a, FmeValue & b) = nullptr;
223-
FmeValue (*unary_op)(FmeValue & a) = nullptr;
237+
if (i >= expression.size()) { break; }
238+
FmeValue (*binary_op)(FmeValue &a, FmeValue &b) = nullptr;
239+
FmeValue (*unary_op)(FmeValue &a, machine::Address inst_addr) = nullptr;
224240
int prio = base_prio;
225241

226242
optxtx = ch;
227-
if (ch == '~') {
243+
if (ch == '%') {
244+
// `%` MODIFIER `(` SYMBOL `)`
245+
// MODIFIER := `hi` | `lo` | `pcrel_hi` | `pcrel_lo`
246+
247+
prio += 90;
248+
// The opening parenthesis is peeked and asserted but not consumed.
249+
QStringView expr = QStringView(expression).mid(i + 1);
250+
if (expr.startsWith(QStringLiteral("hi("))) {
251+
i += 2;
252+
optxtx = QStringLiteral("%hi");
253+
unary_op = [](FmeValue &a, machine::Address) -> FmeValue {
254+
return get_bits(a, 31, 12);
255+
};
256+
} else if (expr.startsWith(QStringLiteral("lo("))) {
257+
i += 2;
258+
optxtx = QStringLiteral("%lo");
259+
unary_op = [](FmeValue &a, machine::Address) -> FmeValue {
260+
return sign_extend(get_bits(a, 11, 0), 12);
261+
};
262+
} else if (expr.startsWith(QStringLiteral("pcrel_hi("))) {
263+
i += 8;
264+
optxtx = QStringLiteral("%pcrel_hi");
265+
unary_op = [](FmeValue &a, machine::Address inst_addr) -> FmeValue {
266+
return get_bits(a - inst_addr.get_raw(), 31, 12)
267+
+ get_bit(a - inst_addr.get_raw(), 11);
268+
};
269+
} else if (expr.startsWith(QStringLiteral("pcrel_lo("))) {
270+
i += 8;
271+
optxtx = QStringLiteral("%pcrel_lo");
272+
unary_op = [](FmeValue &a, machine::Address inst_addr) -> FmeValue {
273+
return sign_extend(get_bits(a - inst_addr.get_raw() + 4, 11, 0), 12);
274+
};
275+
} else {
276+
auto modifier = tokenize_symbol(expr);
277+
error = QString("Unknown modifier \"%1\"").arg(modifier);
278+
ok = false;
279+
break;
280+
}
281+
} else if (ch == '~') {
228282
prio += 90;
229-
unary_op = [](FmeValue &a) -> FmeValue { return ~a; };
283+
unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return ~a; };
230284
} else if (ch == '-') {
231285
if (is_unary) {
232286
prio += 90;
233-
unary_op = [](FmeValue &a) -> FmeValue { return -a; };
287+
unary_op = [](FmeValue &a, machine::Address) -> FmeValue { return -a; };
234288
} else {
235-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
236-
return a - b;
237-
};
289+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a - b; };
238290
prio += 20;
239291
}
240292
} else if (ch == '+') {
241-
if (is_unary) {
242-
continue;
243-
}
244-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
245-
return a + b;
246-
};
293+
if (is_unary) { continue; }
294+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a + b; };
247295
prio += 20;
248296
} else if (ch == '*') {
249-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
250-
return a * b;
251-
};
297+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a * b; };
252298
prio += 30;
253299
} else if (ch == '/') {
254-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
255-
return a / b;
256-
};
300+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a / b; };
257301
prio += 30;
258302
} else if (ch == '|') {
259-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
260-
return a | b;
261-
};
303+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a | b; };
262304
prio += 10;
263305
} else if (ch == '&') {
264-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
265-
return a & b;
266-
};
306+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a & b; };
267307
prio += 15;
268308
} else if (ch == '^') {
269-
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue {
270-
return a ^ b;
271-
};
309+
binary_op = [](FmeValue &a, FmeValue &b) -> FmeValue { return a ^ b; };
272310
prio += 15;
273311
} else if (ch == '(') {
274312
base_prio += 100;
@@ -280,37 +318,29 @@ bool FmeExpression::parse(const QString &expression, QString &error) {
280318
break;
281319
}
282320
} else {
283-
error
284-
= QString("Unknow character \"%1\" in expression.").arg(ch);
321+
error = QString("Unknow character \"%1\" in expression.").arg(ch);
285322
ok = false;
286323
break;
287324
}
288325
if ((binary_op != nullptr) || (unary_op != nullptr)) {
289326
FmeNode *node;
290327
FmeNode *child;
291-
for (node = this; (child = node->child()) != nullptr;
292-
node = child) {
293-
if (child->priority() >= prio) {
294-
break;
295-
}
328+
for (node = this; (child = node->child()) != nullptr; node = child) {
329+
if (child->priority() >= prio) { break; }
296330
}
297331
if (binary_op != nullptr) {
298-
ok = node->insert(
299-
new FmeNodeBinaryOp(prio, binary_op, child, optxtx));
332+
ok = node->insert(new FmeNodeBinaryOp(prio, binary_op, child, optxtx));
300333
is_unary = true;
301334
} else {
302-
ok = node->insert(
303-
new FmeNodeUnaryOp(prio, unary_op, optxtx));
335+
ok = node->insert(new FmeNodeUnaryOp(prio, unary_op, optxtx));
304336
}
305337
if (!ok) {
306338
error = QString("parse stuck at \"%1\"").arg(QString(ch));
307339
break;
308340
}
309341
}
310342
} else {
311-
if (!in_word) {
312-
word_start = i;
313-
}
343+
if (!in_word) { word_start = i; }
314344
in_word = true;
315345
}
316346
}
@@ -323,11 +353,13 @@ FmeExpression::~FmeExpression() {
323353
root = nullptr;
324354
}
325355

326-
bool FmeExpression::eval(FmeValue &value, FmeSymbolDb *symdb, QString &error) {
327-
if (!root) {
328-
return false;
329-
}
330-
return root->eval(value, symdb, error);
356+
bool FmeExpression::eval(
357+
FmeValue &value,
358+
FmeSymbolDb *symdb,
359+
QString &error,
360+
machine::Address inst_addr) {
361+
if (!root) { return false; }
362+
return root->eval(value, symdb, error, inst_addr);
331363
}
332364

333365
bool FmeExpression::insert(FmeNode *node) {

0 commit comments

Comments
 (0)