@@ -247,6 +247,31 @@ const BigTomb = struct {
247
247
log .debug ("%{d} => {}" , .{ bt .inst , result });
248
248
const branch = & bt .function .branch_stack .items [bt .function .branch_stack .items .len - 1 ];
249
249
branch .inst_table .putAssumeCapacityNoClobber (bt .inst , result );
250
+
251
+ switch (result ) {
252
+ .register = > | reg | {
253
+ // In some cases (such as bitcast), an operand
254
+ // may be the same MCValue as the result. If
255
+ // that operand died and was a register, it
256
+ // was freed by processDeath. We have to
257
+ // "re-allocate" the register.
258
+ if (bt .function .register_manager .isRegFree (reg )) {
259
+ bt .function .register_manager .getRegAssumeFree (reg , bt .inst );
260
+ }
261
+ },
262
+ .register_c_flag ,
263
+ .register_v_flag ,
264
+ = > | reg | {
265
+ if (bt .function .register_manager .isRegFree (reg )) {
266
+ bt .function .register_manager .getRegAssumeFree (reg , bt .inst );
267
+ }
268
+ bt .function .cpsr_flags_inst = bt .inst ;
269
+ },
270
+ .cpsr_flags = > {
271
+ bt .function .cpsr_flags_inst = bt .inst ;
272
+ },
273
+ else = > {},
274
+ }
250
275
}
251
276
bt .function .finishAirBookkeeping ();
252
277
}
@@ -332,7 +357,7 @@ pub fn generate(
332
357
};
333
358
334
359
for (function .dbg_arg_relocs .items ) | reloc | {
335
- try function .genArgDbgInfo (reloc .inst , reloc .index , call_info . stack_byte_count );
360
+ try function .genArgDbgInfo (reloc .inst , reloc .index );
336
361
}
337
362
338
363
var mir = Mir {
@@ -351,7 +376,8 @@ pub fn generate(
351
376
.prev_di_pc = 0 ,
352
377
.prev_di_line = module_fn .lbrace_line ,
353
378
.prev_di_column = module_fn .lbrace_column ,
354
- .prologue_stack_space = call_info .stack_byte_count + function .saved_regs_stack_space ,
379
+ .stack_size = function .max_end_stack ,
380
+ .saved_regs_stack_space = function .saved_regs_stack_space ,
355
381
};
356
382
defer emit .deinit ();
357
383
@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {
464
490
const total_stack_size = self .max_end_stack + self .saved_regs_stack_space ;
465
491
const aligned_total_stack_end = mem .alignForwardGeneric (u32 , total_stack_size , self .stack_align );
466
492
const stack_size = aligned_total_stack_end - self .saved_regs_stack_space ;
493
+ self .max_end_stack = stack_size ;
467
494
if (Instruction .Operand .fromU32 (stack_size )) | op | {
468
495
self .mir_instructions .set (sub_reloc , .{
469
496
.tag = .sub ,
@@ -1812,7 +1839,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
1812
1839
switch (error_union_mcv ) {
1813
1840
.register = > return self .fail ("TODO errUnionErr for registers" , .{}),
1814
1841
.stack_argument_offset = > | off | {
1815
- return MCValue { .stack_argument_offset = off - err_offset };
1842
+ return MCValue { .stack_argument_offset = off + err_offset };
1816
1843
},
1817
1844
.stack_offset = > | off | {
1818
1845
return MCValue { .stack_offset = off - err_offset };
@@ -1849,7 +1876,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
1849
1876
switch (error_union_mcv ) {
1850
1877
.register = > return self .fail ("TODO errUnionPayload for registers" , .{}),
1851
1878
.stack_argument_offset = > | off | {
1852
- return MCValue { .stack_argument_offset = off - payload_offset };
1879
+ return MCValue { .stack_argument_offset = off + payload_offset };
1853
1880
},
1854
1881
.stack_offset = > | off | {
1855
1882
return MCValue { .stack_offset = off - payload_offset };
@@ -1983,7 +2010,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1983
2010
.dead , .unreach = > unreachable ,
1984
2011
.register = > unreachable , // a slice doesn't fit in one register
1985
2012
.stack_argument_offset = > | off | {
1986
- break :result MCValue { .stack_argument_offset = off - 4 };
2013
+ break :result MCValue { .stack_argument_offset = off + 4 };
1987
2014
},
1988
2015
.stack_offset = > | off | {
1989
2016
break :result MCValue { .stack_offset = off - 4 };
@@ -2259,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2259
2286
.register_c_flag ,
2260
2287
.register_v_flag ,
2261
2288
= > unreachable , // cannot hold an address
2262
- .immediate = > | imm | try self .setRegOrMem (elem_ty , dst_mcv , .{ .memory = imm }),
2263
- .ptr_stack_offset = > | off | try self .setRegOrMem (elem_ty , dst_mcv , .{ .stack_offset = off }),
2289
+ .immediate = > | imm | {
2290
+ try self .setRegOrMem (elem_ty , dst_mcv , .{ .memory = imm });
2291
+ },
2292
+ .ptr_stack_offset = > | off | {
2293
+ try self .setRegOrMem (elem_ty , dst_mcv , .{ .stack_offset = off });
2294
+ },
2264
2295
.register = > | reg | {
2265
2296
const reg_lock = self .register_manager .lockReg (reg );
2266
2297
defer if (reg_lock ) | reg_locked | self .register_manager .unlockReg (reg_locked );
2267
2298
2268
2299
switch (dst_mcv ) {
2269
- .dead = > unreachable ,
2270
- .undef = > unreachable ,
2271
- .cpsr_flags = > unreachable ,
2272
2300
.register = > | dst_reg | {
2273
2301
try self .genLdrRegister (dst_reg , reg , elem_ty );
2274
2302
},
@@ -2304,7 +2332,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2304
2332
try self .genInlineMemcpy (src_reg , dst_reg , len_reg , count_reg , tmp_reg );
2305
2333
}
2306
2334
},
2307
- else = > return self . fail ( "TODO load from register into {}" , .{ dst_mcv }),
2335
+ else = > unreachable , // attempting to load into non- register or non-stack MCValue
2308
2336
}
2309
2337
},
2310
2338
.memory ,
@@ -2401,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2401
2429
// sub src_reg, fp, #off
2402
2430
try self .genSetReg (ptr_ty , src_reg , .{ .ptr_stack_offset = off });
2403
2431
},
2404
- .memory = > | addr | try self .genSetReg (Type . usize , src_reg , .{ .immediate = @intCast (u32 , addr ) }),
2432
+ .memory = > | addr | try self .genSetReg (ptr_ty , src_reg , .{ .immediate = @intCast (u32 , addr ) }),
2405
2433
.stack_argument_offset = > | off | {
2406
2434
_ = try self .addInst (.{
2407
2435
.tag = .ldr_ptr_stack_argument ,
@@ -2507,7 +2535,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2507
2535
switch (mcv ) {
2508
2536
.dead , .unreach = > unreachable ,
2509
2537
.stack_argument_offset = > | off | {
2510
- break :result MCValue { .stack_argument_offset = off - struct_field_offset };
2538
+ break :result MCValue { .stack_argument_offset = off + struct_field_offset };
2511
2539
},
2512
2540
.stack_offset = > | off | {
2513
2541
break :result MCValue { .stack_offset = off - struct_field_offset };
@@ -3347,6 +3375,102 @@ fn genInlineMemcpy(
3347
3375
// end:
3348
3376
}
3349
3377
3378
+ fn genInlineMemset (
3379
+ self : * Self ,
3380
+ dst : MCValue ,
3381
+ val : MCValue ,
3382
+ len : MCValue ,
3383
+ ) ! void {
3384
+ const dst_reg = switch (dst ) {
3385
+ .register = > | r | r ,
3386
+ else = > try self .copyToTmpRegister (Type .initTag (.manyptr_u8 ), dst ),
3387
+ };
3388
+ const dst_reg_lock = self .register_manager .lockReg (dst_reg );
3389
+ defer if (dst_reg_lock ) | lock | self .register_manager .unlockReg (lock );
3390
+
3391
+ const val_reg = switch (val ) {
3392
+ .register = > | r | r ,
3393
+ else = > try self .copyToTmpRegister (Type .initTag (.u8 ), val ),
3394
+ };
3395
+ const val_reg_lock = self .register_manager .lockReg (val_reg );
3396
+ defer if (val_reg_lock ) | lock | self .register_manager .unlockReg (lock );
3397
+
3398
+ const len_reg = switch (len ) {
3399
+ .register = > | r | r ,
3400
+ else = > try self .copyToTmpRegister (Type .usize , len ),
3401
+ };
3402
+ const len_reg_lock = self .register_manager .lockReg (len_reg );
3403
+ defer if (len_reg_lock ) | lock | self .register_manager .unlockReg (lock );
3404
+
3405
+ const count_reg = try self .register_manager .allocReg (null , gp );
3406
+
3407
+ try self .genInlineMemsetCode (dst_reg , val_reg , len_reg , count_reg );
3408
+ }
3409
+
3410
+ fn genInlineMemsetCode (
3411
+ self : * Self ,
3412
+ dst : Register ,
3413
+ val : Register ,
3414
+ len : Register ,
3415
+ count : Register ,
3416
+ ) ! void {
3417
+ // mov count, #0
3418
+ _ = try self .addInst (.{
3419
+ .tag = .mov ,
3420
+ .data = .{ .rr_op = .{
3421
+ .rd = count ,
3422
+ .rn = .r0 ,
3423
+ .op = Instruction .Operand .imm (0 , 0 ),
3424
+ } },
3425
+ });
3426
+
3427
+ // loop:
3428
+ // cmp count, len
3429
+ _ = try self .addInst (.{
3430
+ .tag = .cmp ,
3431
+ .data = .{ .rr_op = .{
3432
+ .rd = .r0 ,
3433
+ .rn = count ,
3434
+ .op = Instruction .Operand .reg (len , Instruction .Operand .Shift .none ),
3435
+ } },
3436
+ });
3437
+
3438
+ // bge end
3439
+ _ = try self .addInst (.{
3440
+ .tag = .b ,
3441
+ .cond = .ge ,
3442
+ .data = .{ .inst = @intCast (u32 , self .mir_instructions .len + 4 ) },
3443
+ });
3444
+
3445
+ // strb val, [src, count]
3446
+ _ = try self .addInst (.{
3447
+ .tag = .strb ,
3448
+ .data = .{ .rr_offset = .{
3449
+ .rt = val ,
3450
+ .rn = dst ,
3451
+ .offset = .{ .offset = Instruction .Offset .reg (count , .none ) },
3452
+ } },
3453
+ });
3454
+
3455
+ // add count, count, #1
3456
+ _ = try self .addInst (.{
3457
+ .tag = .add ,
3458
+ .data = .{ .rr_op = .{
3459
+ .rd = count ,
3460
+ .rn = count ,
3461
+ .op = Instruction .Operand .imm (1 , 0 ),
3462
+ } },
3463
+ });
3464
+
3465
+ // b loop
3466
+ _ = try self .addInst (.{
3467
+ .tag = .b ,
3468
+ .data = .{ .inst = @intCast (u32 , self .mir_instructions .len - 4 ) },
3469
+ });
3470
+
3471
+ // end:
3472
+ }
3473
+
3350
3474
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
3351
3475
/// after codegen for this symbol is done.
3352
3476
fn addDbgInfoTypeReloc (self : * Self , ty : Type ) error {OutOfMemory }! void {
@@ -3369,9 +3493,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
3369
3493
}
3370
3494
}
3371
3495
3372
- fn genArgDbgInfo (self : * Self , inst : Air.Inst.Index , arg_index : u32 , stack_byte_count : u32 ) error {OutOfMemory }! void {
3373
- const prologue_stack_space = stack_byte_count + self .saved_regs_stack_space ;
3374
-
3496
+ fn genArgDbgInfo (self : * Self , inst : Air.Inst.Index , arg_index : u32 ) error {OutOfMemory }! void {
3375
3497
const mcv = self .args [arg_index ];
3376
3498
const ty = self .air .instructions .items (.data )[inst ].ty ;
3377
3499
const name = self .mod_fn .getParamName (self .bin_file .options .module .? , arg_index );
@@ -3404,7 +3526,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c
3404
3526
// const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3405
3527
const adjusted_stack_offset = switch (mcv ) {
3406
3528
.stack_offset = > | offset | - @intCast (i32 , offset ),
3407
- .stack_argument_offset = > | offset | @intCast (i32 , prologue_stack_space - offset ),
3529
+ .stack_argument_offset = > | offset | @intCast (i32 , self . saved_regs_stack_space + offset ),
3408
3530
else = > unreachable ,
3409
3531
};
3410
3532
@@ -3524,7 +3646,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3524
3646
try self .register_manager .getReg (reg , null );
3525
3647
}
3526
3648
3527
- if (info .return_value == .stack_offset ) {
3649
+ // If returning by reference, r0 will contain the address of where
3650
+ // to put the result into. In that case, make sure that r0 remains
3651
+ // untouched by the parameter passing code
3652
+ const r0_lock : ? RegisterLock = if (info .return_value == .stack_offset ) blk : {
3528
3653
log .debug ("airCall: return by reference" , .{});
3529
3654
const ret_ty = fn_ty .fnReturnType ();
3530
3655
const ret_abi_size = @intCast (u32 , ret_ty .abiSize (self .target .* ));
@@ -3540,7 +3665,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3540
3665
try self .genSetReg (ptr_ty , .r0 , .{ .ptr_stack_offset = stack_offset });
3541
3666
3542
3667
info .return_value = .{ .stack_offset = stack_offset };
3543
- }
3668
+
3669
+ break :blk self .register_manager .lockRegAssumeUnused (.r0 );
3670
+ } else null ;
3671
+ defer if (r0_lock ) | reg | self .register_manager .unlockReg (reg );
3544
3672
3545
3673
// Make space for the arguments passed via the stack
3546
3674
self .max_end_stack += info .stack_byte_count ;
@@ -3559,7 +3687,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3559
3687
.stack_offset = > unreachable ,
3560
3688
.stack_argument_offset = > | offset | try self .genSetStackArgument (
3561
3689
arg_ty ,
3562
- info . stack_byte_count - offset ,
3690
+ offset ,
3563
3691
arg_mcv ,
3564
3692
),
3565
3693
else = > unreachable ,
@@ -4621,11 +4749,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4621
4749
if (! self .wantSafety ())
4622
4750
return ; // The already existing value will do just fine.
4623
4751
// TODO Upgrade this to a memset call when we have that available.
4624
- switch (ty .abiSize (self .target .* )) {
4625
- 1 = > return self .genSetStack (ty , stack_offset , .{ .immediate = 0xaa }),
4626
- 2 = > return self .genSetStack (ty , stack_offset , .{ .immediate = 0xaaaa }),
4627
- 4 = > return self .genSetStack (ty , stack_offset , .{ .immediate = 0xaaaaaaaa }),
4628
- else = > return self .fail ("TODO implement memset" , .{}),
4752
+ switch (abi_size ) {
4753
+ 1 = > try self .genSetStack (ty , stack_offset , .{ .immediate = 0xaa }),
4754
+ 2 = > try self .genSetStack (ty , stack_offset , .{ .immediate = 0xaaaa }),
4755
+ 4 = > try self .genSetStack (ty , stack_offset , .{ .immediate = 0xaaaaaaaa }),
4756
+ else = > try self .genInlineMemset (
4757
+ .{ .ptr_stack_offset = stack_offset },
4758
+ .{ .immediate = 0xaa },
4759
+ .{ .immediate = abi_size },
4760
+ ),
4629
4761
}
4630
4762
},
4631
4763
.cpsr_flags ,
@@ -5037,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
5037
5169
return ; // The already existing value will do just fine.
5038
5170
// TODO Upgrade this to a memset call when we have that available.
5039
5171
switch (abi_size ) {
5040
- 1 = > return self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaa }),
5041
- 2 = > return self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaaaa }),
5042
- 4 = > return self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaaaaaaaa }),
5172
+ 1 = > try self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaa }),
5173
+ 2 = > try self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaaaa }),
5174
+ 4 = > try self .genSetStackArgument (ty , stack_offset , .{ .immediate = 0xaaaaaaaa }),
5043
5175
else = > return self .fail ("TODO implement memset" , .{}),
5044
5176
}
5045
5177
},
@@ -5653,8 +5785,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5653
5785
if (ty .abiAlignment (self .target .* ) == 8 )
5654
5786
nsaa = std .mem .alignForwardGeneric (u32 , nsaa , 8 );
5655
5787
5656
- nsaa += param_size ;
5657
5788
result .args [i ] = .{ .stack_argument_offset = nsaa };
5789
+ nsaa += param_size ;
5658
5790
}
5659
5791
}
5660
5792
@@ -5687,9 +5819,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5687
5819
for (param_types ) | ty , i | {
5688
5820
if (ty .abiSize (self .target .* ) > 0 ) {
5689
5821
const param_size = @intCast (u32 , ty .abiSize (self .target .* ));
5822
+ const param_alignment = ty .abiAlignment (self .target .* );
5690
5823
5691
- stack_offset = std .mem .alignForwardGeneric (u32 , stack_offset , ty . abiAlignment ( self . target .* )) + param_size ;
5824
+ stack_offset = std .mem .alignForwardGeneric (u32 , stack_offset , param_alignment ) ;
5692
5825
result .args [i ] = .{ .stack_argument_offset = stack_offset };
5826
+ stack_offset += param_size ;
5693
5827
} else {
5694
5828
result .args [i ] = .{ .none = {} };
5695
5829
}
0 commit comments