1 //: Now that we have labels, using non-label offsets should be unnecessary.
 2 //: While SubX will allow programmers to write raw machine code, that isn't
 3 //: *recommended* once we have more ergonomic alternatives.
 4 
 5 :(scenario warn_on_jump_offset)
 6 == 0x1
 7 7e/jump-if 1/disp8
 8 +warn: '7e/jump-if 1/disp8': using raw offsets for jumps is not recommended; use labels instead
 9 
10 :(scenarios transform)
11 :(scenario warn_on_call_offset)
12 == 0x1
13 e8/call 1/disp32
14 +warn: 'e8/call 1/disp32': using raw offsets for calls is not recommended; use labels instead
15 :(scenarios run)
16 
17 :(before "Rewrite Labels(segment code)")
18 recommend_labels(code);
19 if (trace_contains_errors()) return;
20 :(code)
21 void recommend_labels(const segment& code) {
22   trace(99, "transform") << "-- check for numeric labels" << end();
23   for (int i = 0;  i < SIZE(code.lines);  ++i)
24     recommend_labels(code.lines.at(i));
25 }
26 
27 void recommend_labels(const line& inst) {
28   int idx = first_operand(inst);
29   if (idx >= SIZE(inst.words)) return;
30   if (!is_number(inst.words.at(idx).data)) return;
31   if (is_jump(inst))
32     warn << "'" << inst.original << "': using raw offsets for jumps is not recommended; use labels instead\n" << end();
33   else if (is_call(inst))
34     warn << "'" << inst.original << "': using raw offsets for calls is not recommended; use labels instead\n" << end();
35 }
36 
37 bool is_jump(const line& inst) {
38   string op1 = preprocess_op(inst.words.at(0)).data;
39   if (op1 == "0f") {
40     string op2 = preprocess_op(inst.words.at(1)).data;
41     return Jump_opcodes_0f.find(op1) != Jump_opcodes_0f.end();
42   }
43   if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/4;
44   return Jump_opcodes.find(op1) != Jump_opcodes.end();
45 }
46 
47 bool is_call(const line& inst) {
48   string op1 = preprocess_op(inst.words.at(0)).data;
49   if (op1 == "e8") return true;
50   if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/2;
51   return false;  // no multi-byte call opcodes
52 }
53 
54 int subop(const line& inst) {
55   int idx = first_operand(inst);
56   assert(idx < SIZE(inst.words));
57   return (parse_int(inst.words.at(idx).data)>>3) & 0x7;
58 }
59 
60 :(before "End Globals")
61 set<string> Jump_opcodes;
62 set<string> Jump_opcodes_0f;
63 :(before "End One-time Setup")
64 init_jump_opcodes();
65 :(code)
66 void init_jump_opcodes() {
67   Jump_opcodes.insert("74");
68   Jump_opcodes.insert("75");
69   Jump_opcodes.insert("7c");
70   Jump_opcodes.insert("7d");
71   Jump_opcodes.insert("7e");
72   Jump_opcodes.insert("7f");
73   Jump_opcodes_0f.insert("84");
74   Jump_opcodes_0f.insert("85");
75   Jump_opcodes_0f.insert("8c");
76   Jump_opcodes_0f.insert("8d");
77   Jump_opcodes_0f.insert("8e");
78   Jump_opcodes_0f.insert("8f");
79   Jump_opcodes.insert("e9");
80   Jump_opcodes.insert("eb");
81 }