@@ -73,6 +73,14 @@ pub const Assembler = struct {
7373 try self .emit32 (0x8b00_0000 | (@as (u32 , rm ) << 16 ) | (@as (u32 , rn ) << 5 ) | rd );
7474 }
7575
76+ pub fn subtractRegister64 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 ) error {NoSpace }! void {
77+ try self .emit32 (0xcb00_0000 | (@as (u32 , rm ) << 16 ) | (@as (u32 , rn ) << 5 ) | rd );
78+ }
79+
80+ pub fn multiply64 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 ) error {NoSpace }! void {
81+ try self .emit32 (0x9b00_7c00 | (@as (u32 , rm ) << 16 ) | (@as (u32 , rn ) << 5 ) | rd );
82+ }
83+
7684 pub fn subtractImmediate64 (self : * Assembler , rd : u5 , rn : u5 , value : u12 ) error {NoSpace }! void {
7785 try self .emit32 (0xd100_0000 | (@as (u32 , value ) << 10 ) | (@as (u32 , rn ) << 5 ) | rd );
7886 }
@@ -155,14 +163,30 @@ pub const Assembler = struct {
155163 try self .emit32 (0x1e63_0000 | (@as (u32 , rn ) << 5 ) | fd );
156164 }
157165
166+ pub fn convertFloat64ToUnsigned64 (self : * Assembler , rd : u5 , fn_ : u5 ) error {NoSpace }! void {
167+ try self .emit32 (0x9e79_0000 | (@as (u32 , fn_ ) << 5 ) | rd );
168+ }
169+
170+ pub fn convertUnsigned64ToFloat64 (self : * Assembler , fd : u5 , rn : u5 ) error {NoSpace }! void {
171+ try self .emit32 (0x9e63_0000 | (@as (u32 , rn ) << 5 ) | fd );
172+ }
173+
158174 pub fn divideUnsigned32 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 ) error {NoSpace }! void {
159175 try self .emit32 (0x1ac0_0800 | (@as (u32 , rm ) << 16 ) | (@as (u32 , rn ) << 5 ) | rd );
160176 }
161177
178+ pub fn divideUnsigned64 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 ) error {NoSpace }! void {
179+ try self .emit32 (0x9ac0_0800 | (@as (u32 , rm ) << 16 ) | (@as (u32 , rn ) << 5 ) | rd );
180+ }
181+
162182 pub fn multiplySubtract32 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 , ra : u5 ) error {NoSpace }! void {
163183 try self .emit32 (0x1b00_8000 | (@as (u32 , rm ) << 16 ) | (@as (u32 , ra ) << 10 ) | (@as (u32 , rn ) << 5 ) | rd );
164184 }
165185
186+ pub fn multiplySubtract64 (self : * Assembler , rd : u5 , rn : u5 , rm : u5 , ra : u5 ) error {NoSpace }! void {
187+ try self .emit32 (0x9b00_8000 | (@as (u32 , rm ) << 16 ) | (@as (u32 , ra ) << 10 ) | (@as (u32 , rn ) << 5 ) | rd );
188+ }
189+
166190 pub fn conditionalSet32 (self : * Assembler , rd : u5 , condition : Condition ) error {NoSpace }! void {
167191 try self .emit32 (0x1a9f_07e0 | (@as (u32 , @intFromEnum (condition .inverted ())) << 12 ) | rd );
168192 }
@@ -361,6 +385,31 @@ test "AArch64 guarded unsigned remainder encodings" {
361385 }
362386}
363387
388+ test "AArch64 guarded unsigned 64-bit arithmetic encodings" {
389+ var storage : [28 ]u8 = undefined ;
390+ var assembler = Assembler .init (& storage );
391+ try assembler .subtractRegister64 (9 , 10 , 11 );
392+ try assembler .multiply64 (12 , 13 , 14 );
393+ try assembler .divideUnsigned64 (15 , 16 , 17 );
394+ try assembler .multiplySubtract64 (18 , 19 , 20 , 21 );
395+ try assembler .convertUnsigned64ToFloat64 (2 , 22 );
396+ try assembler .convertFloat64ToUnsigned64 (23 , 3 );
397+ try assembler .ret ();
398+
399+ const expected = [_ ]u32 {
400+ 0xcb0b_0149 ,
401+ 0x9b0e_7dac ,
402+ 0x9ad1_0a0f ,
403+ 0x9b14_d672 ,
404+ 0x9e63_02c2 ,
405+ 0x9e79_0077 ,
406+ 0xd65f_03c0 ,
407+ };
408+ for (expected , 0.. ) | instruction , index | {
409+ try std .testing .expectEqual (instruction , std .mem .readInt (u32 , assembler .bytes ()[index * 4 .. ][0.. 4], .little ));
410+ }
411+ }
412+
364413test "AArch64 preserves register-resident numeric stack" {
365414 var storage : [24 ]u8 = undefined ;
366415 var assembler = Assembler .init (& storage );
0 commit comments