diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2016-12-18 07:06:32 +0100 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-02-06 00:01:09 +0100 |
| commit | 047a43fa754c0f82666d5858168bd63fe87d90a7 (patch) | |
| tree | 5042db32a3a94e14ca60357a755a4ba2f36cdaa1 | |
| parent | 9fb6070311ea3ebc0ad1e8d60935a604f45e4e9c (diff) | |
| download | sparse-dev-047a43fa754c0f82666d5858168bd63fe87d90a7.tar.gz | |
extract extract eval_insn() from simplify_constant_binop()
For some optimizations, it's desirable to be able to
directly evaluate constant operations and not to have
to wait a whole simplification cycle or to have to
allocate an new instruction.
So, extract the part dealing exclusively with the
evaluation into a separate function.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
| -rw-r--r-- | simplify.c | 241 |
1 files changed, 128 insertions, 113 deletions
@@ -392,6 +392,131 @@ static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo) return size; } +static pseudo_t eval_insn(struct instruction *insn) +{ + /* FIXME! Verify signs and sizes!! */ + unsigned int size = insn->size; + long long left = insn->src1->value; + long long right = insn->src2->value; + unsigned long long ul, ur; + long long res, mask, bits; + + mask = 1ULL << (size-1); + bits = mask | (mask-1); + + if (left & mask) + left |= ~bits; + if (right & mask) + right |= ~bits; + ul = left & bits; + ur = right & bits; + + switch (insn->opcode) { + case OP_ADD: + res = left + right; + break; + case OP_SUB: + res = left - right; + break; + case OP_MULU: + res = ul * ur; + break; + case OP_MULS: + res = left * right; + break; + case OP_DIVU: + if (!ur) + goto undef; + res = ul / ur; + break; + case OP_DIVS: + if (!right) + goto undef; + if (left == mask && right == -1) + goto undef; + res = left / right; + break; + case OP_MODU: + if (!ur) + goto undef; + res = ul % ur; + break; + case OP_MODS: + if (!right) + goto undef; + if (left == mask && right == -1) + goto undef; + res = left % right; + break; + case OP_SHL: + res = left << right; + break; + case OP_LSR: + res = ul >> ur; + break; + case OP_ASR: + res = left >> right; + break; + /* Logical */ + case OP_AND: + res = left & right; + break; + case OP_OR: + res = left | right; + break; + case OP_XOR: + res = left ^ right; + break; + case OP_AND_BOOL: + res = left && right; + break; + case OP_OR_BOOL: + res = left || right; + break; + + /* Binary comparison */ + case OP_SET_EQ: + res = left == right; + break; + case OP_SET_NE: + res = left != right; + break; + case OP_SET_LE: + res = left <= right; + break; + case OP_SET_GE: + res = left >= right; + break; + case OP_SET_LT: + res = left < right; + break; + case OP_SET_GT: + res = left > right; + break; + case OP_SET_B: + res = ul < ur; + break; + case OP_SET_A: + res = ul > ur; + break; + case OP_SET_BE: + res = ul <= ur; + break; + case OP_SET_AE: + res = ul >= ur; + break; + default: + return NULL; + } + res &= bits; + + return value_pseudo(res); + +undef: + return NULL; +} + + static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value) { unsigned int size = operand_size(insn, pseudo); @@ -547,122 +672,12 @@ static int simplify_constant_leftside(struct instruction *insn) static int simplify_constant_binop(struct instruction *insn) { - /* FIXME! Verify signs and sizes!! */ - long long left = insn->src1->value; - long long right = insn->src2->value; - unsigned long long ul, ur; - long long res, mask, bits; - - mask = 1ULL << (insn->size-1); - bits = mask | (mask-1); - - if (left & mask) - left |= ~bits; - if (right & mask) - right |= ~bits; - ul = left & bits; - ur = right & bits; + pseudo_t res = eval_insn(insn); - switch (insn->opcode) { - case OP_ADD: - res = left + right; - break; - case OP_SUB: - res = left - right; - break; - case OP_MULU: - res = ul * ur; - break; - case OP_MULS: - res = left * right; - break; - case OP_DIVU: - if (!ur) - return 0; - res = ul / ur; - break; - case OP_DIVS: - if (!right) - return 0; - if (left == mask && right == -1) - return 0; - res = left / right; - break; - case OP_MODU: - if (!ur) - return 0; - res = ul % ur; - break; - case OP_MODS: - if (!right) - return 0; - if (left == mask && right == -1) - return 0; - res = left % right; - break; - case OP_SHL: - res = left << right; - break; - case OP_LSR: - res = ul >> ur; - break; - case OP_ASR: - res = left >> right; - break; - /* Logical */ - case OP_AND: - res = left & right; - break; - case OP_OR: - res = left | right; - break; - case OP_XOR: - res = left ^ right; - break; - case OP_AND_BOOL: - res = left && right; - break; - case OP_OR_BOOL: - res = left || right; - break; - - /* Binary comparison */ - case OP_SET_EQ: - res = left == right; - break; - case OP_SET_NE: - res = left != right; - break; - case OP_SET_LE: - res = left <= right; - break; - case OP_SET_GE: - res = left >= right; - break; - case OP_SET_LT: - res = left < right; - break; - case OP_SET_GT: - res = left > right; - break; - case OP_SET_B: - res = ul < ur; - break; - case OP_SET_A: - res = ul > ur; - break; - case OP_SET_BE: - res = ul <= ur; - break; - case OP_SET_AE: - res = ul >= ur; - break; - default: + if (!res) return 0; - } - res &= bits; - replace_with_pseudo(insn, value_pseudo(res)); + replace_with_pseudo(insn, res); return REPEAT_CSE; } |
