diff options
| author | Mark Rowe <mark@vector35.com> | 2025-10-18 10:31:00 -0700 |
|---|---|---|
| committer | Mark Rowe <mark@vector35.com> | 2025-10-18 22:26:08 -0700 |
| commit | 1ec0d4fced11af730db0d9273fb512563fc02a0a (patch) | |
| tree | ba2890840a1b376ace3bb5cff3d5ae25e55086b2 /arch/arm64 | |
| parent | 419e7ef52e4d0374f19c2836b4eb358359713d57 (diff) | |
[AArch64] Lift FEAT_CSSC instructions
`abs`, `smax`, `smin`, `umax`, and `umin` are lifted to instruction
sequences involving comparisons, while `cnt` and `ctz` are lifted to
intrinsics.
Diffstat (limited to 'arch/arm64')
| -rw-r--r-- | arch/arm64/arch_arm64.cpp | 8 | ||||
| -rw-r--r-- | arch/arm64/il.cpp | 111 | ||||
| -rw-r--r-- | arch/arm64/il.h | 2 |
3 files changed, 121 insertions, 0 deletions
diff --git a/arch/arm64/arch_arm64.cpp b/arch/arm64/arch_arm64.cpp index 5faf37e5..2ec4a9f2 100644 --- a/arch/arm64/arch_arm64.cpp +++ b/arch/arm64/arch_arm64.cpp @@ -996,6 +996,10 @@ class Arm64Architecture : public Architecture return "_eret"; case ARM64_INTRIN_CLZ: return "_CountLeadingZeros"; + case ARM64_INTRIN_CNT: + return "_PopulationCount"; + case ARM64_INTRIN_CTZ: + return "_CountTrailingZeros"; case ARM64_INTRIN_CLREX: return "__clrex"; case ARM64_INTRIN_REV: @@ -1086,6 +1090,8 @@ class Arm64Architecture : public Architecture }; break; case ARM64_INTRIN_CLZ: // reads <Xn> + case ARM64_INTRIN_CNT: // reads <Xn> + case ARM64_INTRIN_CTZ: // reads <Xn> case ARM64_INTRIN_PRFM: case ARM64_INTRIN_REV: // reads <Xn> case ARM64_INTRIN_RBIT: // reads <Xn> @@ -1149,6 +1155,8 @@ class Arm64Architecture : public Architecture case ARM64_INTRIN_XPACD: // writes <Xd> case ARM64_INTRIN_XPACI: // writes <Xd> case ARM64_INTRIN_CLZ: // writes <Xd> + case ARM64_INTRIN_CNT: // writes <Xd> + case ARM64_INTRIN_CTZ: // writes <Xd> case ARM64_INTRIN_REV: // writes <Xd> case ARM64_INTRIN_RBIT: // writes <Xd> return {Type::IntegerType(8, false)}; diff --git a/arch/arm64/il.cpp b/arch/arm64/il.cpp index aaab258a..348bae73 100644 --- a/arch/arm64/il.cpp +++ b/arch/arm64/il.cpp @@ -1307,6 +1307,13 @@ bool GetLowLevelILForInstruction( LowLevelILLabel trueLabel, falseLabel; switch (instr.operation) { + case ARM64_ABS: + { + ExprId src = ILREG_O(operand2); + GenIfElse(il, il.CompareSignedLessThan(REGSZ_O(operand2), src, il.Const(REGSZ_O(operand2), 0)), + ILSETREG_O(operand1, il.Neg(REGSZ_O(operand2), src)), ILSETREG_O(operand1, src)); + break; + } case ARM64_ADD: switch (instr.encoding) { @@ -1733,6 +1740,14 @@ bool GetLowLevelILForInstruction( il.AddInstruction(il.Intrinsic( {RegisterOrFlag::Register(REG_O(operand1))}, ARM64_INTRIN_CLZ, {ILREG_O(operand2)})); break; + case ARM64_CNT: + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(REG_O(operand1))}, ARM64_INTRIN_CNT, {ILREG_O(operand2)})); + break; + case ARM64_CTZ: + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(REG_O(operand1))}, ARM64_INTRIN_CTZ, {ILREG_O(operand2)})); + break; case ARM64_DC: // il.AddInstruction( // il.Intrinsic({}, ARM64_INTRIN_DC, {ILREG_O(operand2)})); /* operand1 is <dc_op> */ @@ -3730,6 +3745,54 @@ bool GetLowLevelILForInstruction( il.MultDoublePrecSigned(REGSZ_O(operand1), ILREG_O(operand2), ILREG_O(operand3)), il.Const(1, 64)))))); break; + case ARM64_SMAX: + { + ExprId op2 = ILREG_O(operand2); + ExprId op3; + + switch (instr.encoding) + { + case ENC_SMAX_32_MINMAX_IMM: + case ENC_SMAX_64_MINMAX_IMM: + op3 = il.Const(REGSZ_O(operand2), operand3.immediate); + break; + case ENC_SMAX_32_DP_2SRC: + case ENC_SMAX_64_DP_2SRC: + op3 = ILREG_O(operand3); + break; + default: + il.AddInstruction(il.Unimplemented()); + return true; + } + + GenIfElse(il, il.CompareSignedGreaterThan(REGSZ_O(operand2), op2, op3), ILSETREG_O(operand1, op2), + ILSETREG_O(operand1, op3)); + break; + } + case ARM64_SMIN: + { + ExprId op2 = ILREG_O(operand2); + ExprId op3; + + switch (instr.encoding) + { + case ENC_SMIN_32_MINMAX_IMM: + case ENC_SMIN_64_MINMAX_IMM: + op3 = il.Const(REGSZ_O(operand2), operand3.immediate); + break; + case ENC_SMIN_32_DP_2SRC: + case ENC_SMIN_64_DP_2SRC: + op3 = ILREG_O(operand3); + break; + default: + il.AddInstruction(il.Unimplemented()); + return true; + } + + GenIfElse(il, il.CompareSignedLessThan(REGSZ_O(operand2), op2, op3), ILSETREG_O(operand1, op2), + ILSETREG_O(operand1, op3)); + break; + } case ARM64_UDIV: switch (instr.encoding) { @@ -3742,6 +3805,54 @@ bool GetLowLevelILForInstruction( il.AddInstruction(ILSETREG_O( operand1, il.DivUnsigned(REGSZ_O(operand2), ILREG_O(operand2), ILREG_O(operand3)))); break; + case ARM64_UMAX: + { + ExprId op2 = ILREG_O(operand2); + ExprId op3; + + switch (instr.encoding) + { + case ENC_UMAX_32U_MINMAX_IMM: + case ENC_UMAX_64U_MINMAX_IMM: + op3 = il.Const(REGSZ_O(operand2), operand3.immediate); + break; + case ENC_UMAX_32_DP_2SRC: + case ENC_UMAX_64_DP_2SRC: + op3 = ILREG_O(operand3); + break; + default: + il.AddInstruction(il.Unimplemented()); + return true; + } + + GenIfElse(il, il.CompareUnsignedGreaterThan(REGSZ_O(operand2), op2, op3), ILSETREG_O(operand1, op2), + ILSETREG_O(operand1, op3)); + break; + } + case ARM64_UMIN: + { + ExprId op2 = ILREG_O(operand2); + ExprId op3; + + switch (instr.encoding) + { + case ENC_UMIN_32U_MINMAX_IMM: + case ENC_UMIN_64U_MINMAX_IMM: + op3 = il.Const(REGSZ_O(operand2), operand3.immediate); + break; + case ENC_UMIN_32_DP_2SRC: + case ENC_UMIN_64_DP_2SRC: + op3 = ILREG_O(operand3); + break; + default: + il.AddInstruction(il.Unimplemented()); + return true; + } + + GenIfElse(il, il.CompareUnsignedLessThan(REGSZ_O(operand2), op2, op3), ILSETREG_O(operand1, op2), + ILSETREG_O(operand1, op3)); + break; + } case ARM64_UBFIZ: il.AddInstruction( ILSETREG_O(operand1, il.ZeroExtend(REGSZ_O(operand1), diff --git a/arch/arm64/il.h b/arch/arm64/il.h index 6be7cfe7..37192275 100644 --- a/arch/arm64/il.h +++ b/arch/arm64/il.h @@ -73,6 +73,8 @@ enum Arm64Intrinsic : uint32_t ARM64_INTRIN_YIELD, ARM64_INTRIN_ERET, ARM64_INTRIN_CLZ, + ARM64_INTRIN_CNT, + ARM64_INTRIN_CTZ, ARM64_INTRIN_CLREX, ARM64_INTRIN_REV, ARM64_INTRIN_RBIT, |
