Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize C extension convertible tool #3

Merged
1 commit merged into from
Dec 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# V8 RISC-V Tools

This directory is for tools developed specifically for the development of the
RISC-V backend.
This directory is for tools developed specifically for the development of the RISC-V backend.

## analyze.py

Expand Down Expand Up @@ -35,3 +34,41 @@ optional arguments:
--print-host-calls Print info about calls to host functions
--fp Print floating point arguments and return values
```

## CountInstr.py

This is a simple tool to collect statistics and compare codes generated by two different backends.

usage:
```
python3 ./v8-riscv-tools/CountInstr.py path_to_riscv_d8 path_to_mips_d8 [args of d8]
```
example:
```
python3 ./v8-riscv-tools/CountInstr.py ./out/riscv64.sim/d8 ./out/mips64el.debug/d8 test.js --test --enable-slow-check
```

## collect-convertible.py

This is a simple tool to collect statistics on instructions that can be directly rewritten into C-extension instructions.

To use the tool, first execute your test with the flags `--print-all-code` or
`--print-code`, dumping the output to a file. Then execute this tool, passing
it that dump file and it will print statistics on convertible instructions.
```bash
$ cctest --print-all-code test-interpreter-intrinsics/Call &> out.log
$ collect-convertible.py out.log
```

The full usage information can be printed using `--help`:
```
usage: collect-convertible.py [-h] [-v] logfile

positional arguments:
logfile

optional arguments:
-h, --help show this help message and exit
-v, --verbose print all convertible instructions
```

170 changes: 94 additions & 76 deletions collect-convertible.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,90 @@ def isIntN(x, n):
def isUIntN(x, n):
return (x >> n) == 0

def is3BitReg(reg):
return bool(re.match(r'^f?(s[01]|a[0-5])$', reg))

instr2constraint = {}
for instr in ['nop', 'ebreak', 'mv']:
instr2constraint[instr] = ((lambda *args: True, 'c.' + instr), )
for instr in ['lw', 'flw', 'sw', 'fsw']:
instr2constraint[instr] = ( (lambda rd, offset, rs:
rs == 'sp'
and isUIntN(int(offset), 8)
and (int(offset) & 0x3) == 0, 'c.'+instr+'sp'),
(lambda rd, offset, rs:
is3BitReg(rd)
and is3BitReg(rs)
and isUIntN(int(offset), 7)
and (int(offset) & 0x3) == 0, 'c.'+instr))
for instr in ['ld', 'fld', 'sd', 'fsd']:
instr2constraint[instr] = ( (lambda rd, offset, rs:
rs == 'sp'
and isUIntN(int(offset), 9)
and (int(offset) & 0x7) == 0, 'c.'+instr+'sp'),
(lambda rd, offset, rs:
is3BitReg(rd)
and is3BitReg(rs)
and isUIntN(int(offset), 8)
and (int(offset) & 0x7) == 0, 'c.'+instr))
for instr in ['jalr', 'jr']:
instr2constraint[instr] = ((lambda *args: len(args) == 1, 'c.'+instr), )
for instr in ['j']:
instr2constraint[instr] = ((lambda *args: len(args) == 1
and isUIntN(int(args[0]), 12)
and (int(args[0]) & 0x1) == 0, 'c.'+instr), )
for instr in ['beq', 'bne']:
instr2constraint[instr] = ((lambda rs1, rs2, offset:
rs2 == 'zero_reg'
and is3BitReg(rs1) \
and isIntN(int(offset), 9)
and (int(offset) & 0x1) == 0, 'c.'+instr), )
for instr in ['and', 'or', 'xor', 'sub', 'andw', 'subw']:
instr2constraint[instr] = ((lambda rd, rs1, rs2:
rd == rs1 \
and is3BitReg(rd) \
and is3BitReg(rs2), 'c.'+instr), )
for instr in ['andi']:
instr2constraint[instr] = ((lambda rd, rs, imm: rd == rs \
and is3BitReg(rd) \
and isIntN(int(imm, 16), 6), 'c.'+instr), )
for instr in ['li']:
instr2constraint[instr] = ((lambda rd, imm: isIntN(int(imm), 6), 'c.'+instr), )
for instr in ['lui']:
instr2constraint[instr] = ((lambda rd, imm:
(rd != 'zero_reg' and rd != 'sp')
and isUIntN(int(imm, 16), 6), 'c.'+instr), )
for instr in ['slli']:
instr2constraint[instr] = ((lambda rd, rs, shamt:
rd == rs
and isUIntN(int(shamt), 6), 'c.'+instr), )
for instr in ['srli', 'srai']:
instr2constraint[instr] = ((lambda rd, rs, shamt:
rd == rs
and is3BitReg(rd)
and isUIntN(int(shamt), 6), 'c.'+instr), )
for instr in ['add']:
instr2constraint[instr] = ((lambda rd, rs1, rs2: rd == rs1, 'c.'+instr), )
for instr in ['addi']:
instr2constraint[instr] = ( (lambda rd, rs, imm:
# C.ADDI
rd == rs and isIntN(int(imm), 6), 'c.addi'),
(lambda rd, rs, imm:
# C.ADDI16SP
rd == rs and rd == 'sp'
and isIntN(int(imm), 10)
and (int(imm) & 0xF == 0), 'c.addi16sp'),
(lambda rd, rs, imm:
# C.ADDI4SPN
is3BitReg(rd) and rs == 'sp'
and isUIntN(int(imm), 10)
and (int(imm) & 0x3) == 0, 'c.addi4spn'))
for instr in ['addiw']:
instr2constraint[instr] = ((lambda rd, rs, imm: rd == rs
and isIntN(int(imm), 6), 'c.'+instr), )
for instr in ['sext.w']:
instr2constraint[instr] = ((lambda rd, rs: rd == rs, 'c.addiw'), )

class Instruction:

def __init__(self, line, pc, insnHex, insn, operands, offset):
Expand All @@ -31,84 +115,16 @@ def __init__(self, line, pc, insnHex, insn, operands, offset):
def __repr__(self):
return f"{self.pc:x} {self.insnHex:08x} {self.insn} {','.join(self.operands)}"

def __is3BitReg(self, reg):
return bool(re.match(r'^f?(s[01]|a[0-5])$', reg))

def __checkConstraint(self, fn):
return fn(*self.operands)

def isConvertible(self):
if self.insn in ['nop', 'ebreak', 'mv']:
return True
if self.insn in ['lw', 'flw', 'sw', 'fsw']:
return self.__checkConstraint(lambda rd, offset, rs:
rs == 'sp'
and isUIntN(int(offset), 8)
and (int(offset) & 0x3) == 0)
if self.insn in ['ld', 'fld', 'sd', 'fsd']:
return self.__checkConstraint(lambda rd, offset, rs:
rs == 'sp'
and isUIntN(int(offset), 9)
and (int(offset) & 0x7) == 0)
if self.insn in ['jalr', 'jr']:
return len(self.operands) == 1
if self.insn in ['jal', 'j']:
return len(self.operands) == 1 \
and self.__checkConstraint(lambda offset:
isUIntN(int(offset), 12)
and (int(offset) & 0x1) == 0)
if self.insn in ['beq', 'bne']:
return self.__checkConstraint(lambda rs1, rs2, offset:
rs2 == 'zero_reg'
and self.__is3BitReg(rs1) \
and isIntN(int(offset), 9)
and (int(offset) & 0x1) == 0)
if self.insn in ['and', 'or', 'xor', 'sub', 'andw', 'subw']:
return self.__checkConstraint(lambda rd, rs1, rs2:
rd == rs1 \
and self.__is3BitReg(rd) \
and self.__is3BitReg(rs2))
if self.insn in ['andi']:
return self.__checkConstraint(lambda rd, rs, imm: rd == rs \
and self.__is3BitReg(rd) \
and isIntN(int(imm, 16), 6))
if self.insn in ['li']:
return self.__checkConstraint(lambda rd, imm: isIntN(int(imm), 6))
if self.insn in ['lui']:
return self.__checkConstraint(lambda rd, imm:
(rd != 'zero_reg' or rd != 'sp')
and isUIntN(int(imm, 16), 6))
if self.insn in ['slli']:
return self.__checkConstraint(lambda rd, rs, shamt:
rd == rs
and isUIntN(int(shamt), 6))
if self.insn in ['srli', 'srai']:
return self.__checkConstraint(lambda rd, rs, shamt:
rd == rs
and self.__is3BitReg(rd)
and isUIntN(int(shamt), 6))
if self.insn in ['add']:
return self.__checkConstraint(lambda rd, rs1, rs2: rd == rs1)
if self.insn in ['addi']:
return self.__checkConstraint(lambda rd, rs, imm:
# C.ADDI
(rd == rs and isIntN(int(imm), 6))
# C.ADDI16SP
or (rd == rs and rd == 'sp'
and isIntN(int(imm), 10)
and (int(imm) & 0xF == 0))
# C.ADDI4SPN
or (self.__is3BitReg(rd)
and rs == 'sp'
and isUIntN(int(imm), 10)
and (int(imm) & 0x3) == 0))
if self.insn in ['addiw']:
return self.__checkConstraint(lambda rd, rs, imm: rd == rs
and isIntN(int(imm), 6))
if self.insn in ['sext.w']:
return self.__checkConstraint(lambda rd, rs: rd == rs)

return False
def compressTo(self):
if self.insn in instr2constraint:
cons = instr2constraint[self.insn]
for fn, cInstr in cons:
if self.__checkConstraint(fn):
return cInstr
return ''

def insnSize(self):
return 32 if self.insnHex & 0x3 == 0x3 else 16
Expand Down Expand Up @@ -194,9 +210,11 @@ def printTable(lst):
if insn is not None and not insn.isShort():
rawCounter[insn.insn] += 1
try:
if insn.isConvertible():
cInstr = insn.compressTo()
if cInstr:
if args.verbose:
print(line, end = '')
print(' ====> ', cInstr)
convertibleCounter[insn.insn] += 1
except BaseException:
print("Error Line: ", line, end = '')
Expand Down