@@ -573,25 +573,54 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
573
573
// sub sp, sp, #reloc
574
574
mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .push (.al , .{ .fp , .lr }).toU32 ());
575
575
mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , .fp , Instruction .Operand .reg (.sp , Instruction .Operand .Shift .none )).toU32 ());
576
- // TODO: prepare stack for local variables
577
- // const backpatch_reloc = try self.code.addManyAsArray( 4);
576
+ const backpatch_reloc = self . code . items . len ;
577
+ try self .code .resize ( backpatch_reloc + 4 );
578
578
579
579
try self .dbgSetPrologueEnd ();
580
580
581
581
try self .genBody (self .mod_fn .analysis .success );
582
582
583
583
// Backpatch stack offset
584
- // const stack_end = self.max_end_stack;
585
- // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
586
- // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm()));
584
+ const stack_end = self .max_end_stack ;
585
+ const aligned_stack_end = mem .alignForward (stack_end , self .stack_align );
586
+ if (Instruction .Operand .fromU32 (@intCast (u32 , aligned_stack_end ))) | op | {
587
+ mem .writeIntLittle (u32 , self .code .items [backpatch_reloc .. ][0.. 4], Instruction .sub (.al , .sp , .sp , op ).toU32 ());
588
+ } else {
589
+ return self .fail (self .src , "TODO ARM: allow larger stacks" , .{});
590
+ }
587
591
588
592
try self .dbgSetEpilogueBegin ();
589
593
594
+ // exitlude jumps
595
+ if (self .exitlude_jump_relocs .items .len == 1 ) {
596
+ // There is only one relocation. Hence,
597
+ // this relocation must be at the end of
598
+ // the code. Therefore, we can just delete
599
+ // the space initially reserved for the
600
+ // jump
601
+ self .code .items .len -= 4 ;
602
+ } else for (self .exitlude_jump_relocs .items ) | jmp_reloc | {
603
+ const amt = self .code .items .len - (jmp_reloc + 4 );
604
+ if (amt == 0 ) {
605
+ // This return is at the end of the
606
+ // code block. We can't just delete
607
+ // the space because there may be
608
+ // other jumps we already relocated to
609
+ // the address. Instead, insert a nop
610
+ mem .writeIntLittle (u32 , self .code .items [jmp_reloc .. ][0.. 4], Instruction .nop ().toU32 ());
611
+ } else {
612
+ if (math .cast (i26 , amt )) | offset | {
613
+ mem .writeIntLittle (u32 , self .code .items [jmp_reloc .. ][0.. 4], Instruction .b (.al , offset ).toU32 ());
614
+ } else | err | {
615
+ return self .fail (self .src , "exitlude jump is too large" , .{});
616
+ }
617
+ }
618
+ }
619
+
590
620
// mov sp, fp
591
621
// pop {fp, pc}
592
- // TODO: return by jumping to this code, use relocations
593
- // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
594
- // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
622
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , .sp , Instruction .Operand .reg (.fp , Instruction .Operand .Shift .none )).toU32 ());
623
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .pop (.al , .{ .fp , .pc }).toU32 ());
595
624
} else {
596
625
try self .dbgSetPrologueEnd ();
597
626
try self .genBody (self .mod_fn .analysis .success );
@@ -1661,12 +1690,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1661
1690
mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .jalr (.zero , 0 , .ra ).toU32 ());
1662
1691
},
1663
1692
.arm = > {
1664
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , .sp , Instruction .Operand .reg (.fp , Instruction .Operand .Shift .none )).toU32 ());
1665
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .pop (.al , .{ .fp , .pc }).toU32 ());
1666
- // TODO: jump to the end with relocation
1667
- // // Just add space for an instruction, patch this later
1668
- // try self.code.resize(self.code.items.len + 4);
1669
- // try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
1693
+ // Just add space for an instruction, patch this later
1694
+ try self .code .resize (self .code .items .len + 4 );
1695
+ try self .exitlude_jump_relocs .append (self .gpa , self .code .items .len - 4 );
1670
1696
},
1671
1697
else = > return self .fail (src , "TODO implement return for {}" , .{self .target .cpu .arch }),
1672
1698
}
@@ -1932,6 +1958,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1932
1958
mem .writeIntLittle (i32 , self .code .addManyAsArrayAssumeCapacity (4 ), delta );
1933
1959
}
1934
1960
},
1961
+ .arm = > {
1962
+ if (math .cast (i26 , @intCast (i32 , index ) - @intCast (i32 , self .code .items .len ))) | delta | {
1963
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .b (.al , delta ).toU32 ());
1964
+ } else | err | {
1965
+ return self .fail (src , "TODO: enable larger branch offset" , .{});
1966
+ }
1967
+ },
1935
1968
else = > return self .fail (src , "TODO implement jump for {}" , .{self .target .cpu .arch }),
1936
1969
}
1937
1970
}
@@ -2167,6 +2200,58 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2167
2200
2168
2201
fn genSetStack (self : * Self , src : usize , ty : Type , stack_offset : u32 , mcv : MCValue ) InnerError ! void {
2169
2202
switch (arch ) {
2203
+ .arm = > switch (mcv ) {
2204
+ .dead = > unreachable ,
2205
+ .ptr_stack_offset = > unreachable ,
2206
+ .ptr_embedded_in_code = > unreachable ,
2207
+ .unreach , .none = > return , // Nothing to do.
2208
+ .undef = > {
2209
+ if (! self .wantSafety ())
2210
+ return ; // The already existing value will do just fine.
2211
+ // TODO Upgrade this to a memset call when we have that available.
2212
+ switch (ty .abiSize (self .target .* )) {
2213
+ 1 = > return self .genSetStack (src , ty , stack_offset , .{ .immediate = 0xaa }),
2214
+ 2 = > return self .genSetStack (src , ty , stack_offset , .{ .immediate = 0xaaaa }),
2215
+ 4 = > return self .genSetStack (src , ty , stack_offset , .{ .immediate = 0xaaaaaaaa }),
2216
+ 8 = > return self .genSetStack (src , ty , stack_offset , .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
2217
+ else = > return self .fail (src , "TODO implement memset" , .{}),
2218
+ }
2219
+ },
2220
+ .compare_flags_unsigned = > | op | {
2221
+ return self .fail (src , "TODO implement set stack variable with compare flags value (unsigned)" , .{});
2222
+ },
2223
+ .compare_flags_signed = > | op | {
2224
+ return self .fail (src , "TODO implement set stack variable with compare flags value (signed)" , .{});
2225
+ },
2226
+ .immediate = > {
2227
+ const reg = try self .copyToTmpRegister (src , mcv );
2228
+ return self .genSetStack (src , ty , stack_offset , MCValue { .register = reg });
2229
+ },
2230
+ .embedded_in_code = > | code_offset | {
2231
+ return self .fail (src , "TODO implement set stack variable from embedded_in_code" , .{});
2232
+ },
2233
+ .register = > | reg | {
2234
+ // TODO: strb, strh
2235
+ if (stack_offset <= math .maxInt (u12 )) {
2236
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .str (.al , reg , .fp , .{
2237
+ .offset = Instruction .Offset .imm (@intCast (u12 , stack_offset )),
2238
+ .positive = false ,
2239
+ }).toU32 ());
2240
+ } else {
2241
+ return self .fail (src , "TODO genSetStack with larger offsets" , .{});
2242
+ }
2243
+ },
2244
+ .memory = > | vaddr | {
2245
+ return self .fail (src , "TODO implement set stack variable from memory vaddr" , .{});
2246
+ },
2247
+ .stack_offset = > | off | {
2248
+ if (stack_offset == off )
2249
+ return ; // Copy stack variable to itself; nothing to do.
2250
+
2251
+ const reg = try self .copyToTmpRegister (src , mcv );
2252
+ return self .genSetStack (src , ty , stack_offset , MCValue { .register = reg });
2253
+ },
2254
+ },
2170
2255
.x86_64 = > switch (mcv ) {
2171
2256
.dead = > unreachable ,
2172
2257
.ptr_stack_offset = > unreachable ,
@@ -2274,35 +2359,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2274
2359
return self .genSetReg (src , reg , .{ .immediate = 0xaaaaaaaa });
2275
2360
},
2276
2361
.immediate = > | x | {
2277
- // TODO better analysis of x to determine the
2278
- // least amount of necessary instructions (use
2279
- // more intelligent rotating)
2280
- if (x <= math .maxInt (u8 )) {
2281
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , Instruction .Operand .imm (@truncate (u8 , x ), 0 )).toU32 ());
2282
- return ;
2283
- } else if (x <= math .maxInt (u16 )) {
2284
- // TODO Use movw Note: Not supported on
2285
- // all ARM targets!
2286
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , Instruction .Operand .imm (@truncate (u8 , x ), 0 )).toU32 ());
2287
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 8 ), 12 )).toU32 ());
2288
- } else if (x <= math .maxInt (u32 )) {
2289
- // TODO Use movw and movt Note: Not
2290
- // supported on all ARM targets! Also TODO
2291
- // write constant to code and load
2292
- // relative to pc
2362
+ if (x > math .maxInt (u32 )) return self .fail (src , "ARM registers are 32-bit wide" , .{});
2293
2363
2294
- // immediate: 0xaabbccdd
2295
- // mov reg, #0xaa
2296
- // orr reg, reg, #0xbb, 24
2297
- // orr reg, reg, #0xcc, 16
2298
- // orr reg, reg, #0xdd, 8
2299
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , Instruction .Operand .imm (@truncate (u8 , x ), 0 )).toU32 ());
2300
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 8 ), 12 )).toU32 ());
2301
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 16 ), 8 )).toU32 ());
2302
- mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 24 ), 4 )).toU32 ());
2303
- return ;
2364
+ if (Instruction .Operand .fromU32 (@intCast (u32 , x ))) | op | {
2365
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , op ).toU32 ());
2366
+ } else if (Instruction .Operand .fromU32 (~ @intCast (u32 , x ))) | op | {
2367
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mvn (.al , reg , op ).toU32 ());
2368
+ } else if (x <= math .maxInt (u16 )) {
2369
+ if (Target .arm .featureSetHas (self .target .cpu .features , .has_v7 )) {
2370
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .movw (.al , reg , @intCast (u16 , x )).toU32 ());
2371
+ } else {
2372
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , Instruction .Operand .imm (@truncate (u8 , x ), 0 )).toU32 ());
2373
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 8 ), 12 )).toU32 ());
2374
+ }
2304
2375
} else {
2305
- return self .fail (src , "ARM registers are 32-bit wide" , .{});
2376
+ // TODO write constant to code and load
2377
+ // relative to pc
2378
+ if (Target .arm .featureSetHas (self .target .cpu .features , .has_v7 )) {
2379
+ // immediate: 0xaaaabbbb
2380
+ // movw reg, #0xbbbb
2381
+ // movt reg, #0xaaaa
2382
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .movw (.al , reg , @truncate (u16 , x )).toU32 ());
2383
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .movt (.al , reg , @truncate (u16 , x >> 16 )).toU32 ());
2384
+ } else {
2385
+ // immediate: 0xaabbccdd
2386
+ // mov reg, #0xaa
2387
+ // orr reg, reg, #0xbb, 24
2388
+ // orr reg, reg, #0xcc, 16
2389
+ // orr reg, reg, #0xdd, 8
2390
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .mov (.al , reg , Instruction .Operand .imm (@truncate (u8 , x ), 0 )).toU32 ());
2391
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 8 ), 12 )).toU32 ());
2392
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 16 ), 8 )).toU32 ());
2393
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .orr (.al , reg , reg , Instruction .Operand .imm (@truncate (u8 , x >> 24 ), 4 )).toU32 ());
2394
+ }
2306
2395
}
2307
2396
},
2308
2397
.register = > | src_reg | {
@@ -2319,6 +2408,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2319
2408
try self .genSetReg (src , reg , .{ .immediate = addr });
2320
2409
mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .ldr (.al , reg , reg , .{ .offset = Instruction .Offset .none }).toU32 ());
2321
2410
},
2411
+ .stack_offset = > | unadjusted_off | {
2412
+ // TODO: ldrb, ldrh
2413
+ // TODO: maybe addressing from sp instead of fp
2414
+ if (unadjusted_off <= math .maxInt (u12 )) {
2415
+ mem .writeIntLittle (u32 , try self .code .addManyAsArray (4 ), Instruction .ldr (.al , reg , .fp , .{
2416
+ .offset = Instruction .Offset .imm (@intCast (u12 , unadjusted_off )),
2417
+ .positive = false ,
2418
+ }).toU32 ());
2419
+ } else {
2420
+ return self .fail (src , "TODO genSetReg with larger stack offset" , .{});
2421
+ }
2422
+ },
2322
2423
else = > return self .fail (src , "TODO implement getSetReg for arm {}" , .{mcv }),
2323
2424
},
2324
2425
.riscv64 = > switch (mcv ) {
0 commit comments