diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-08-01 14:50:19 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-08-01 14:50:19 -0700 |
commit | 37c859058d678dc30d4bc2dee985d7a5e2d07db0 (patch) | |
tree | 2dbb1e9e1ec12752cefd6b6b5fa75a23a8935c0b | |
parent | 70decc7aefa641857f813823552fcd1e04d3a551 (diff) | |
download | mu-37c859058d678dc30d4bc2dee985d7a5e2d07db0.tar.gz |
table-based register conversion
Requires a change to the C++ translator: support string literals in all segments, not just the code segment. (The self-hosted translator already had this.)
-rw-r--r-- | 038---literal_strings.cc | 62 | ||||
-rwxr-xr-x | apps/desugar | bin | 33910 -> 33629 bytes | |||
-rw-r--r-- | apps/desugar.subx | 324 |
3 files changed, 218 insertions, 168 deletions
diff --git a/038---literal_strings.cc b/038---literal_strings.cc index 547747a6..48d46108 100644 --- a/038---literal_strings.cc +++ b/038---literal_strings.cc @@ -12,7 +12,7 @@ void test_transform_literal_string() { CHECK_TRACE_CONTENTS( "transform: -- move literal strings to data segment\n" "transform: adding global variable '__subx_global_1' containing \"test\"\n" - "transform: instruction after transform: 'b8 __subx_global_1'\n" + "transform: line after transform: 'b8 __subx_global_1'\n" ); } @@ -32,33 +32,40 @@ Next_auto_global = 1; void transform_literal_strings(program& p) { trace(3, "transform") << "-- move literal strings to data segment" << end(); if (p.segments.empty()) return; - segment& code = *find(p, "code"); - segment& data = *find(p, "data"); - for (int i = 0; i < SIZE(code.lines); ++i) { - line& inst = code.lines.at(i); - for (int j = 0; j < SIZE(inst.words); ++j) { - word& curr = inst.words.at(j); - if (curr.data.at(0) != '"') continue; - ostringstream global_name; - global_name << "__subx_global_" << Next_auto_global; - ++Next_auto_global; - add_global_to_data_segment(global_name.str(), curr, data); - curr.data = global_name.str(); + vector<line> new_lines; + for (int s = 0; s < SIZE(p.segments); ++s) { + segment& seg = p.segments.at(s); + trace(99, "transform") << "segment '" << seg.name << "'" << end(); + for (int i = 0; i < SIZE(seg.lines); ++i) { +//? cerr << seg.name << '/' << i << '\n'; + line& line = seg.lines.at(i); + for (int j = 0; j < SIZE(line.words); ++j) { + word& curr = line.words.at(j); + if (curr.data.at(0) != '"') continue; + ostringstream global_name; + global_name << "__subx_global_" << Next_auto_global; + ++Next_auto_global; + add_global_to_data_segment(global_name.str(), curr, new_lines); + curr.data = global_name.str(); + } + trace(99, "transform") << "line after transform: '" << data_to_string(line) << "'" << end(); } - trace(99, "transform") << "instruction after transform: '" << data_to_string(inst) << "'" << end(); } + segment* data = find(p, "data"); + if (data) + data->lines.insert(data->lines.end(), new_lines.begin(), new_lines.end()); } -void add_global_to_data_segment(const string& name, const word& value, segment& data) { +void add_global_to_data_segment(const string& name, const word& value, vector<line>& out) { trace(99, "transform") << "adding global variable '" << name << "' containing " << value.data << end(); // emit label - data.lines.push_back(label(name)); + out.push_back(label(name)); // emit size for size-prefixed array - data.lines.push_back(line()); - emit_hex_bytes(data.lines.back(), SIZE(value.data)-/*skip quotes*/2, 4/*bytes*/); + out.push_back(line()); + emit_hex_bytes(out.back(), SIZE(value.data)-/*skip quotes*/2, 4/*bytes*/); // emit data byte by byte - data.lines.push_back(line()); - line& curr = data.lines.back(); + out.push_back(line()); + line& curr = out.back(); for (int i = /*skip start quote*/1; i < SIZE(value.data)-/*skip end quote*/1; ++i) { char c = value.data.at(i); curr.words.push_back(word()); @@ -83,6 +90,21 @@ void test_instruction_with_string_literal() { CHECK_TRACE_COUNT("parse2", 3); } +void test_string_literal_in_data_segment() { + run( + "== code 0x1\n" + "b8/copy X/imm32\n" + "== data 0x2000\n" + "X:\n" + "\"test\"/imm32\n" + ); + CHECK_TRACE_CONTENTS( + "transform: -- move literal strings to data segment\n" + "transform: adding global variable '__subx_global_1' containing \"test\"\n" + "transform: line after transform: '__subx_global_1'\n" + ); +} + :(before "End Line Parsing Special-cases(line_data -> l)") if (line_data.find('"') != string::npos) { // can cause false-positives, but we can handle them parse_instruction_character_by_character(line_data, l); diff --git a/apps/desugar b/apps/desugar index 9428424f..d04778dc 100755 --- a/apps/desugar +++ b/apps/desugar Binary files differdiff --git a/apps/desugar.subx b/apps/desugar.subx index 118aae59..25c21d78 100644 --- a/apps/desugar.subx +++ b/apps/desugar.subx @@ -157,21 +157,13 @@ $convert:check-for-register-literal: $convert:register-literal: # ++word-slice->start 4b/increment-EBX - # EAX = desugar-register(word-slice) + # desugar-register(word-slice, out) # . . push args 52/push-EDX # . . call e8/call desugar-register/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # write-buffered(out, EAX) - # . . push args - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # continue eb/jump $convert:next-word/disp8 $convert:regular-word: @@ -227,201 +219,237 @@ $convert:end: 5d/pop-to-EBP c3/return -desugar-register: # word : (address slice) -> register : (address byte array) - # ECX holds return value +desugar-register: # word : (address slice), out : (address buffered-file) # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # . save registers - 51/push-ECX - # if slice-equal?(word, "eax") return reg 0 - # . EAX = slice-equal?(word, "eax") - 68/push "eax"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . return "0" - b9/copy-to-ECX "3/mod/direct 0/rm32/EAX"/imm32 - 3d/compare-EAX-and 1/imm32 - 0f 84/jump-if-equal $desugar-register:end/disp32 - # if slice-equal?(word, "ecx") return reg 1 - # . EAX = slice-equal?(word, "ecx") - 68/push "ecx"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . return "1" - b9/copy-to-ECX "3/mod/direct 1/rm32/ECX"/imm32 - 3d/compare-EAX-and 1/imm32 - 0f 84/jump-if-equal $desugar-register:end/disp32 - # if slice-equal?(word, "edx") return reg 2 - # . EAX = slice-equal?(word, "edx") - 68/push "edx"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . return "2" - b9/copy-to-ECX "3/mod/direct 2/rm32/EDX"/imm32 - 3d/compare-EAX-and 1/imm32 - 0f 84/jump-if-equal $desugar-register:end/disp32 - # if slice-equal?(word, "ebx") return reg 3 - # . EAX = slice-equal?(word, "ebx") - 68/push "ebx"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return reg 3 - b9/copy-to-ECX "3/mod/direct 3/rm32/EBX"/imm32 - 3d/compare-EAX-and 1/imm32 - 74/jump-if-equal $desugar-register:end/disp8 - # if slice-equal?(word, "esp") return reg 4 - # . EAX = slice-equal?(word, "esp") - 68/push "esp"/imm32 + 50/push-EAX + # reg-num/EAX = get-slice(Registers, word, row-size=8) + # . . push args + 68/push 8/imm32/row-size ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 68/push Registers/imm32 # . . call - e8/call slice-equal?/disp32 + e8/call get-slice/disp32 # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return reg 4 - b9/copy-to-ECX "3/mod/direct 4/rm32/ESP"/imm32 - 3d/compare-EAX-and 1/imm32 - 74/jump-if-equal $desugar-register:end/disp8 - # if slice-equal?(word, "ebp") return reg 5 - # . EAX = slice-equal?(word, "ebp") - 68/push "ebp"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # write-buffered(out, "3/mod/direct ") + # . . push args + 68/push "3/mod/direct "/imm32 + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) # . . call - e8/call slice-equal?/disp32 + e8/call write-buffered/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return reg 5 - b9/copy-to-ECX "3/mod/direct 5/rm32/EBP"/imm32 - 3d/compare-EAX-and 1/imm32 - 74/jump-if-equal $desugar-register:end/disp8 - # if slice-equal?(word, "esi") return reg 6 - # . EAX = slice-equal?(word, "esi") - 68/push "esi"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # print-int32-buffered(out, *EAX) + # . . push args + ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) # . . call - e8/call slice-equal?/disp32 + e8/call print-int32-buffered/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return reg 6 - b9/copy-to-ECX "3/mod/direct 6/rm32/ESI"/imm32 - 3d/compare-EAX-and 1/imm32 - 74/jump-if-equal $desugar-register:end/disp8 - # if slice-equal?(word, "edi") return reg 7 - # . EAX = slice-equal?(word, "edi") - 68/push "edi"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # write-buffered(out, "/rm32") + # . . push args + 68/push "/rm32"/imm32 + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) # . . call - e8/call slice-equal?/disp32 + e8/call write-buffered/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return reg 7 - b9/copy-to-ECX "3/mod/direct 7/rm32/EDI"/imm32 - 3d/compare-EAX-and 1/imm32 - 74/jump-if-equal $desugar-register:end/disp8 - # fail - eb/jump $desugar-register:abort/disp8 $desugar-register:end: - # return ECX - 89/copy 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to EAX # . restore registers - 59/pop-to-ECX + 58/pop-to-EAX # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return -$desugar-register:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "unknown symbol to desugar\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 52/push-EDX - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 test-desugar-register: # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -$test-desugar-register-1: + # setup + # . clear-stream(_test-output-stream) + # . . push args + 68/push _test-output-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(_test-output-buffered-file+4) + # . . push args + b8/copy-to-EAX _test-output-buffered-file/imm32 + 05/add-to-EAX 4/imm32 + 50/push-EAX + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # var slice/ECX = "eax" b8/copy-to-EAX "eax"/imm32 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} + # . ECX = {EAX, ECX} 51/push-ECX 50/push-EAX 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # result/EAX = desugar-register(str/ECX) + # desugar-register(str, _test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 51/push-ECX + # . . call e8/call desugar-register/disp32 - # . discard args + # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # string-equal?(expected, result/EAX) - 50/push-EAX - 68/push "3/mod/direct 0/rm32/EAX"/imm32 - e8/call string-equal?/disp32 - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) + # . flush(_test-output-buffered-file) # . . push args - 68/push "F - test-desugar-register 1"/imm32 - 68/push 1/imm32/true - 50/push-EAX + 68/push _test-output-buffered-file/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +#? # dump output {{{ +#? # . write(2/stderr, "^") +#? # . . push args +#? 68/push "^"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . write-stream(2/stderr, _test-output-stream) +#? # . . push args +#? 68/push _test-output-stream/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write-stream/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . write(2/stderr, "$\n") +#? # . . push args +#? 68/push "$\n"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # }}} + # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg) + # . . push args + 68/push "F - test-desugar-register/0"/imm32 + 68/push "3/mod/direct 0x00000000/rm32"/imm32 + 68/push _test-output-stream/imm32 # . . call - e8/call check-ints-equal/disp32 + e8/call check-stream-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-desugar-register-2: + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-desugar-register-2: + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # setup + # . clear-stream(_test-output-stream) + # . . push args + 68/push _test-output-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # . clear-stream(_test-output-buffered-file+4) + # . . push args + b8/copy-to-EAX _test-output-buffered-file/imm32 + 05/add-to-EAX 4/imm32 + 50/push-EAX + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # var slice/ECX = "edi" b8/copy-to-EAX "edi"/imm32 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 4/disp8 . # copy EAX+ECX+4 to ECX 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} + # . ECX = {EAX, ECX} 51/push-ECX 50/push-EAX 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # result/EAX = desugar-register(str/ECX) + # desugar-register(str/ECX, _test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 51/push-ECX + # . . call e8/call desugar-register/disp32 - # . discard args + # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # string-equal?(expected, result/EAX) - 50/push-EAX - 68/push "3/mod/direct 7/rm32/EDI"/imm32 - e8/call string-equal?/disp32 - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) + # . flush(_test-output-buffered-file) # . . push args - 68/push "F - test-desugar-register 1"/imm32 - 68/push 1/imm32/true - 50/push-EAX + 68/push _test-output-buffered-file/imm32 # . . call - e8/call check-ints-equal/disp32 + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +#? # dump output {{{ +#? # . write(2/stderr, "^") +#? # . . push args +#? 68/push "^"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . write-stream(2/stderr, _test-output-stream) +#? # . . push args +#? 68/push _test-output-stream/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write-stream/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # . write(2/stderr, "$\n") +#? # . . push args +#? 68/push "$\n"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +#? # }}} + # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg) + # . . push args + 68/push "F - test-desugar-register/1"/imm32 + 68/push "3/mod/direct 0x00000007/rm32"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-stream-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return + +== data +Registers: # (table string int) + # a table is a stream + 0x40/imm32/write + 0/imm32/read + 0x40/imm32/length + # data + "eax"/imm32 0/imm32 + "ecx"/imm32 1/imm32 + "edx"/imm32 2/imm32 + "ebx"/imm32 3/imm32 + "esp"/imm32 4/imm32 + "ebp"/imm32 5/imm32 + "esi"/imm32 6/imm32 + "edi"/imm32 7/imm32 + +# . . vim:nowrap:textwidth=0 |