1 /* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code)
\r
2 2021-02-09 : Igor Pavlov : Public domain */
\r
6 /* #define SHOW_STAT */
\r
18 #include "CpuArch.h"
\r
20 #define CProb UInt16
\r
22 #define kTopValue ((UInt32)1 << 24)
\r
23 #define kNumModelBits 11
\r
24 #define kBitModelTotal (1 << kNumModelBits)
\r
25 #define kNumMoveBits 5
\r
27 void Bcj2Enc_Init(CBcj2Enc *p)
\r
31 p->state = BCJ2_ENC_STATE_OK;
\r
32 p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
\r
37 p->range = 0xFFFFFFFF;
\r
45 p->relatLimit = BCJ2_RELAT_LIMIT;
\r
51 for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
\r
52 p->probs[i] = kBitModelTotal >> 1;
\r
55 static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p)
\r
57 if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0)
\r
59 Byte *buf = p->bufs[BCJ2_STREAM_RC];
\r
62 if (buf == p->lims[BCJ2_STREAM_RC])
\r
64 p->state = BCJ2_STREAM_RC;
\r
65 p->bufs[BCJ2_STREAM_RC] = buf;
\r
68 *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32));
\r
71 while (--p->cacheSize);
\r
72 p->bufs[BCJ2_STREAM_RC] = buf;
\r
73 p->cache = (Byte)((UInt32)p->low >> 24);
\r
76 p->low = (UInt32)p->low << 8;
\r
80 static void Bcj2Enc_Encode_2(CBcj2Enc *p)
\r
82 if (BCJ2_IS_32BIT_STREAM(p->state))
\r
84 Byte *cur = p->bufs[p->state];
\r
85 if (cur == p->lims[p->state])
\r
87 SetBe32(cur, p->tempTarget);
\r
88 p->bufs[p->state] = cur + 4;
\r
91 p->state = BCJ2_ENC_STATE_ORIG;
\r
95 if (p->range < kTopValue)
\r
97 if (RangeEnc_ShiftLow(p))
\r
104 const Byte *src = p->src;
\r
105 const Byte *srcLim;
\r
107 SizeT num = (SizeT)(p->srcLim - src);
\r
109 if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
\r
118 dest = p->bufs[BCJ2_STREAM_MAIN];
\r
119 if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest))
\r
121 num = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest);
\r
124 p->state = BCJ2_STREAM_MAIN;
\r
129 srcLim = src + num;
\r
131 if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80)
\r
139 if ((b & 0xFE) == 0xE8)
\r
142 if (++src != srcLim)
\r
147 if (++src == srcLim)
\r
149 if ((*src & 0xF0) != 0x80)
\r
155 num = (SizeT)(src - p->src);
\r
159 p->prevByte = src[-1];
\r
160 p->bufs[BCJ2_STREAM_MAIN] = dest;
\r
162 p->ip += (UInt32)num;
\r
167 Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]);
\r
168 BoolInt needConvert;
\r
170 p->bufs[BCJ2_STREAM_MAIN] = dest + 1;
\r
171 p->ip += (UInt32)num + 1;
\r
174 needConvert = False;
\r
176 if ((SizeT)(p->srcLim - src) >= 4)
\r
178 UInt32 relatVal = GetUi32(src);
\r
179 if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize)
\r
180 && ((relatVal + p->relatLimit) >> 1) < p->relatLimit)
\r
181 needConvert = True;
\r
188 CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0));
\r
191 bound = (p->range >> kNumModelBits) * ttt;
\r
196 *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
\r
204 *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
\r
207 UInt32 relatVal = GetUi32(src);
\r
210 absVal = p->ip + relatVal;
\r
211 p->prevByte = src[3];
\r
215 unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
\r
216 Byte *cur = p->bufs[cj];
\r
217 if (cur == p->lims[cj])
\r
220 p->tempTarget = absVal;
\r
223 SetBe32(cur, absVal);
\r
224 p->bufs[cj] = cur + 4;
\r
233 if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
\r
236 for (; p->flushPos < 5; p->flushPos++)
\r
237 if (RangeEnc_ShiftLow(p))
\r
239 p->state = BCJ2_ENC_STATE_OK;
\r
243 void Bcj2Enc_Encode(CBcj2Enc *p)
\r
246 PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
248 if (p->tempPos != 0)
\r
250 unsigned extra = 0;
\r
254 const Byte *src = p->src;
\r
255 const Byte *srcLim = p->srcLim;
\r
256 EBcj2Enc_FinishMode finishMode = p->finishMode;
\r
259 p->srcLim = p->temp + p->tempPos;
\r
261 p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
\r
263 PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
265 Bcj2Enc_Encode_2(p);
\r
268 unsigned num = (unsigned)(p->src - p->temp);
\r
269 unsigned tempPos = p->tempPos - num;
\r
271 p->tempPos = tempPos;
\r
272 for (i = 0; i < tempPos; i++)
\r
273 p->temp[i] = p->temp[(size_t)i + num];
\r
276 p->srcLim = srcLim;
\r
277 p->finishMode = finishMode;
\r
279 if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim)
\r
282 if (extra >= tempPos)
\r
284 p->src = src - tempPos;
\r
289 p->temp[tempPos] = src[0];
\r
290 p->tempPos = tempPos + 1;
\r
297 PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
299 Bcj2Enc_Encode_2(p);
\r
301 if (p->state == BCJ2_ENC_STATE_ORIG)
\r
303 const Byte *src = p->src;
\r
304 unsigned rem = (unsigned)(p->srcLim - src);
\r
306 for (i = 0; i < rem; i++)
\r
307 p->temp[i] = src[i];
\r
309 p->src = src + rem;
\r