about summary refs log tree commit diff stats
path: root/subx/036recommend_labels.cc
diff options
context:
space:
mode:
Diffstat (limited to 'subx/036recommend_labels.cc')
-rw-r--r--subx/036recommend_labels.cc81
1 files changed, 81 insertions, 0 deletions
diff --git a/subx/036recommend_labels.cc b/subx/036recommend_labels.cc
new file mode 100644
index 00000000..b40e2a66
--- /dev/null
+++ b/subx/036recommend_labels.cc
@@ -0,0 +1,81 @@
+//: Now that we have labels, using non-label offsets should be unnecessary.
+//: While SubX will allow programmers to write raw machine code, that isn't
+//: *recommended* once we have more ergonomic alternatives.
+
+:(scenario warn_on_jump_offset)
+== 0x1
+7e 1/disp8
++warn: '7e 1/disp8': using raw offsets for jumps is not recommended; use labels instead
+
+:(scenarios transform)
+:(scenario warn_on_call_offset)
+== 0x1
+e8 1/disp32
++warn: 'e8 1/disp32': using raw offsets for calls is not recommended; use labels instead
+:(scenarios run)
+
+:(before "Rewrite Labels(segment code)")
+recommend_labels(code);
+
+:(code)
+void recommend_labels(const segment& code) {
+  trace(99, "transform") << "-- check for numeric labels" << end();
+  for (int i = 0;  i < SIZE(code.lines);  ++i)
+    recommend_labels(code.lines.at(i));
+}
+
+void recommend_labels(const line& inst) {
+  int idx = first_operand(inst);
+  if (idx >= SIZE(inst.words)) return;
+  if (!is_number(inst.words.at(idx).data)) return;
+  if (is_jump(inst))
+    warn << "'" << inst.original << "': using raw offsets for jumps is not recommended; use labels instead\n" << end();
+  else if (is_call(inst))
+    warn << "'" << inst.original << "': using raw offsets for calls is not recommended; use labels instead\n" << end();
+}
+
+bool is_jump(const line& inst) {
+  string op1 = preprocess_op(inst.words.at(0)).data;
+  if (op1 == "0f") {
+    string op2 = preprocess_op(inst.words.at(1)).data;
+    return Jump_opcodes_0f.find(op1) != Jump_opcodes_0f.end();
+  }
+  if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/4;
+  return Jump_opcodes.find(op1) != Jump_opcodes.end();
+}
+
+bool is_call(const line& inst) {
+  string op1 = preprocess_op(inst.words.at(0)).data;
+  if (op1 == "e8") return true;
+  if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/2;
+  return false;  // no multi-byte call opcodes
+}
+
+int subop(const line& inst) {
+  int idx = first_operand(inst);
+  assert(idx < SIZE(inst.words));
+  return (parse_int(inst.words.at(idx).data)>>3) & 0x7;
+}
+
+:(before "End Globals")
+set<string> Jump_opcodes;
+set<string> Jump_opcodes_0f;
+:(before "End One-time Setup")
+init_jump_opcodes();
+:(code)
+void init_jump_opcodes() {
+  Jump_opcodes.insert("74");
+  Jump_opcodes.insert("75");
+  Jump_opcodes.insert("7c");
+  Jump_opcodes.insert("7d");
+  Jump_opcodes.insert("7e");
+  Jump_opcodes.insert("7f");
+  Jump_opcodes_0f.insert("84");
+  Jump_opcodes_0f.insert("85");
+  Jump_opcodes_0f.insert("8c");
+  Jump_opcodes_0f.insert("8d");
+  Jump_opcodes_0f.insert("8e");
+  Jump_opcodes_0f.insert("8f");
+  Jump_opcodes.insert("e9");
+  Jump_opcodes.insert("eb");
+}