Create and use LZCOUNT Pcode op

This commit is contained in:
Pokechu22 2022-07-11 12:40:19 -07:00
parent 865cd22cab
commit 14880b53c4
47 changed files with 288 additions and 247 deletions

View file

@ -3617,6 +3617,7 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &worklist)
pushConsumed(b,op->getIn(2), worklist);
break;
case CPUI_POPCOUNT:
case CPUI_LZCOUNT:
a = 16 * op->getIn(0)->getSize() - 1; // Mask for possible bits that could be set
a &= outc; // Of the bits that could be set, which are consumed
b = (a == 0) ? 0 : ~((uintb)0); // if any consumed, treat all input bits as consumed

View file

@ -55,7 +55,8 @@ const uint4 DynamicHash::transtable[] = {
0, // CAST is skipped
CPUI_INT_ADD, CPUI_INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT, CPUI_POPCOUNT
CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT,
CPUI_POPCOUNT, CPUI_LZCOUNT
};

View file

@ -645,6 +645,10 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
resmask = coveringmask((uintb)sz1);
resmask &= fullmask;
break;
case CPUI_LZCOUNT:
resmask = coveringmask(getIn(0)->getSize() * 8);
resmask &= fullmask;
break;
case CPUI_SUBPIECE:
resmask = getIn(0)->getNZMask();
sz1 = (int4)getIn(1)->getOffset();

View file

@ -102,6 +102,7 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false);
inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false);
inst[CPUI_POPCOUNT] = new OpBehaviorPopcount();
inst[CPUI_LZCOUNT] = new OpBehaviorLzcount();
}
/// \param sizeout is the size of the output in bytes
@ -757,3 +758,8 @@ uintb OpBehaviorPopcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) cons
return (uintb)popcount(in1);
}
uintb OpBehaviorLzcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const
{
return (uintb)(count_leading_zeros(in1) - 8*(sizeof(uintb) - sizein));
}

View file

@ -511,4 +511,11 @@ public:
virtual uintb evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const;
};
/// CPUI_LZCOUNT behavior
class OpBehaviorLzcount : public OpBehavior {
public:
OpBehaviorLzcount(void) : OpBehavior(CPUI_LZCOUNT,true) {} ///< Constructor
virtual uintb evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const;
};
#endif

View file

@ -42,14 +42,14 @@ static const char *opcode_name[] = {
"TRUNC", "CEIL", "FLOOR", "ROUND",
"BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST",
"LABEL", "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW",
"INSERT", "EXTRACT", "POPCOUNT"
"INSERT", "EXTRACT", "POPCOUNT", "LZCOUNT"
};
static const int4 opcode_indices[] = {
0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66,
0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66,
61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70,
54, 24, 19, 27, 21, 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30,
23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62, 72, 10, 59,
23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 73, 69, 62, 72, 10, 59,
67, 3, 63, 56, 45
};

View file

@ -123,8 +123,9 @@ enum OpCode {
CPUI_INSERT = 70, ///< Insert a bit-range
CPUI_EXTRACT = 71, ///< Extract a bit-range
CPUI_POPCOUNT = 72, ///< Count the 1-bits
CPUI_LZCOUNT = 73, ///< Count the leading 0-bits
CPUI_MAX = 73 ///< Value indicating the end of the op-code values
CPUI_MAX = 74 ///< Value indicating the end of the op-code values
};
extern const char *get_opname(OpCode opc); ///< Convert an OpCode to the name as a string

View file

@ -329,6 +329,7 @@ public:
virtual void opInsertOp(const PcodeOp *op);
virtual void opExtractOp(const PcodeOp *op);
virtual void opPopcountOp(const PcodeOp *op) { opFunc(op); }
virtual void opLzcountOp(const PcodeOp *op) { opFunc(op); }
};
/// \brief Set of print commands for displaying an open brace '{' and setting a new indent level

View file

@ -554,6 +554,7 @@ public:
virtual void opInsertOp(const PcodeOp *op)=0; ///< Emit an INSERT operator
virtual void opExtractOp(const PcodeOp *op)=0; ///< Emit an EXTRACT operator
virtual void opPopcountOp(const PcodeOp *op)=0; ///< Emit a POPCOUNT operator
virtual void opLzcountOp(const PcodeOp *op)=0; ///< Emit a LZCOUNT operator
virtual string unnamedField(int4 off,int4 size); ///< Generate an artificial field name
static int4 mostNaturalBase(uintb val); ///< Determine the most natural base for an integer

View file

@ -785,6 +785,9 @@ void ConsistencyChecker::printOpName(ostream &s,OpTpl *op)
case CPUI_POPCOUNT:
s << "Count bits(popcount)";
break;
case CPUI_LZCOUNT:
s << "Count leading zero bits(lzcount)";
break;
default:
break;
}

View file

@ -94,7 +94,7 @@
%right '!' '~'
%token OP_ZEXT OP_CARRY OP_BORROW OP_SEXT OP_SCARRY OP_SBORROW OP_NAN OP_ABS
%token OP_SQRT OP_CEIL OP_FLOOR OP_ROUND OP_INT2FLOAT OP_FLOAT2FLOAT
%token OP_TRUNC OP_CPOOLREF OP_NEW OP_POPCOUNT
%token OP_TRUNC OP_CPOOLREF OP_NEW OP_POPCOUNT OP_LZCOUNT
%token BADINTEGER GOTO_KEY CALL_KEY RETURN_KEY IF_KEY
%token DEFINE_KEY ATTACH_KEY MACRO_KEY SPACE_KEY TYPE_KEY RAM_KEY DEFAULT_KEY
@ -444,6 +444,7 @@ expr: varnode { $$ = new ExprTree($1); }
| OP_NEW '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3); }
| OP_NEW '(' expr ',' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3,$5); }
| OP_POPCOUNT '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_POPCOUNT,$3); }
| OP_LZCOUNT '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_LZCOUNT,$3); }
| specificsymbol '(' integervarnode ')' { $$ = slgh->pcode.createOp(CPUI_SUBPIECE,new ExprTree($1->getVarnode()),new ExprTree($3)); }
| specificsymbol ':' INTEGER { $$ = slgh->pcode.createBitRange($1,0,(uint4)(*$3 * 8)); delete $3; }
| specificsymbol '[' INTEGER ',' INTEGER ']' { $$ = slgh->pcode.createBitRange($1,(uint4)*$3,(uint4)*$5); delete $3, delete $5; }

View file

@ -641,6 +641,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH
<sem>cpool { return OP_CPOOLREF; }
<sem>newobject { return OP_NEW; }
<sem>popcount { return OP_POPCOUNT; }
<sem>lzcount { return OP_LZCOUNT; }
<sem>if { return IF_KEY; }
<sem>goto { return GOTO_KEY; }
<sem>call { return CALL_KEY; }

View file

@ -102,6 +102,7 @@ void TypeOp::registerInstructions(vector<TypeOp *> &inst,TypeFactory *tlst,
inst[CPUI_INSERT] = new TypeOpInsert(tlst);
inst[CPUI_EXTRACT] = new TypeOpExtract(tlst);
inst[CPUI_POPCOUNT] = new TypeOpPopcount(tlst);
inst[CPUI_LZCOUNT] = new TypeOpLzcount(tlst);
}
/// Change basic data-type info (signed vs unsigned) and operator names ( '>>' vs '>>>' )
@ -2323,3 +2324,10 @@ TypeOpPopcount::TypeOpPopcount(TypeFactory *t)
opflags = PcodeOp::unary;
behave = new OpBehaviorPopcount();
}
TypeOpLzcount::TypeOpLzcount(TypeFactory *t)
: TypeOpFunc(t,CPUI_LZCOUNT,"LZCOUNT",TYPE_INT,TYPE_UNKNOWN)
{
opflags = PcodeOp::unary;
behave = new OpBehaviorLzcount();
}

View file

@ -857,4 +857,11 @@ public:
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opPopcountOp(op); }
};
/// \brief Information about the LZCOUNT op-code
class TypeOpLzcount : public TypeOpFunc {
public:
TypeOpLzcount(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opLzcountOp(op); }
};
#endif

View file

@ -2,7 +2,7 @@
<article id="pcoderef_title">
<info>
<title>P-Code Reference Manual</title>
<releaseinfo>Last updated September 5, 2019</releaseinfo>
<releaseinfo>Last updated March 2, 2023</releaseinfo>
</info>
<table xml:id="mytoc.htmltable" width="90%" frame='none'>
<col width="25%"/>
@ -22,7 +22,7 @@
<td><link linkend="cpui_int_sub">INT_SUB</link></td>
<td><link linkend="cpui_float_equal">FLOAT_EQUAL</link></td>
</tr>
<tr>P
<tr>
<td></td>
<td><link linkend="cpui_store">STORE</link></td>
<td><link linkend="cpui_int_carry">INT_CARRY</link></td>
@ -90,52 +90,58 @@
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_equal">INT_EQUAL</link></td>
<td><link linkend="cpui_lzcount">LZCOUNT</link></td>
<td><link linkend="cpui_int_mult">INT_MULT</link></td>
<td><link linkend="cpui_float_floor">FLOAT_FLOOR</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_notequal">INT_NOTEQUAL</link></td>
<td><link linkend="cpui_int_equal">INT_EQUAL</link></td>
<td><link linkend="cpui_int_div">INT_DIV</link></td>
<td><link linkend="cpui_float_round">FLOAT_ROUND</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_less">INT_LESS</link></td>
<td><link linkend="cpui_int_notequal">INT_NOTEQUAL</link></td>
<td><link linkend="cpui_int_rem">INT_REM</link></td>
<td><link linkend="cpui_float_nan">FLOAT_NAN</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_sless">INT_SLESS</link></td>
<td><link linkend="cpui_int_less">INT_LESS</link></td>
<td><link linkend="cpui_int_sdiv">INT_SDIV</link></td>
<td><link linkend="cpui_int2float">INT2FLOAT</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_lessequal">INT_LESSEQUAL</link></td>
<td><link linkend="cpui_int_sless">INT_SLESS</link></td>
<td><link linkend="cpui_int_srem">INT_SREM</link></td>
<td><link linkend="cpui_float2float">FLOAT2FLOAT</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_slessequal">INT_SLESSEQUAL</link></td>
<td><link linkend="cpui_int_lessequal">INT_LESSEQUAL</link></td>
<td><link linkend="cpui_bool_negate">BOOL_NEGATE</link></td>
<td><link linkend="cpui_trunc">TRUNC</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_zext">INT_ZEXT</link></td>
<td><link linkend="cpui_int_slessequal">INT_SLESSEQUAL</link></td>
<td><link linkend="cpui_bool_xor">BOOL_XOR</link></td>
<td><link linkend="cpui_cpoolref">CPOOLREF</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_sext">INT_SEXT</link></td>
<td><link linkend="cpui_int_zext">INT_ZEXT</link></td>
<td><link linkend="cpui_bool_and">BOOL_AND</link></td>
<td><link linkend="cpui_new">NEW</link></td>
</tr>
<tr>
<td></td>
<td><link linkend="cpui_int_sext">INT_SEXT</link></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<sect1 id="index">
@ -977,6 +983,50 @@ count is zero extended into the output varnode.
</para>
</sect2>
<sect2 id="cpui_lzcount"><title>LZCOUNT</title>
<informalexample>
<table xml:id="lzcount.htmltable" frame="above" width="80%" rules="groups">
<col width="23%"/>
<col width="15%"/>
<col width="61%"/>
<thead>
<tr>
<td align="center" colspan="2"><emphasis role="bold">Parameters</emphasis></td>
<td><emphasis role="bold">Description</emphasis></td>
</tr>
</thead>
<tbody>
<tr>
<td align='right'>input0</td>
<td/>
<td>Input varnode to count.</td>
</tr>
<tr>
<td align='right'>output</td>
<td/>
<td>Resulting integer varnode containing count.</td>
</tr>
</tbody>
<tfoot>
<tr>
<td align="center" colspan="2"><emphasis role="bold">Semantic statement</emphasis></td>
<td/>
</tr>
<tr>
<td/>
<td colspan="2"><code>output = lzcount(input0);</code></td>
</tr>
</tfoot>
</table>
</informalexample>
<para>
This operator counts the number of zeros starting at the most significant bit.
For instance, for a 4-byte varnode, a value of 0 returns 32, a value of 1
returns 31, and the value 2<superscript>31</superscript> returns 0.
The resulting count is zero extended into the output varnode.
</para>
</sect2>
<sect2 id="cpui_int_equal"><title>INT_EQUAL</title>
<informalexample>
<table xml:id="intequal.htmltable" frame="above" width="80%" rules="groups">
@ -4058,6 +4108,11 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = inpu
<td><code>popcount(v0)</code></td>
<td>Count 1 bits in v0.</td>
</tr>
<tr>
<td>LZCOUNT</td>
<td><code>lzcount(v0)</code></td>
<td>Counts the number of leading zero bits in v0.</td>
</tr>
<tr>
<td>INT_EQUAL</td>
<td><code>v0 == v1</code></td>

View file

@ -4,7 +4,7 @@
<title>SLEIGH</title>
<subtitle>A Language for Rapid Processor Specification</subtitle>
<pubdate>Originally published December 16, 2005</pubdate>
<releaseinfo>Last updated August 24, 2022</releaseinfo>
<releaseinfo>Last updated March 2, 2023</releaseinfo>
</info>
<simplesect id="sleigh_history">
<info>
@ -279,7 +279,8 @@ general purpose processor instruction sets. They break up into groups.
</tr>
<tr>
<td>Logical</td>
<td><code>INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNT</code></td>
<td><code>INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT,
POPCOUNT, LZCOUNT</code></td>
</tr>
<tr>
<td>Integer Comparison</td>
@ -3856,6 +3857,12 @@ to lowest.
<td>Count the number of 1 bits in v0.
</td>
</tr>
<tr>
<td><code>LZCOUNT</code></td>
<td><code>lzcount(v0)</code></td>
<td>Count the number of leading 0 bits in v0.
</td>
</tr>
<tr>
<td><code>(simulated)</code></td>
<td><code>v0[6,1]</code></td>

View file

@ -1,57 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pcode.emulate.callother;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.program.model.pcode.Varnode;
public class CountLeadingOnesOpBehavior implements OpBehaviorOther {
@Override
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) {
if (out == null) {
throw new LowlevelError("CALLOTHER: Count Leading Ones op missing required output");
}
if (inputs.length != 2 || inputs[1].getSize() == 0 || inputs[1].isConstant()) {
throw new LowlevelError(
"CALLOTHER: Count Leading Ones op requires one non-constant varnode input");
}
// TODO: add support for larger varnode sizes
Varnode in = inputs[1];
if (in.getSize() > 8 || out.getSize() > 8) {
throw new LowlevelError(
"CALLOTHER: Count Leading Ones op only supports varnodes of size 8-bytes or less");
}
MemoryState memoryState = emu.getMemoryState();
long value = memoryState.getValue(in);
long mask = 1L << ((in.getSize() * 8) - 1);
long count = 0;
while ( (mask & value) != 0 ) {
++count;
value = value << 1;
}
memoryState.setValue(out, count);
}
}

View file

@ -1,60 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pcode.emulate.callother;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
import ghidra.program.model.pcode.Varnode;
public class CountLeadingZerosOpBehavior implements OpBehaviorOther {
@Override
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) {
if (out == null) {
throw new LowlevelError("CALLOTHER: Count Leading Zeros op missing required output");
}
if (inputs.length != 2 || inputs[1].getSize() == 0 || inputs[1].isConstant()) {
throw new LowlevelError(
"CALLOTHER: Count Leading Zeros op requires one non-constant varnode input");
}
// TODO: add support for larger varnode sizes
Varnode in = inputs[1];
if (in.getSize() > 8 || out.getSize() > 8) {
throw new LowlevelError(
"CALLOTHER: Count Leading Zeros op only supports varnodes of size 8-bytes or less");
}
MemoryState memoryState = emu.getMemoryState();
long value = memoryState.getValue(in);
long mask = 1L << ((in.getSize() * 8) - 1);
long count = 0;
while (mask != 0) {
if ((mask & value) != 0) {
break;
}
++count;
mask >>>= 1;
}
memoryState.setValue(out, count);
}
}

View file

@ -104,6 +104,7 @@ public class OpBehaviorFactory {
opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT));
opBehaviorMap.put(PcodeOp.EXTRACT, new SpecialOpBehavior(PcodeOp.EXTRACT));
opBehaviorMap.put(PcodeOp.POPCOUNT, new OpBehaviorPopcount());
opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount());
}
private OpBehaviorFactory() {

View file

@ -0,0 +1,48 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pcode.opbehavior;
import java.math.BigInteger;
import ghidra.program.model.pcode.PcodeOp;
public class OpBehaviorLzcount extends UnaryOpBehavior {
public OpBehaviorLzcount() {
super(PcodeOp.LZCOUNT);
}
@Override
public long evaluateUnary(int sizeout, int sizein, long val) {
long mask = 1L << ((sizein * 8) - 1);
long count = 0;
while (mask != 0) {
if ((mask & val) != 0) {
break;
}
++count;
mask >>>= 1;
}
return count;
}
@Override
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1) {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -113,6 +113,7 @@ public enum OpCode {
CPUI_INSERT,
CPUI_EXTRACT,
CPUI_POPCOUNT,
CPUI_LZCOUNT,
CPUI_MAX;
@ -203,7 +204,8 @@ public enum OpCode {
"UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB",
"FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL",
"FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL",
"CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT" };
"CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT",
"LZCOUNT" };
public static String get_opname(OpCode op) {
return opcode_name[op.ordinal()];
@ -212,7 +214,7 @@ public enum OpCode {
static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66,
61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21,
33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17,
65, 2, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 };
65, 2, 73, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 };
public static OpCode get_opcode(String nm) { // Use binary search to find name
int min = 1; // Don't include BLANK

View file

@ -996,6 +996,9 @@ public abstract class PcodeCompile {
if ("popcount".equals(name) && hasOperands(1, operands, location, name)) {
return createOp(location, OpCode.CPUI_POPCOUNT, r);
}
if ("lzcount".equals(name) && hasOperands(1, operands, location, name)) {
return createOp(location, OpCode.CPUI_LZCOUNT, r);
}
return null;
}
@ -1073,6 +1076,9 @@ public abstract class PcodeCompile {
if ("popcount".equals(name)) {
return true;
}
if ("lzcount".equals(name)) {
return true;
}
return false;
}

View file

@ -75,7 +75,7 @@ public class DynamicHash {
0, // CAST is skipped
PcodeOp.INT_ADD, PcodeOp.INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
PcodeOp.SEGMENTOP, PcodeOp.CPOOLREF, PcodeOp.NEW, PcodeOp.INSERT, PcodeOp.EXTRACT,
PcodeOp.POPCOUNT };
PcodeOp.POPCOUNT, PcodeOp.LZCOUNT };
/**
* An edge between a Varnode and a PcodeOp

View file

@ -132,8 +132,9 @@ public class PcodeOp {
public static final int INSERT = 70;
public static final int EXTRACT = 71;
public static final int POPCOUNT = 72;
public static final int LZCOUNT = 73;
public static final int PCODE_MAX = 73;
public static final int PCODE_MAX = 74;
private static Hashtable<String, Integer> opcodeTable;
@ -689,6 +690,8 @@ public class PcodeOp {
return "EXTRACT";
case POPCOUNT:
return "POPCOUNT";
case LZCOUNT:
return "LZCOUNT";
default:
return "INVALID_OP";

View file

@ -2,7 +2,6 @@
<processor_spec>
<properties>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.m68kEmulateInstructionStateModifier"/>
<property key="assemblyRating:68000:BE:32:default" value="PLATINUM"/>
</properties>
<programcounter register="PC"/>

View file

@ -825,8 +825,6 @@ with : extGUARD=1 {
logflags(); tmp:4 = e2l; getbitfield(tmp, f_off, f_wd); f_reg = tmp; resbitflags(f_reg, f_wd-1);
}
define pcodeop countLeadingZeros;
:bfffo e2l{f_off:f_wd},f_reg is opbig=0xed & op67=3 & $(DAT_DIR_CTL_ADDR_MODES); f_off & f_wd & f_reg & flddo=0 & fldoffdat=0 & flddw=0 & fldwddat=0; e2l
[ savmod2=savmod1; regtsan=regtfan; ] {
# "Find First One in Bit Field" pronounced "boo-foe"
@ -839,7 +837,7 @@ define pcodeop countLeadingZeros;
ZF = (tmp == 0);
VF = 0;
CF = 0;
tmp2:4 = countLeadingZeros(tmp);
tmp2:4 = lzcount(tmp);
# NB- it seems the MSB left most bit is really at offset 0,
# and the right LSB is at offset 31
tmp3:4 = tmp2 % 32:4; # need mod for when there are all zeros, when tmp2 would = 32

View file

@ -17,7 +17,6 @@ package ghidra.program.emulation;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
import ghidra.pcode.emulate.callother.OpBehaviorOther;
import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
@ -45,10 +44,6 @@ public class m68kEmulateInstructionStateModifier extends EmulateInstructionState
ISA_MODE0 = new RegisterValue(isaModeReg, BigInteger.ZERO);
*/
// These classes are defined here:
// ghidra/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother
registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior());
registerPcodeOpBehavior("findFirstOne", new FindFirstOneOpBehavior());
}

View file

@ -117,7 +117,6 @@ define context contextreg
ARMcondCk = (35,35) # Finished ARM condition check phase
;
define pcodeop count_leading_zeroes;
define pcodeop coprocessor_function;
define pcodeop coprocessor_function2;
define pcodeop coprocessor_load;

View file

@ -1608,7 +1608,7 @@ define pcodeop IndexCheck;
:clz^ItCond Rd0811,Rm0003 is TMode=1 & ItCond & op4=0xfab & Rm0003; op12=15 & Rd0811
{
build ItCond;
Rd0811 = count_leading_zeroes(Rm0003);
Rd0811 = lzcount(Rm0003);
}
:cmn^ItCond Rn0003,ThumbExpandImm12 is TMode=1 & ItCond & (op11=0x1e & thc0909=0 & sop0508=8 & thc0404=1 & Rn0003; thc1515=0 & thc0811=15) & ThumbExpandImm12

View file

@ -2484,7 +2484,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
{
build COND;
build rm;
Rd = count_leading_zeroes(rm);
Rd = lzcount(rm);
}
@endif # VERSION_5

View file

@ -19,7 +19,6 @@ import java.math.BigInteger;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
import ghidra.pcode.error.LowlevelError;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
@ -46,8 +45,6 @@ public class ARMEmulateInstructionStateModifier extends EmulateInstructionStateM
aMode = new RegisterValue(TModeReg, BigInteger.ZERO);
}
registerPcodeOpBehavior("count_leading_zeroes", new CountLeadingZerosOpBehavior());
/**
* We could registerPcodeOpBehavior for one or more of the following pcodeop's:
*
@ -85,7 +82,6 @@ public class ARMEmulateInstructionStateModifier extends EmulateInstructionStateM
coprocessor_store2
coprocessor_storelong
coprocessor_storelong2
count_leading_zeroes
disableDataAbortInterrupts
disableFIQinterrupts
disableIRQinterrupts

View file

@ -1001,12 +1001,6 @@ define pcodeop getCopRegH;
define pcodeop setCopReg;
define pcodeop setCopRegH;
# countLeadingOnes(val)
define pcodeop countLeadingOnes;
# countLeadingZeros(val)
define pcodeop countLeadingZeros;
# extractField(value, msbd, lsb)
define pcodeop extractField;

View file

@ -980,13 +980,13 @@ define pcodeop SYNC;
# 0111 00ss ssst tttt dddd d000 0010 0001
:clo RD, RSsrc is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x21 & RD & RSsrc {
# Count leading ones in a word
RD = countLeadingOnes( RSsrc );
RD = lzcount( ~RSsrc );
}
# 0111 00ss ssst tttt dddd d000 0010 0000
:clz RD, RSsrc is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x20 & RD & RSsrc {
# Count leading zeros in a word
RD = countLeadingZeros( RSsrc );
RD = lzcount( RSsrc );
}
# 0000 00ss ssst tttt 0000 0000 0001 1010
@ -1573,11 +1573,11 @@ define pcodeop SYNC;
}
:clo RD, RSsrc is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x11 & RD & RSsrc {
RD = countLeadingOnes( RSsrc );
RD = lzcount( ~RSsrc );
}
:clz RD, RSsrc is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x10 & RD & RSsrc {
RD = countLeadingZeros( RSsrc );
RD = lzcount( RSsrc );
}
:div RD, RS32src, RT32src is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1A & fct2=0x02 & RD & RS32src & RT32src {

View file

@ -7,11 +7,11 @@
# 0111 00ss ssst tttt dddd d000 0010 0101
:dclo RD, RSsrc is $(AMODE) & ((REL6=0 & prime=0x1C & sa=0x0 & fct=0x25) | (REL6=1 & prime=0x00 & sa=0x1 & fct=0x13 & op=0)) & RD & RSsrc {
RD = countLeadingOnes( RSsrc );
RD = lzcount( ~RSsrc );
}
# 0111 00ss ssst tttt dddd d000 0010 0100
:dclz RD, RSsrc is $(AMODE) & ((REL6=0 & prime=0x1C & sa=0x0 & fct=0x24) | (REL6=1 & prime=0x00 & sa=0x1 & fct=0x12 & op=0)) & RD & RSsrc {
RD = countLeadingZeros( RSsrc );
RD = lzcount( RSsrc );
}
# 0111 11ss ssst tttt mmmm mLLL LL00 0011

View file

@ -697,11 +697,11 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG &
}
:clo mic_rt32_5, RS0L is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_rt32_5 & RS0L ; micb_poolax=0b111100 & micb_axf=0b0100101100 {
mic_rt32_5 = countLeadingOnes( RS0L );
mic_rt32_5 = lzcount( ~RS0L );
}
:clz mic_rt32_5, RS0L is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_rt32_5 & RS0L ; micb_poolax=0b111100 & micb_axf=0b0101101100 {
mic_rt32_5 = countLeadingZeros( RS0L );
mic_rt32_5 = lzcount( RS0L );
}
:cop2 EXT_MU23 is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_code ; micb_cop=0b010 & EXT_MU23 [ ext_32_code=mic_code; ] {
@ -1676,11 +1676,11 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG &
}
:dclo mic_rt32_5, mic_rs32_0 is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b111100 & micb_axf=0b0100101100 {
mic_rt32_5 = countLeadingOnes( mic_rs32_0 );
mic_rt32_5 = lzcount( ~mic_rs32_0 );
}
:dclz mic_rt32_5, mic_rs32_0 is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b111100 & micb_axf=0b0101101100 {
mic_rt32_5 = countLeadingZeros( mic_rs32_0 );
mic_rt32_5 = lzcount( mic_rs32_0 );
}
:dext mic_rt32_5, mic_rs32_0, micb_pos, SIZEP is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & REL6=1 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b101100 & micb_pos & SIZEP {

View file

@ -19,8 +19,6 @@ import java.math.BigInteger;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
import ghidra.pcode.emulate.callother.CountLeadingOnesOpBehavior;
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
import ghidra.pcode.error.LowlevelError;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
@ -49,13 +47,6 @@ public class MIPSEmulateInstructionStateModifier extends EmulateInstructionState
ISA_MODE0 = new RegisterValue(isaModeReg, BigInteger.ZERO);
}
// These classes are defined here:
// ghidra/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother
registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior());
registerPcodeOpBehavior("countLeadingOnes", new CountLeadingOnesOpBehavior());
/**
* We could registerPcodeOpBehavior for one or more of the following
* pcodeop's:

View file

@ -1415,7 +1415,6 @@ attach variables vrC_8_15 [vr0_8_15 vr1_8_15 vr2_8_15 vr3_8_15 vr4_8_15 vr5_8_15
################################################################
define pcodeop clearHistory;
define pcodeop countLeadingZeros;
define pcodeop countTrailingZeros;
define pcodeop dataCacheBlockAllocate;
define pcodeop dataCacheBlockFlush;

View file

@ -814,13 +814,13 @@
#cntlzd r0,r0 0x7c 00 00 74
:cntlzd A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=58 & Rc=0
{
A = countLeadingZeros(S);
A = lzcount(S);
}
#cntlzd. r0,r0 0x7c 00 00 75
:cntlzd. A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=58 & Rc=1
{
A = countLeadingZeros(S);
A = lzcount(S);
cr0flags(A);
}
@endif
@ -828,13 +828,13 @@
#cntlzw r0,r0 0x7c 00 00 34
:cntlzw A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=26 & Rc=0
{
A = countLeadingZeros(S:4);
A = lzcount(S:4);
}
#cntlzw. r0,r0 0x7c 00 00 35
:cntlzw. A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=26 & Rc=1
{
A = countLeadingZeros(S:4);
A = lzcount(S:4);
cr0flags(A);
}
#===========================================================

View file

@ -19,7 +19,6 @@ import java.math.BigInteger;
import ghidra.pcode.emulate.Emulate;
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
import ghidra.pcode.emulate.callother.OpBehaviorOther;
import ghidra.pcode.memstate.MemoryState;
import ghidra.pcodeCPort.error.LowlevelError;
@ -30,7 +29,6 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM
public PPCEmulateInstructionStateModifier(Emulate emu) {
super(emu);
registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior());
registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior());
}

View file

@ -490,8 +490,6 @@ define pcodeop cache_index_ivld;
define pcodeop cache_index_wb;
define pcodeop cache_index_wi;
define pcodeop round16;
define pcodeop leading_ones;
define pcodeop leading_zeros;
define pcodeop leading_signs;
define pcodeop crc32;
@ -1840,7 +1838,7 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404=
# CLO D[c], D[a] (RR)
:clo Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x1c0
{
Rd2831 = leading_ones(Rd0811);
Rd2831 = lzcount(~Rd0811);
}
# CLO.H D[c], D[a] (RR)
@ -1848,8 +1846,8 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404=
{
local tmp1:4 = zext(Rd0811[16,16]);
local tmp0:4 = zext(Rd0811[0,16]);
Rd2831[16,16] = leading_ones(tmp1);
Rd2831[0,16] = leading_ones(tmp0);
Rd2831[16,16] = lzcount(~tmp1);
Rd2831[0,16] = lzcount(~tmp0);
}
# CLS D[c], D[a] (RR)
@ -1870,13 +1868,13 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404=
# CLZ D[c], D[a] (RR)
:clz Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x1b0
{
Rd2831 = leading_zeros(Rd0811);
Rd2831 = lzcount(Rd0811);
}
# CLZ.H D[c], D[a] (RR)
:clz.h Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x7c0
{
local result:4 = (leading_zeros(Rd0811[16,16]) << 16) | leading_zeros(Rd0811[0,16]);
local result:4 = (lzcount(Rd0811[16,16]) << 16) | lzcount(Rd0811[0,16]);
Rd2831 = result;
}

View file

@ -11,57 +11,22 @@ macro lzcntflags(input, output) {
:LZCNT Reg16, rm16 is vexMode=0 & opsize=0 & $(PRE_66) & $(PRE_F3) & byte=0x0F; byte=0xBD; Reg16 ... & rm16 {
countTmp:2 = 0;
inputTmp:2 = rm16;
<loopbegin>
if ((inputTmp & 0x8000) != 0) goto <loopend>;
countTmp = countTmp + 1;
inputTmp = (inputTmp << 1) | 1;
goto <loopbegin>;
<loopend>
lzcntflags(rm16, countTmp);
Reg16 = countTmp;
Reg16 = lzcount(rm16);
lzcntflags(rm16, Reg16);
}
:LZCNT Reg32, rm32 is vexMode=0 & opsize=1 & $(PRE_F3) & byte=0x0F; byte=0xBD; Reg32 ... & check_Reg32_dest ... & rm32 {
countTmp:4 = 0;
inputTmp:4 = rm32;
<loopbegin>
if ((inputTmp & 0x80000000) != 0) goto <loopend>;
countTmp = countTmp + 1;
inputTmp = (inputTmp << 1) | 1;
goto <loopbegin>;
<loopend>
lzcntflags(rm32, countTmp);
Reg32 = countTmp;
Reg32 = lzcount(rm32);
lzcntflags(rm32, Reg32);
build check_Reg32_dest;
}
@ifdef IA64
:LZCNT Reg64, rm64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & $(PRE_F3) & $(REX_W) & byte=0x0F; byte=0xBD; Reg64 ... & rm64 {
countTmp:8 = 0;
inputTmp:8 = rm64;
<loopbegin>
if ((inputTmp & 0x8000000000000000) != 0) goto <loopend>;
countTmp = countTmp + 1;
inputTmp = (inputTmp << 1) | 1;
goto <loopbegin>;
<loopend>
lzcntflags(rm64, countTmp);
Reg64 = countTmp;
Reg64 = lzcount(rm64);
lzcntflags(rm64, Reg64);
}
@endif

View file

@ -661,6 +661,7 @@ exprSingle returns Expression:
| pcodeop='floor' '(' op1=expr ')'
| pcodeop='round' '(' op1=expr ')'
| pcodeop='popcount' '(' op1=expr ')'
| pcodeop='lzcount' '(' op1=expr ')'
| pcodeop='cpool' '(' op1=expr ',' op2=expr ',' op3=expr ')'
| pcodeop='newobject' '(' op1=newObjParams ')'
| op=[macroOrPcode] op1=paramlist
@ -1142,4 +1143,4 @@ terminal WS : (' '|'\t'|'\r'|'\n')+;
//
//terminal DEFINENAME: 'synthetic:DEFINENAME';
//terminal BEGINDEFINE: 'synthetic:BEGINDEFINE';
//terminal ENDDEFINE: 'synthetic:ENDDEFINE';
//terminal ENDDEFINE: 'synthetic:ENDDEFINE';

View file

@ -676,6 +676,49 @@ count is zero extended into the output varnode.
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="cpui_lzcount"></a>LZCOUNT</h3></div></div></div>
<div class="informalexample"><div class="table">
<a name="lzcount.htmltable"></a><table xml:id="lzcount.htmltable" frame="above" width="80%" rules="groups">
<col width="23%">
<col width="15%">
<col width="61%">
<thead><tr>
<td align="center" colspan="2"><span class="bold"><strong>Parameters</strong></span></td>
<td><span class="bold"><strong>Description</strong></span></td>
</tr></thead>
<tbody>
<tr>
<td align="right">input0</td>
<td></td>
<td>Input varnode to count.</td>
</tr>
<tr>
<td align="right">output</td>
<td></td>
<td>Resulting integer varnode containing count.</td>
</tr>
</tbody>
<tfoot>
<tr>
<td align="center" colspan="2"><span class="bold"><strong>Semantic statement</strong></span></td>
<td></td>
</tr>
<tr>
<td></td>
<td colspan="2"><code class="code">output = lzcount(input0);</code></td>
</tr>
</tfoot>
</table>
</div></div>
<p>
This operator counts the number of zeros starting at the most significant bit.
For instance, for a 4-byte varnode, a value of 0 returns 32, a value of 1
returns 31, and the value 2<sup>31</sup> returns 0.
The resulting count is zero extended into the output varnode.
</p>
</div>
<div class="sect2">
<div class="titlepage"><div><div><h3 class="title">
<a name="cpui_int_equal"></a>INT_EQUAL</h3></div></div></div>
<div class="informalexample"><div class="table">
<a name="intequal.htmltable"></a><table xml:id="intequal.htmltable" frame="above" width="80%" rules="groups">

View file

@ -26,7 +26,7 @@
<div>
<div><h1 class="title">
<a name="pcoderef_title"></a>P-Code Reference Manual</h1></div>
<div><p class="releaseinfo">Last updated September 5, 2019</p></div>
<div><p class="releaseinfo">Last updated March 2, 2023</p></div>
</div>
<hr>
</div>
@ -117,52 +117,58 @@
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_equal" title="INT_EQUAL">INT_EQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_lzcount" title="LZCOUNT">LZCOUNT</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_mult" title="INT_MULT">INT_MULT</a></td>
<td><a class="link" href="pcodedescription.html#cpui_float_floor" title="FLOAT_FLOOR">FLOAT_FLOOR</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_notequal" title="INT_NOTEQUAL">INT_NOTEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_equal" title="INT_EQUAL">INT_EQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_div" title="INT_DIV">INT_DIV</a></td>
<td><a class="link" href="pcodedescription.html#cpui_float_round" title="FLOAT_ROUND">FLOAT_ROUND</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_less" title="INT_LESS">INT_LESS</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_notequal" title="INT_NOTEQUAL">INT_NOTEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_rem" title="INT_REM">INT_REM</a></td>
<td><a class="link" href="pcodedescription.html#cpui_float_nan" title="FLOAT_NAN">FLOAT_NAN</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_sless" title="INT_SLESS">INT_SLESS</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_less" title="INT_LESS">INT_LESS</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_sdiv" title="INT_SDIV">INT_SDIV</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int2float" title="INT2FLOAT">INT2FLOAT</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_lessequal" title="INT_LESSEQUAL">INT_LESSEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_sless" title="INT_SLESS">INT_SLESS</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_srem" title="INT_SREM">INT_SREM</a></td>
<td><a class="link" href="pcodedescription.html#cpui_float2float" title="FLOAT2FLOAT">FLOAT2FLOAT</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_slessequal" title="INT_SLESSEQUAL">INT_SLESSEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_lessequal" title="INT_LESSEQUAL">INT_LESSEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_bool_negate" title="BOOL_NEGATE">BOOL_NEGATE</a></td>
<td><a class="link" href="pcodedescription.html#cpui_trunc" title="TRUNC">TRUNC</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_zext" title="INT_ZEXT">INT_ZEXT</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_slessequal" title="INT_SLESSEQUAL">INT_SLESSEQUAL</a></td>
<td><a class="link" href="pcodedescription.html#cpui_bool_xor" title="BOOL_XOR">BOOL_XOR</a></td>
<td><a class="link" href="pseudo-ops.html#cpui_cpoolref" title="CPOOLREF">CPOOLREF</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_sext" title="INT_SEXT">INT_SEXT</a></td>
<td><a class="link" href="pcodedescription.html#cpui_int_zext" title="INT_ZEXT">INT_ZEXT</a></td>
<td><a class="link" href="pcodedescription.html#cpui_bool_and" title="BOOL_AND">BOOL_AND</a></td>
<td><a class="link" href="pseudo-ops.html#cpui_new" title="NEW">NEW</a></td>
</tr>
<tr>
<td></td>
<td><a class="link" href="pcodedescription.html#cpui_int_sext" title="INT_SEXT">INT_SEXT</a></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>

View file

@ -139,6 +139,11 @@
<td><code class="code">popcount(v0)</code></td>
<td>Count 1 bits in v0.</td>
</tr>
<tr>
<td>LZCOUNT</td>
<td><code class="code">lzcount(v0)</code></td>
<td>Counts the number of leading zero bits in v0.</td>
</tr>
<tr>
<td>INT_EQUAL</td>
<td><code class="code">v0 == v1</code></td>

View file

@ -27,7 +27,7 @@
<div><h1 class="title">
<a name="sleigh_title"></a>SLEIGH</h1></div>
<div><h3 class="subtitle"><i>A Language for Rapid Processor Specification</i></h3></div>
<div><p class="releaseinfo">Last updated August 24, 2022</p></div>
<div><p class="releaseinfo">Last updated March 2, 2023</p></div>
<div><p class="pubdate">Originally published December 16, 2005</p></div>
</div>
<hr>
@ -372,7 +372,8 @@ general purpose processor instruction sets. They break up into groups.
</tr>
<tr>
<td>Logical</td>
<td><code class="code">INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNT</code></td>
<td><code class="code">INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT,
POPCOUNT, LZCOUNT</code></td>
</tr>
<tr>
<td>Integer Comparison</td>

View file

@ -83,6 +83,12 @@ to lowest.
<td>Count the number of 1 bits in v0.
</td>
</tr>
<tr>
<td><code class="code">LZCOUNT</code></td>
<td><code class="code">lzcount(v0)</code></td>
<td>Count the number of leading 0 bits in v0.
</td>
</tr>
<tr>
<td><code class="code">(simulated)</code></td>
<td><code class="code">v0[6,1]</code></td>