| /************************************************************************** |
| * |
| * Copyright 2010 Luca Barbieri |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial |
| * portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE |
| * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include <vector> |
| #include <set> |
| #include "sm4.h" |
| |
| #define check(x) do {if(!(x)) return false;} while(0) |
| |
| bool sm4_link_cf_insns(sm4_program& program) |
| { |
| if(program.cf_insn_linked.size()) |
| return true; |
| |
| std::vector<int> cf_insn_linked; |
| cf_insn_linked.resize(program.insns.size()); |
| memset(&cf_insn_linked[0], 0xff, cf_insn_linked.size() * sizeof(int)); |
| std::vector<unsigned> cf_stack; |
| for(unsigned insn_num = 0; insn_num < program.insns.size(); ++insn_num) |
| { |
| unsigned v; |
| switch(program.insns[insn_num]->opcode) |
| { |
| case SM4_OPCODE_LOOP: |
| cf_stack.push_back(insn_num); |
| break; |
| case SM4_OPCODE_ENDLOOP: |
| check(!cf_stack.empty()); |
| v = cf_stack.back(); |
| check(program.insns[v]->opcode == SM4_OPCODE_LOOP); |
| cf_insn_linked[v] = insn_num; |
| cf_insn_linked[insn_num] = v; |
| cf_stack.pop_back(); |
| break; |
| case SM4_OPCODE_IF: |
| case SM4_OPCODE_SWITCH: |
| cf_insn_linked[insn_num] = insn_num; // later changed |
| cf_stack.push_back(insn_num); |
| break; |
| case SM4_OPCODE_ELSE: |
| case SM4_OPCODE_CASE: |
| check(!cf_stack.empty()); |
| v = cf_stack.back(); |
| if(program.insns[insn_num]->opcode == SM4_OPCODE_ELSE) |
| check(program.insns[v]->opcode == SM4_OPCODE_IF); |
| else |
| check(program.insns[v]->opcode == SM4_OPCODE_SWITCH || program.insns[v]->opcode == SM4_OPCODE_CASE); |
| cf_insn_linked[insn_num] = cf_insn_linked[v]; // later changed |
| cf_insn_linked[v] = insn_num; |
| cf_stack.back() = insn_num; |
| break; |
| case SM4_OPCODE_ENDSWITCH: |
| case SM4_OPCODE_ENDIF: |
| check(!cf_stack.empty()); |
| v = cf_stack.back(); |
| if(program.insns[insn_num]->opcode == SM4_OPCODE_ENDIF) |
| check(program.insns[v]->opcode == SM4_OPCODE_IF || program.insns[v]->opcode == SM4_OPCODE_ELSE); |
| else |
| check(program.insns[v]->opcode == SM4_OPCODE_SWITCH || program.insns[v]->opcode == SM4_OPCODE_CASE); |
| cf_insn_linked[insn_num] = cf_insn_linked[v]; |
| cf_insn_linked[v] = insn_num; |
| cf_stack.pop_back(); |
| break; |
| } |
| } |
| check(cf_stack.empty()); |
| program.cf_insn_linked.swap(cf_insn_linked); |
| return true; |
| } |
| |
| bool sm4_find_labels(sm4_program& program) |
| { |
| if(program.labels_found) |
| return true; |
| |
| std::vector<int> labels; |
| for(unsigned insn_num = 0; insn_num < program.insns.size(); ++insn_num) |
| { |
| switch(program.insns[insn_num]->opcode) |
| { |
| case SM4_OPCODE_LABEL: |
| if(program.insns[insn_num]->num_ops > 0) |
| { |
| sm4_op& op = *program.insns[insn_num]->ops[0]; |
| if(op.file == SM4_FILE_LABEL && op.has_simple_index()) |
| { |
| unsigned idx = (unsigned)op.indices[0].disp; |
| if(idx >= labels.size()) |
| labels.resize(idx + 1); |
| labels[idx] = insn_num; |
| } |
| } |
| break; |
| } |
| } |
| program.label_to_insn_num.swap(labels); |
| program.labels_found = true; |
| return true; |
| } |