@@ -81,6 +81,41 @@ declare void @print_configuration(ptr, ptr)
81
81
; finish_rewriting.ll
82
82
83
83
declare i64 @__gmpz_get_ui(ptr)
84
+ declare ptr @kore_alloc(i64)
85
+ declare void @memcpy(ptr, ptr, i64)
86
+ declare void @error_on_get(i64, i64)
87
+ declare void @error_on_start_substr(i64, i64)
88
+ declare void @error_on_end_substr(ptr, i64)
89
+ declare void @integer_overflow(i64)
90
+ declare void @buffer_overflow_replace_at(i64, i64, i64)
91
+ declare void @buffer_overflow_update(i64, i64)
92
+ declare void @error_on_update(i64)
93
+ declare i1 @hook_BYTES_mutableBytesEnabled()
94
+ declare i64 @hook_BYTES_length64(ptr)
95
+
96
+ define ptr @copy_if_needed_in_llvm(ptr %b) {
97
+ entry:
98
+ %mutable_bytes_enabled = call i1 @hook_BYTES_mutableBytesEnabled()
99
+ br i1 %mutable_bytes_enabled, label %return_b, label %copy_needed
100
+
101
+ return_b:
102
+ ret ptr %b
103
+
104
+ copy_needed:
105
+ %len = call i64 @hook_BYTES_length64(ptr %b)
106
+ %len_bytes = mul i64 %len, 8 ; 8 bytes per byte
107
+ %alloc_size = add i64 %len_bytes, 40 ; 8 bytes for header, rest for data
108
+ %alloc = call ptr @kore_alloc(i64 %alloc_size)
109
+
110
+ store i64 %len, ptr %alloc
111
+
112
+ %data_ptr = getelementptr i8, ptr %alloc, i64 8
113
+ %b_data_ptr = getelementptr i8, ptr %b, i64 8
114
+
115
+ call void @memcpy(ptr %data_ptr, ptr %b_data_ptr, i64 %len_bytes)
116
+
117
+ ret ptr %data_ptr
118
+ }
84
119
85
120
@exit_int_0 = constant %mpz { i32 0, i32 0, ptr getelementptr inbounds ([0 x i64], ptr @exit_int_0_limbs, i32 0, i32 0) }
86
121
@exit_int_0_limbs = constant [0 x i64] zeroinitializer
@@ -177,7 +212,8 @@ declare noalias ptr @kore_alloc_integer(i64)
177
212
178
213
; string_equal.ll
179
214
180
- declare i32 @memcmp(ptr, ptr, i64);
215
+ declare i32 @memcmp(ptr, ptr, i64)
216
+ declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
181
217
182
218
define i1 @string_equal(ptr %str1, ptr %str2, i64 %len1, i64 %len2) {
183
219
%len_eq = icmp eq i64 %len1, %len2
@@ -245,6 +281,329 @@ define void @take_search_step(ptr %subject) {
245
281
ret void
246
282
}
247
283
284
+ ; MInt Functions
285
+
286
+ define i256 @hook_LIST_size256(ptr %l) {
287
+ entry:
288
+ %len_ptr = getelementptr %list, ptr %l, i64 0, i32 0
289
+ %len = load i64, ptr %len_ptr
290
+ %len_256 = zext i64 %len to i256
291
+ ret i256 %len_256
292
+ }
293
+
294
+ define i256 @hook_BYTES_get256(ptr %b, i256 %off) {
295
+ entry:
296
+ ; Check for buffer overflow
297
+ %len = call i64 @hook_BYTES_length64(ptr %b)
298
+ %len_256 = zext i64 %len to i256
299
+ %off_lt_len = icmp ult i256 %off, %len_256
300
+ br i1 %off_lt_len, label %valid_off, label %overflow
301
+ overflow:
302
+ %off_trunc = trunc i256 %off to i64
303
+ call void @error_on_get(i64 %off_trunc, i64 %len)
304
+ unreachable
305
+ valid_off:
306
+ ; Load the byte at the specified offset
307
+ %data_ptr = getelementptr %string, ptr %b, i256 0, i32 1, i256 0
308
+ %byte_ptr = getelementptr i8, ptr %data_ptr, i256 %off
309
+ %byte_value = load i8, ptr %byte_ptr
310
+
311
+ ; Return the byte value as an i256
312
+ %result = zext i8 %byte_value to i256
313
+ ret i256 %result
314
+ }
315
+
316
+ define ptr @hook_BYTES_substr256(ptr %input, i256 %start, i256 %end) {
317
+ entry:
318
+ %end_lt_start = icmp ult i256 %end, %start
319
+ br i1 %end_lt_start, label %error, label %check_length
320
+ error:
321
+ %end_trunc = trunc i256 %end to i64
322
+ %start_trunc = trunc i256 %start to i64
323
+ call void @error_on_start_substr(i64 %start_trunc, i64 %end_trunc)
324
+ unreachable
325
+ check_length:
326
+ %input_len = call i64 @hook_BYTES_length64(ptr %input)
327
+ %input_len_256 = zext i64 %input_len to i256
328
+ %end_gt_input_len = icmp ugt i256 %end, %input_len_256
329
+ br i1 %end_gt_input_len, label %error_length, label %calculate_length
330
+ error_length:
331
+ %end_trunc2 = trunc i256 %end to i64
332
+ call void @error_on_end_substr(ptr %input, i64 %end_trunc2)
333
+ unreachable
334
+ calculate_length:
335
+ %len = sub i256 %end, %start
336
+
337
+ %bytes_len = mul i256 %len, 8
338
+ %alloc_size = add i256 40, %bytes_len
339
+ %alloc_size_i64 = trunc i256 %alloc_size to i64
340
+ %alloc = call ptr @kore_alloc(i64 %alloc_size_i64)
341
+
342
+ %len_i64 = trunc i256 %len to i64
343
+ %bytes_ptr = getelementptr [40 x i8], ptr %alloc, i64 0, i64 0
344
+ store i64 %len_i64, ptr %bytes_ptr
345
+
346
+ %data_ptr = getelementptr [40 x i8], ptr %alloc, i64 0, i64 8
347
+ %input_data_ptr = getelementptr %string, ptr %input, i256 0, i32 1, i256 0
348
+ %start_ptr = getelementptr i8, ptr %input_data_ptr, i256 %start
349
+ %end_ptr = getelementptr i8, ptr %input_data_ptr, i256 %end
350
+ call void @memcpy(ptr %data_ptr, ptr %start_ptr, i64 %len_i64)
351
+
352
+ %result = bitcast ptr %alloc to ptr
353
+ ret ptr %result
354
+ }
355
+
356
+ define i256 @hook_BYTES_length256(ptr %b) {
357
+ entry:
358
+ %len = call i64 @hook_BYTES_length64(ptr %b)
359
+ %len_256 = zext i64 %len to i256
360
+ ret i256 %len_256
361
+ }
362
+
363
+ define ptr @hook_BYTES_padRight256(ptr %b, i256 %length, i256 %v) {
364
+ entry:
365
+ %len = call i64 @hook_BYTES_length64(ptr %b)
366
+ %len_256 = zext i64 %len to i256
367
+ %length_gt_len = icmp ugt i256 %length, %len_256
368
+ br i1 %length_gt_len, label %pad, label %return_b
369
+
370
+ return_b:
371
+ ret ptr %b
372
+
373
+ pad:
374
+ %v_gt_255 = icmp ugt i256 %v, 255
375
+ br i1 %v_gt_255, label %error, label %allocate
376
+
377
+ error:
378
+ %v_trunc = trunc i256 %v to i64
379
+ call void @integer_overflow(i64 %v_trunc)
380
+ unreachable
381
+
382
+ allocate:
383
+ %bytes_len = mul i256 %length, 8
384
+ %alloc_size = add i256 %bytes_len, 40 ; 8 bytes for header, rest for data
385
+ %alloc_size_i64 = trunc i256 %alloc_size to i64
386
+ %alloc = call ptr @kore_alloc(i64 %alloc_size_i64)
387
+
388
+ %length_i64 = trunc i256 %length to i64
389
+ store i64 %length_i64, ptr %alloc
390
+
391
+ %data_ptr = getelementptr i8, ptr %alloc, i64 8
392
+ %b_data_ptr = getelementptr i8, ptr %b, i64 8
393
+ call void @memcpy(ptr %data_ptr, ptr %b_data_ptr, i64 %len)
394
+
395
+ %remaining_bytes = sub i64 %length_i64, %len
396
+ %fill_ptr = getelementptr i8, ptr %data_ptr, i64 %len
397
+ %v_i8 = trunc i256 %v to i8
398
+ call void @llvm.memset.p0.i64(ptr %fill_ptr, i8 %v_i8, i64 %remaining_bytes, i1 false)
399
+
400
+ %result = bitcast ptr %alloc to ptr
401
+ ret ptr %result
402
+ }
403
+
404
+ define ptr @hook_BYTES_padLeft256(ptr %b, i256 %length, i256 %v) {
405
+ entry:
406
+ %len = call i64 @hook_BYTES_length64(ptr %b)
407
+ %len_256 = zext i64 %len to i256
408
+ %length_gt_len = icmp ugt i256 %length, %len_256
409
+ br i1 %length_gt_len, label %pad, label %return_b
410
+
411
+ return_b:
412
+ ret ptr %b
413
+
414
+ pad:
415
+ %v_gt_255 = icmp ugt i256 %v, 255
416
+ br i1 %v_gt_255, label %error, label %allocate
417
+
418
+ error:
419
+ %v_trunc = trunc i256 %v to i64
420
+ call void @integer_overflow(i64 %v_trunc)
421
+ unreachable
422
+
423
+ allocate:
424
+ %bytes_len = mul i256 %length, 8
425
+ %alloc_size = add i256 %bytes_len, 40 ; 8 bytes for header, rest for data
426
+ %alloc_size_i64 = trunc i256 %alloc_size to i64
427
+ %alloc = call ptr @kore_alloc(i64 %alloc_size_i64)
428
+
429
+ %length_i64 = trunc i256 %length to i64
430
+ store i64 %length_i64, ptr %alloc
431
+ %data_ptr = getelementptr i8, ptr %alloc, i64 8
432
+ %b_data_ptr = getelementptr i8, ptr %b, i64 8
433
+ %remaining_bytes = sub i64 %length_i64, %len
434
+ %fill_ptr = getelementptr i8, ptr %data_ptr, i64 0
435
+ %v_i8 = trunc i256 %v to i8
436
+ call void @llvm.memset.p0.i64(ptr %fill_ptr, i8 %v_i8, i64 %remaining_bytes, i1 false)
437
+
438
+ %b_data_end_ptr = getelementptr i8, ptr %data_ptr, i64 %remaining_bytes
439
+ call void @memcpy(ptr %b_data_end_ptr, ptr %b_data_ptr, i64 %len)
440
+
441
+ %result = bitcast ptr %alloc to ptr
442
+ ret ptr %result
443
+ }
444
+
445
+ define ptr @hook_BYTES_replaceAt256(ptr %dest, i256 %index, ptr %src) {
446
+ entry:
447
+ call ptr @copy_if_needed_in_llvm(ptr %dest)
448
+
449
+ %dest_len = call i64 @hook_BYTES_length64(ptr %dest)
450
+ %dest_len_256 = zext i64 %dest_len to i256
451
+
452
+ %src_len = call i64 @hook_BYTES_length64(ptr %src)
453
+ %src_len_256 = zext i64 %src_len to i256
454
+
455
+ %index_sum_dest_src = add i256 %index, %src_len_256
456
+ %index_gt_dest_len = icmp ugt i256 %index_sum_dest_src, %dest_len_256
457
+
458
+ br i1 %index_gt_dest_len, label %error, label %copy_data
459
+
460
+ error:
461
+ %index_trunc = trunc i256 %index to i64
462
+ %dest_len_trunc = trunc i256 %dest_len_256 to i64
463
+ %src_len_trunc = trunc i256 %src_len_256 to i64
464
+ call void @buffer_overflow_replace_at(i64 %index_trunc, i64 %dest_len_trunc, i64 %src_len_trunc)
465
+ unreachable
466
+
467
+ copy_data:
468
+ %data_ptr = getelementptr i8, ptr %dest, i64 8
469
+ %src_data_ptr = getelementptr i8, ptr %src, i64 8
470
+ %index_i64 = trunc i256 %index to i64
471
+ %dest_offset_ptr = getelementptr i8, ptr %data_ptr, i64 %index_i64
472
+ call void @memcpy(ptr %dest_offset_ptr, ptr %src_data_ptr, i64 %src_len)
473
+
474
+ ; Return the modified destination
475
+ ret ptr %dest
476
+ }
477
+
478
+ define ptr @hook_MINT_MInt2Bytes(i256 %mint) {
479
+ entry:
480
+ %alloc = call ptr @kore_alloc(i64 40) ; 8 bytes for header, 32 bytes for MInt
481
+
482
+ ; store 32 as lenght of the MInt in the fist 8 bytes
483
+ %bytes_ptr = getelementptr [40 x i8], ptr %alloc, i64 0, i64 0
484
+ store i64 32, ptr %bytes_ptr
485
+
486
+ ; store the MInt in the next 32 bytes
487
+ %mint_ptr = getelementptr [40 x i8], ptr %alloc, i64 0, i64 8
488
+ %mint_vector = bitcast i256 %mint to <32 x i8>
489
+ %reversed_mint = shufflevector <32 x i8> %mint_vector, <32 x i8> undef, <32 x i32>
490
+ <i32 31, i32 30, i32 29, i32 28, i32 27, i32 26, i32 25, i32 24,
491
+ i32 23, i32 22, i32 21, i32 20, i32 19, i32 18, i32 17, i32 16,
492
+ i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8,
493
+ i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
494
+
495
+ ; Store the reversed MInt bytes in the allocated memory
496
+ %reversed_mint_ptr = alloca <32 x i8>
497
+ store <32 x i8> %reversed_mint, ptr %reversed_mint_ptr
498
+ call void @memcpy(ptr %mint_ptr, ptr %reversed_mint_ptr, i64 32)
499
+
500
+ ; Return the pointer to the bytes
501
+ ret ptr %alloc
502
+ }
503
+
504
+ define i256 @hook_MINT_Bytes2MInt(ptr %bytes) {
505
+ entry:
506
+ %alloc = alloca [32 x i8]
507
+ %bytes_ptr = getelementptr [32 x i8], ptr %alloc, i64 0, i64 0
508
+
509
+ ; The first 8 bytes are the used by the header, so we skip them as
510
+ ; we assume we will always have a 256-bit MInt
511
+ %bytes_contents = getelementptr i8, ptr %bytes, i64 8
512
+ call void @memcpy(ptr %bytes_ptr, ptr %bytes_contents, i64 32)
513
+
514
+ ; Convert the bytes to a 256-bit integer
515
+ %mint = load i256, ptr %bytes_ptr
516
+
517
+ ; Reverse the byte order to convert from little-endian to big-endian
518
+ %mint_vector = bitcast i256 %mint to <32 x i8>
519
+ %reversed_mint = shufflevector <32 x i8> %mint_vector, <32 x i8> undef, <32 x i32>
520
+ <i32 31, i32 30, i32 29, i32 28, i32 27, i32 26, i32 25, i32 24,
521
+ i32 23, i32 22, i32 21, i32 20, i32 19, i32 18, i32 17, i32 16,
522
+ i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8,
523
+ i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
524
+
525
+ ; Convert the reversed vector back to i256
526
+ %result = bitcast <32 x i8> %reversed_mint to i256
527
+ ret i256 %result
528
+ }
529
+
530
+ define ptr @hook_BYTES_update256(ptr %b, i256 %index, i256 %value) {
531
+ entry:
532
+ call ptr @copy_if_needed_in_llvm(ptr %b)
533
+
534
+ %len = call i64 @hook_BYTES_length64(ptr %b)
535
+ %len_256 = zext i64 %len to i256
536
+
537
+ %index_uge_len = icmp uge i256 %index, %len_256
538
+ br i1 %index_uge_len, label %error, label %update_value
539
+
540
+ error:
541
+ %index_trunc = trunc i256 %index to i64
542
+ %len_trunc = trunc i256 %len_256 to i64
543
+ call void @buffer_overflow_update(i64 %index_trunc, i64 %len_trunc)
544
+ unreachable
545
+
546
+ update_value:
547
+ %value_ge_255 = icmp ugt i256 %value, 255
548
+ br i1 %value_ge_255, label %error_value, label %set_value
549
+
550
+ error_value:
551
+ %value_trunc = trunc i256 %value to i64
552
+ call void @error_on_update(i64 %value_trunc)
553
+ unreachable
554
+
555
+ set_value:
556
+ %data_ptr = getelementptr i8, ptr %b, i64 8
557
+ %index_i64 = trunc i256 %index to i64
558
+ %byte_ptr = getelementptr i8, ptr %data_ptr, i64 %index_i64
559
+ %value_i8 = trunc i256 %value to i8
560
+ store i8 %value_i8, ptr %byte_ptr
561
+
562
+ ; Return the modified buffer
563
+ ret ptr %b
564
+ }
565
+
566
+
567
+ define i256 @hook_MINT_pow256(i256 %base, i256 %exp) {
568
+ entry:
569
+ ; Special cases: if exp == 0 return 1, if base == 0 return 0
570
+ %exp_is_zero = icmp eq i256 %exp, 0
571
+ br i1 %exp_is_zero, label %exp_zero, label %check_base
572
+
573
+ exp_zero:
574
+ ret i256 1
575
+
576
+ check_base:
577
+ %base_is_zero = icmp eq i256 %base, 0
578
+ br i1 %base_is_zero, label %base_zero, label %loop
579
+
580
+ base_zero:
581
+ ret i256 0
582
+
583
+ ; Initialize result = 1, current_base = base, current_exp = exp
584
+ loop:
585
+ %result = phi i256 [1, %check_base], [%next_result, %loop_body]
586
+ %curr_base = phi i256 [%base, %check_base], [%next_base, %loop_body]
587
+ %curr_exp = phi i256 [%exp, %check_base], [%next_exp, %loop_body]
588
+ %exp_done = icmp eq i256 %curr_exp, 0
589
+ br i1 %exp_done, label %done, label %loop_body
590
+
591
+ loop_body:
592
+ ; if (curr_exp & 1) result *= curr_base
593
+ %exp_and_1 = and i256 %curr_exp, 1
594
+ %is_odd = icmp ne i256 %exp_and_1, 0
595
+ %mul_result = mul i256 %result, %curr_base
596
+ %next_result = select i1 %is_odd, i256 %mul_result, i256 %result
597
+ ; curr_base *= curr_base
598
+ %next_base = mul i256 %curr_base, %curr_base
599
+ ; curr_exp >>= 1
600
+ %next_exp = lshr i256 %curr_exp, 1
601
+ br label %loop
602
+
603
+ done:
604
+ ret i256 %result
605
+ }
606
+
248
607
define i64 @get_steps() {
249
608
entry:
250
609
%steps = load i64, ptr @steps
0 commit comments