summaryrefslogtreecommitdiff
path: root/arch/arm64
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2025-10-18 10:31:00 -0700
committerMark Rowe <mark@vector35.com>2025-10-18 22:26:08 -0700
commit1ec0d4fced11af730db0d9273fb512563fc02a0a (patch)
treeba2890840a1b376ace3bb5cff3d5ae25e55086b2 /arch/arm64
parent419e7ef52e4d0374f19c2836b4eb358359713d57 (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.cpp8
-rw-r--r--arch/arm64/il.cpp111
-rw-r--r--arch/arm64/il.h2
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,