summaryrefslogtreecommitdiffhomepage
path: root/ir/tv/strcalc.h
blob: 225cd5de5bc32b052fd8c0a44c7570ca7e597d65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
 * This file is part of libFirm.
 * Copyright (C) 2012 University of Karlsruhe.
 */

/**
 * @file
 * @brief   Arithmetic operations on arbitrary precision integer numbers.
 * @author   Mathias Heil, Matthias Braun
 */
#ifndef FIRM_TV_STRCALC_H
#define FIRM_TV_STRCALC_H

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "firm_types.h"

#define SC_BITS 8

typedef uint8_t sc_word;

/**
 * The output mode for integer values.
 */
enum base_t {
	SC_HEX, /**< hexadecimal output with BIG letters */
	SC_DEC, /**< decimal output */
};

/**
 * buffer = value1 + value2
 */
void sc_add(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = buffer + 1
 */
void sc_inc(sc_word *buffer);

/**
 * buffer = value1 - value2
 */
void sc_sub(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = -value
 */
void sc_neg(const sc_word *value, sc_word *buffer);

/**
 * buffer = value1 & value2
 */
void sc_and(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 & ~value2
 */
void sc_andnot(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 | value2
 */
void sc_or(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 | ~value2
 */
void sc_ornot(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 ^ value2
 */
void sc_xor(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = ~value
 */
void sc_not(const sc_word *value, sc_word *buffer);

/**
 * buffer = value1 * value2
 */
void sc_mul(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 / value2
 * @returns carry flag
 */
bool sc_div(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 % value2
 */
void sc_mod(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * div_buffer = value1 / value2
 * mod_buffer = value1 % value2
 * @returns carry
 */
bool sc_divmod(const sc_word *value1, const sc_word *value2,
               sc_word *div_buffer, sc_word *mod_buffer);

/**
 * buffer = value1 << shift_cnt
 */
void sc_shlI(const sc_word *value1, unsigned shift_cnt, sc_word *buffer);

/**
 * buffer = value1 << value2
 */
void sc_shl(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 >>u shift_count
 * @returns carry flag
 */
bool sc_shrI(const sc_word *value1, unsigned shift_count, sc_word *buffer);

/**
 * buffer = value1 >>u value2
 * @returns carry flag
 */
bool sc_shr(const sc_word *value1, const sc_word *value2, sc_word *buffer);

/**
 * buffer = value1 >>s shift_count
 * @returns carry flag
 */
bool sc_shrsI(const sc_word *value1, unsigned shift_cnt, unsigned bitsize,
              sc_word *buffer);

/**
 * buffer = value1 >>s value2
 * @returns carry flag
 */
bool sc_shrs(const sc_word *value1, const sc_word *value2, unsigned bitsize,
             sc_word *buffer);

/**
 * buffer = 0
 */
void sc_zero(sc_word *buffer);

/** return length in sc_words of a strcalc value. */
unsigned sc_get_value_length(void);

/** perform sign extension from @p from_bits size to full buffer */
void sc_sign_extend(sc_word *buffer, unsigned from_bits);

/** perform zero extension from @p from_bits size to full buffer */
void sc_zero_extend(sc_word *buffer, unsigned from_bits);

/**
 * create an value form a string representation
 * @return true if ok, false in case of parse error
 */
bool sc_val_from_str(bool negative, unsigned base, const char *str,
                     size_t len, sc_word *buffer);

/** create a value from a long */
void sc_val_from_long(long l, sc_word *buffer);

/** create a value form an unsigned long */
void sc_val_from_ulong(unsigned long l, sc_word *buffer);

/**
 * Construct a strcalc value form a sequence of bytes in two complement little
 * endian format.
 * @param bytes       pointer to array of bytes
 * @param n_bytes     number of bytes in the sequence
 * @param buffer      destination buffer (calc_buffer if used if NULL)
 */
void sc_val_from_bytes(unsigned char const *bytes, size_t n_bytes,
                       sc_word *buffer);

/**
 * Construct a strcalc value from a sequence of bytes in a little endian
 * formatted buffer. @p from specifies the first byte, @p to the last byte
 * (excluding).
 */
void sc_val_from_bits(unsigned char const *const bytes, unsigned from,
                      unsigned to, sc_word *buffer);

/** converts a value to a long */
long sc_val_to_long(const sc_word *val);
uint64_t sc_val_to_uint64(const sc_word *val);
void sc_min_from_bits(unsigned num_bits, bool sign, sc_word *buffer);
void sc_max_from_bits(unsigned num_bits, bool sign, sc_word *buffer);

/**
 * Convert a strcalc value to a sequence of bytes in two complement little
 * endian representation.
 */
void sc_val_to_bytes(const sc_word *val, unsigned char *buf, size_t buf_size);

/**
 * Compares val1 and val2
 */
ir_relation sc_comp(const sc_word *val1, const sc_word *val2);

int sc_get_highest_set_bit(const sc_word *value);
int sc_get_highest_clear_bit(const sc_word *value);
int sc_get_lowest_set_bit(const sc_word *value);
bool sc_is_negative(const sc_word *value);
bool sc_is_zero(const sc_word *value, unsigned num_bits);
bool sc_is_all_one(const sc_word *value, unsigned num_bits);

/**
 * Return the bits of a tarval at a given byte-offset.
 *
 * @param value     the value
 * @param len       number of valid bits in the value
 * @param byte_ofs  the byte offset
 */
unsigned char sc_sub_bits(const sc_word *value, unsigned len,
                          unsigned byte_ofs);

/**
 * Converts a tarval into a string.
 *
 * @param val1        the value pointer
 * @param bits        number of valid bits in this value
 * @param base        output base
 * @param signed_mode print it signed (only decimal mode supported
 */
const char *sc_print(const sc_word *val1, unsigned bits, enum base_t base,
                     bool signed_mode);

/**
 * Write value into string. The buffer is filled from the end, use the return
 * value to get the real start position of the string!
 * If the buffer is too small for the value, the behavior is undefined!
 */
char *sc_print_buf(char *buf, size_t buf_len, const sc_word *val, unsigned bits,
                   enum base_t base, bool is_signed);

/** Initialize the strcalc module.
 * Sets up internal data structures and constants
 * After the first call subsequent calls have no effect
 */
void init_strcalc(unsigned precision);
void finish_strcalc(void);
unsigned sc_get_precision(void);

/** Return the bit at a given position. */
static inline bool sc_get_bit_at(const sc_word *value, unsigned pos)
{
	unsigned nibble = pos / SC_BITS;
	return (value[nibble] >> (pos % SC_BITS)) & 1;
}

/** Set the bit at the specified position. */
void sc_set_bit_at(sc_word *value, unsigned pos);
void sc_clear_bit_at(sc_word *value, unsigned pos);

unsigned sc_popcount(const sc_word *value, unsigned bits);

#endif