diff --git a/compiler/src/dmd/backend/arm/disasmarm.d b/compiler/src/dmd/backend/arm/disasmarm.d index 5f9645c48354..cb9266f61757 100644 --- a/compiler/src/dmd/backend/arm/disasmarm.d +++ b/compiler/src/dmd/backend/arm/disasmarm.d @@ -378,12 +378,15 @@ void disassemble(uint c) @trusted p1 = addsubTab[opS]; p2 = regString(sf, Rd); p3 = regString(sf, Rn); - p4 = wordtostring(imm12 << (sh * 12)); + p4 = wordtostring(imm12); + if (sh) + p5 = "lsl #12"; if (opS == 0 && sh == 0 && imm12 == 0 && (Rd == 31 || Rn == 31)) { p1 = "mov"; // https://www.scs.stanford.edu/~zyedidia/arm64/add_addsub_imm.html p4 = ""; + p5 = ""; } else if (opS == 1 && Rd == 31) // adds { @@ -1377,7 +1380,7 @@ void disassemble(uint c) @trusted p5 = ""; } } - else if (field(ins, 28, 24) == 11 && field(ins, 21, 21) == 0) // https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_shift + else if (field(ins, 28, 24) == 0x0B && field(ins, 21, 21) == 0) // https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#addsub_shift { if (log) printf("Add/subtract (shifted register)\n"); uint sf = field(ins, 31, 31); @@ -1429,7 +1432,7 @@ void disassemble(uint c) @trusted } } } - else if (field(ins, 28, 24) == 11 && field(ins, 21, 21)) // https://www.scs.stanford.edu/~zyedidia/arm64/subs_addsub_ext.html + else if (field(ins, 28, 24) == 0x0B && field(ins, 21, 21)) // https://www.scs.stanford.edu/~zyedidia/arm64/subs_addsub_ext.html { if (log) printf("Add/subtract (extended register)\n"); uint sf = field(ins, 31, 31); @@ -1474,7 +1477,7 @@ void disassemble(uint c) @trusted p1 = "cmn"; // https://www.scs.stanford.edu/~zyedidia/arm64/cmn_adds_addsub_ext.html shiftP(); } - else if (opS == 3 && Rd == 0) + else if (opS == 3 && Rd == 31) { p1 = "cmp"; // https://www.scs.stanford.edu/~zyedidia/arm64/cmp_subs_addsub_ext.html shiftP(); @@ -1600,9 +1603,18 @@ void disassemble(uint c) @trusted string[4] opstring = [ "csel", "csinc", "csinv", "csneg" ]; p1 = opstring[op * 2 + (op2 & 1)]; p2 = regString(sf, Rd); - p3 = regString(sf, Rn); - p4 = regString(sf, Rm); - p5 = condstring[cond]; + if (op * 2 + (op2 & 1) == 1 && + Rm == 0x1F && Rn == 0x1F) + { + p1 = "cset"; + p3 = condstring[cond ^ 1]; + } + else + { + p3 = regString(sf, Rn); + p4 = regString(sf, Rm); + p5 = condstring[cond]; + } } else if (field(ins, 28, 24) == 0x1B) // http://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#dp_3src { @@ -2097,7 +2109,7 @@ const(char)[] labeltostring(ulong w) @trusted const(char)[] indexString(uint reg) { - __gshared char[1 + 2 + 1 + 1] EA; + __gshared char[1 + 3 + 1 + 1] EA; const n = snprintf(EA.ptr, EA.length, "[%s]", regString(1, reg).ptr); assert(n <= EA.length); @@ -2220,8 +2232,12 @@ unittest unittest { int line64 = __LINE__; - string[46] cases64 = // 64 bit code gen + string[50] cases64 = // 64 bit code gen [ + "B9 00 03 A1 str w1,[x29]", + "1A 9F A7 E0 cset w0,lt", + "91 40 00 00 add x0,x0,#0,lsl #12", + "D5 3B D0 40 mrs x0,S3_3_c13_c0_2", "A8 C1 7B FD ldp x29,x30,[sp],#16", "90 00 00 00 adrp x0,#0", "A9 01 7B FD stp x29,x30,[sp,#16]", diff --git a/compiler/src/dmd/backend/arm/instr.d b/compiler/src/dmd/backend/arm/instr.d index 47dba78880ae..33bf88f4095c 100644 --- a/compiler/src/dmd/backend/arm/instr.d +++ b/compiler/src/dmd/backend/arm/instr.d @@ -19,6 +19,19 @@ import core.stdc.stdio; nothrow: @safe: +enum Extend +{ + UXTB, + UXTH, + UXTW, + LSL, + UXTX = LSL, + SXTB, + SXTH, + SXTW, + SXTX, +} + /************************ * AArch64 instructions */ @@ -28,6 +41,7 @@ struct INSTR enum uint nop = 0xD503201F; + alias reg_t = ubyte; /************************************ Reserved ***********************************************/ /* https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#reserved */ @@ -68,6 +82,7 @@ struct INSTR */ static uint addsub_imm(uint sf, uint op, uint S, uint sh, uint imm12, ubyte Rn, ubyte Rd) { + assert(imm12 < 0x1000); return (sf << 31) | (op << 30) | (S << 29) | @@ -118,6 +133,17 @@ struct INSTR /****************************** Branches, Exception Generating and System instructions **************/ /* https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#control */ + /* System register move + * MSR/MRS + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#systemmove + */ + static uint systemmove(uint L, uint sysreg, ubyte Rt) + { + return (0x354 << 22) | (L << 21) | (1 << 20) | (sysreg << 5) | Rt; + } + + enum tpidr_el0 = 0x5E82; + /* Unconditional branch (register) * BLR * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#branch_reg @@ -211,10 +237,12 @@ struct INSTR */ static uint addsub_shift(uint sf, uint op, uint S, uint shift, ubyte Rm, uint imm6, ubyte Rn, ubyte Rd) { + assert(shift < 4); + assert(imm6 < 64); return (sf << 31) | (op << 30) | (S << 29) | - (0xA << 24) | + (0xB << 24) | (shift << 22) | (0 << 21) | (Rm << 16) | @@ -229,6 +257,7 @@ struct INSTR */ static uint addsub_ext(uint sf, uint op, uint S, uint opt, ubyte Rm, uint option, uint imm3, ubyte Rn, ubyte Rd) { + assert(imm3 < 8); return (sf << 31) | (op << 30) | (S << 29) | @@ -308,6 +337,7 @@ struct INSTR */ static uint condsel(uint sf, uint op, uint S, ubyte Rm, uint cond, uint o2, ubyte Rn, ubyte Rd) { + assert(cond < 16); return (sf << 31) | (op << 30) | (S << 29) | (0xD4 << 21) | (Rm << 16) | (cond << 12) | (o2 << 10) | (Rn << 5) | Rd; } @@ -385,6 +415,24 @@ struct INSTR Rt; } + /* Load/store register (register offset) + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + */ + static uint ldst_regoff(uint size, uint VR, uint opc, ubyte Rm, uint option, uint S, ubyte Rn, ubyte Rt) + { + return (size << 30) | + (7 << 27) | + (VR << 26) | + (opc << 22) | + (1 << 21) | + (Rm << 16) | + (option << 13) | + (S << 12) | + (1 << 11) | + (Rn << 5) | + Rt; + } + /* Load/store register (unsigned immediate) * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_pos */ @@ -485,6 +533,38 @@ struct INSTR return subs_imm(sf, sh, imm12, Rn, 31); } + /* SUBS Rd, Rn, Rm, shift, #imm6 + * http://www.scs.stanford.edu/~zyedidia/arm64/subs_addsub_shift.html + */ + static uint subs_shift(uint sf, ubyte Rm, uint shift, uint imm6, ubyte Rn, ubyte Rd) + { + return addsub_shift(sf, 1, 1, shift, Rm, imm6, Rn, Rd); + } + + /* CMP Rn, Rm, shift, #imm6 + * http://www.scs.stanford.edu/~zyedidia/arm64/cmp_subs_addsub_shift.html + */ + static uint cmp_shift(uint sf, ubyte Rm, uint shift, uint imm6, ubyte Rn) + { + return addsub_shift(sf, 1, 1, shift, Rm, imm6, Rn, 0x1F); + } + + /* SUBS Rd, Rn, Rm, extend, #imm3 + * http://www.scs.stanford.edu/~zyedidia/arm64/cmp_subs_addsub_ext.html + */ + static uint subs_ext(uint sf, ubyte Rm, uint option, uint imm3, ubyte Rn, ubyte Rd) + { + return addsub_ext(sf, 1, 1, 0, Rm, option, imm3, Rn, Rd); + } + + /* CMP Rn, Rm, extend, #imm3 + * http://www.scs.stanford.edu/~zyedidia/arm64/cmp_subs_addsub_ext.html + */ + static uint cmp_ext(uint sf, ubyte Rm, uint option, uint imm3, ubyte Rn) + { + return addsub_ext(sf, 1, 1, 0, Rm, option, imm3, Rn, 0x1F); + } + /* ORR Rd, Rn, Rm{, shift #amount} * https://www.scs.stanford.edu/~zyedidia/arm64/orr_log_shift.html */ @@ -503,6 +583,14 @@ struct INSTR return orr_shifted_register(sf, 0, Rm, 0, 31, Rd); } + /* CSINC Rd, Rn, Rm, ? + * https://www.scs.stanford.edu/~zyedidia/arm64/csinc.html + */ + static uint csinc(uint sf, ubyte Rm, uint cond, ubyte Rn, ubyte Rd) + { + return condsel(sf, 0, 0, Rm, cond, 1, Rn, Rd); + } + /* Loads and Stores */ /* Load/store no-allocate pair (offset) @@ -537,12 +625,36 @@ struct INSTR return ldstpair(opc, VR, 3, L, imm7, Rt2, Rn, Rt); } + /* STRB (immediate) Unsigned offset + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_pos + * https://www.scs.stanford.edu/~zyedidia/arm64/strb_imm.html + */ + static uint strb_imm(ubyte Rt, ubyte Rn, ulong offset) + { + // STRB Rt,[Xn,#offset] + uint size = 0; + uint imm12 = offset & 0xFFF; + return ldst_pos(0, 0, 0, imm12, Rn, Rt); + } + + /* STRH (immediate) Unsigned offset + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_pos + * https://www.scs.stanford.edu/~zyedidia/arm64/strh_imm.html + */ + static uint strh_imm(ubyte Rt, ubyte Rn, ulong offset) + { + // STRH Rt,[Xn,#offset] + uint size = 1; + uint imm12 = offset & 0xFFF; + return ldst_pos(0, 0, 0, imm12, Rn, Rt); + } + /* STR (immediate) Unsigned offset * https://www.scs.stanford.edu/~zyedidia/arm64/str_imm_gen.html */ static uint str_imm_gen(uint is64, ubyte Rt, ubyte Rn, ulong offset) { - // str Rt,[Rn,#offset] + // STR Rt,[Xn,#offset] uint size = 2 + is64; uint imm12 = (cast(uint)offset >> (is64 ? 3 : 2)) & 0xFFF; return ldst_pos(size, 0, 0, imm12, Rn, Rt); @@ -558,4 +670,84 @@ struct INSTR uint imm12 = (cast(uint)offset >> (is64 ? 3 : 2)) & 0xFFF; return ldst_pos(size, 0, 1, imm12, Rn, Rt); } + + /* STRB (register) + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/strb_reg.html + */ + static uint strb_reg(reg_t Rindex,uint extend,uint S,reg_t Xbase,reg_t Rt) + { + // STRB Rt,Xbase,Rindex,extend S + return ldst_regoff(0, 0, 0, Rindex, extend, S, Xbase, Rt); + } + + /* STRH (register) + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/strh_reg.html + */ + static uint strh_reg(reg_t Rindex,uint extend,uint S,reg_t Xbase,reg_t Rt) + { + // STRH Rt,Xbase,Rindex,extend S + return ldst_regoff(0, 1, 0, Rindex, extend, S, Xbase, Rt); + } + + /* STR (register) + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/str_reg_gen.html + */ + static uint str_reg_gen(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // STR Rt,Rbase,Rindex,extend S + return ldst_regoff(2 | sz, 0, 0, Rindex, extend, S, Rbase, Rt); + } + + /* LDRB (register) Extended register + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/ldrb_reg.html + */ + static uint ldrb_reg(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // LDRB Rt,Rbase,Rindex,extend S + return ldst_regoff(0, 0, 1, Rindex, extend, S, Rbase, Rt); + } + + /* LDRSB (register) Extended register + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/ldrb_reg.html + */ + static uint ldrsb_reg(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // LDRB Rt,Rbase,Rindex,extend S + return ldst_regoff(0, 0, 2 + (sz == 8), Rindex, extend, S, Rbase, Rt); + } + + /* LDRH (register) Extended register + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/ldrh_reg.html + */ + static uint ldrh_reg(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // LDRH Rt,Rbase,Rindex,extend S + return ldst_regoff(1, 0, 1, Rindex, extend, S, Rbase, Rt); + } + + /* LDRSH (register) Extended register + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/ldrsh_reg.html + */ + static uint ldrsh_reg(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // LDRSH Rt,Rbase,Rindex,extend S + return ldst_regoff(1, 0, 2 + (sz == 8), Rindex, extend, S, Rbase, Rt); + } + + /* LDR (register) + * https://www.scs.stanford.edu/~zyedidia/arm64/encodingindex.html#ldst_regoff + * https://www.scs.stanford.edu/~zyedidia/arm64/ldr_reg_gen.html + */ + static uint ldr_reg_gen(uint sz,reg_t Rindex,uint extend,uint S,reg_t Rbase,reg_t Rt) + { + // LDR Rt,Rbase,Rindex,extend S + return ldst_regoff(2 | sz, 0, 1, Rindex, extend, S, Rbase, Rt); + } }