Skip to content

Commit

Permalink
Do an optimization pass based on profiling from hprof
Browse files Browse the repository at this point in the history
Mainly involved speeding up Binary.stringToInt

Also removed the access to RunSpeedPanel if there isn't a GUI.

On my system this improves the time taken for the testsuite from 1.7s to 1.0s.
With a hello world taking 0.1s and with initialization for rars 0.6s.
  • Loading branch information
TheThirdOne committed Apr 8, 2019
1 parent 8adf7d9 commit 40bd684
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 102 deletions.
63 changes: 14 additions & 49 deletions rars/assembler/TokenTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,45 +128,8 @@ public static TokenTypes matchTokenType(String value) {

int i = Binary.stringToInt(value); // KENV 1/6/05

/* **************************************************************************
* MODIFICATION AND COMMENT, DPS 3-July-2008
*
* The modifications of January 2005 documented below are being rescinded.
* All hexadecimal immediate values are considered 32 bits in length and
* their classification as INTEGER_5, INTEGER_16, INTEGER_16U (new)
* or INTEGER_32 depends on their 32 bit value. So 0xFFFF will be
* equivalent to 0x0000FFFF instead of 0xFFFFFFFF. This change, along with
* the introduction of INTEGER_16U (adopted from Greg Gibeling of Berkeley),
* required extensive changes to instruction templates especially for
* pseudo-instructions.
*
* This modification also appears inbuildBasicStatementFromBasicInstruction()
* in rars.ProgramStatement.
*
* ///// Begin modification 1/4/05 KENV ///////////////////////////////////////////
* // We have decided to interpret non-signed (no + or -) 16-bit hexadecimal immediate
* // operands as signed values in the range -32768 to 32767. So 0xffff will represent
* // -1, not 65535 (bit 15 as sign bit), 0x8000 will represent -32768 not 32768.
* // NOTE: 32-bit hexadecimal immediate operands whose values fall into this range
* // will be likewise affected, but they are used only in pseudo-instructions. The
* // code in ExtendedInstruction.java to split this number into upper 16 bits for "lui"
* // and lower 16 bits for "ori" works with the original source code token, so it is
* // not affected by this tweak. 32-bit immediates in data segment directives
* // are also processed elsewhere so are not affected either.
* ////////////////////////////////////////////////////////////////////////////////
*
* if ( Binary.isHex(value) &&
* (i >= 32768) &&
* (i <= 65535) ) // Range 0x8000 ... 0xffff
* {
* // Subtract the 0xffff bias, because strings in the
* // range "0x8000" ... "0xffff" are used to represent
* // 16-bit negative numbers, not positive numbers.
* i = i - 65536;
* }
* // ------------- END KENV 1/4/05 MODIFICATIONS --------------
*
* ************************* END DPS 3-July-2008 COMMENTS *******************************/
// Comments from 2008 and 2005 were removed - Benjamin Landers 2019

// shift operands must be in range 0-31
if (i >= 0 && i <= 31) {
return TokenTypes.INTEGER_5;
Expand All @@ -184,18 +147,16 @@ public static TokenTypes matchTokenType(String value) {

// See if it is a real (fixed or floating point) number. Note that parseDouble()
// accepts integer values but if it were an integer literal we wouldn't get this far.
if (value.equals("Inf"))
return TokenTypes.REAL_NUMBER;
try {
Double.parseDouble(value);
return TokenTypes.REAL_NUMBER;
} catch (NumberFormatException e) {
// NO ACTION -- exception suppressed
if (value.equals("Inf") || value.equals("NaN")) return TokenTypes.REAL_NUMBER;
if(('0' <= value.charAt(0) && value.charAt(0) <= '9') || value.charAt(0) == '.' || value.charAt(0) == '-'){
try {
Double.parseDouble(value);
return TokenTypes.REAL_NUMBER;
} catch (NumberFormatException e) {
// NO ACTION -- exception suppressed
}
}

// See if it is an instruction operator
if (Globals.instructionSet.matchOperator(value) != null)
return TokenTypes.OPERATOR;

// See if it is a directive
if (value.charAt(0) == '.' && Directives.matchDirective(value) != null) {
Expand All @@ -206,6 +167,10 @@ public static TokenTypes matchTokenType(String value) {
if (value.charAt(0) == '"')
return TokenTypes.QUOTED_STRING;

// See if it is an instruction operator
if (Globals.instructionSet.matchOperator(value) != null)
return TokenTypes.OPERATOR;

// Test for identifier goes last because I have defined tokens for various
// MIPS constructs (such as operators and directives) that also could fit
// the lexical specifications of an identifier, and those need to be
Expand Down
14 changes: 9 additions & 5 deletions rars/riscv/hardware/RegisterBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ public Register getRegister(int num) {
* @return The register object,or null if not found.
**/
public Register getRegister(String name) {
if(name.length() < 2) return null;

// Handle a direct name
for (Register r : regFile) {
if (r.getName().equals(name)) {
Expand All @@ -131,12 +133,14 @@ public Register getRegister(String name) {
}
// Handle prefix case
if (name.charAt(0) == prefix) {
try {
return getRegister(Binary.stringToInt(name.substring(1))); // KENV 1/6/05
} catch (Exception e) {
// handles both NumberFormat
return null;
if(name.charAt(1) == 0) { // Ensure that it is a normal decimal number
if(name.length() > 2) return null;
return getRegister(0);
}

Integer num = Binary.stringToIntFast(name.substring(1));
if(num == null) return null;
return getRegister(num);
}
return null;
}
Expand Down
6 changes: 4 additions & 2 deletions rars/simulator/Simulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,17 @@ public synchronized void setStop(Reason reason) {

private void startExecution() {
Simulator.getInstance().notifyObserversOfExecution(new SimulatorNotice(SimulatorNotice.SIMULATOR_START,
maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), pc, null, pe, done));
maxSteps,(Globals.getGui() != null || Globals.runSpeedPanelExists)?RunSpeedPanel.getInstance().getRunSpeed():RunSpeedPanel.UNLIMITED_SPEED,
pc, null, pe, done));
}

private void stopExecution(boolean done, Reason reason) {
this.done = done;
this.constructReturnReason = reason;
if (done) SystemIO.resetFiles(); // close any files opened in the process of simulating
Simulator.getInstance().notifyObserversOfExecution(new SimulatorNotice(SimulatorNotice.SIMULATOR_STOP,
maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), pc, reason, pe, done));
maxSteps, (Globals.getGui() != null || Globals.runSpeedPanelExists)?RunSpeedPanel.getInstance().getRunSpeed():RunSpeedPanel.UNLIMITED_SPEED,
pc, reason, pe, done));
}

private synchronized void interrupt() {
Expand Down
96 changes: 50 additions & 46 deletions rars/util/Binary.java
Original file line number Diff line number Diff line change
Expand Up @@ -372,62 +372,66 @@ public static String intToAscii(int d) {
* @return returns int value represented by given string
* @throws NumberFormatException if string cannot be translated into an int
*/

public static int stringToInt(String s) throws NumberFormatException {
String work = new String(s);
// Profiling showed that the old method here using Integer.decode was slow
// stringToIntFast should be input by input compatible
Integer res2 = stringToIntFast(s);
if(res2 == null) throw new NumberFormatException();
return res2;
}

public static Integer stringToIntFast(String s){
if(s.length() == 0) return null;
char first = s.charAt(0);
if(!(('0' <= first && first <= '9') || first == '-')) return null;
int result = 0;
// First, use Integer.decode(). This will validate most, but it flags
// valid hex two's complement values as exceptions. We'll catch those and
// do our own validation.
try {
result = Integer.decode(s);
} catch (NumberFormatException nfe) {
// Multistep process toward validation of hex two's complement. 3-step test:
// (1) exactly 10 characters long,
// (2) starts with Ox or 0X,
// (3) last 8 characters are valid hex digits.
work = work.toLowerCase();
if (work.length() == 10 && work.startsWith("0x")) {
String bitString = "";
int index;
// while testing characters, build bit string to set up for binaryStringToInt
for (int i = 2; i < 10; i++) {
index = Arrays.binarySearch(chars, work.charAt(i));
if (index < 0) {
throw new NumberFormatException();
}
bitString = bitString + intToBinaryString(index, 4);
// Not doing s = s.lowercase() because it is slightly slower
if(s.length() > 2 && first == '0' && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) { // Hex case
if(s.length() > 10) return null; // This must overflow or contain invalid characters
for(int i = 2; i < s.length(); i++) {
char c = s.charAt(i);
result *= 16;
if ('0' <= c && c <= '9') {
result += c - '0';
} else if ('a' <= c && c <= 'f') {
result += c - 'a' + 10;
} else if ('A' <= c && c <= 'F') {
result += c - 'A' + 10;
} else {
return null;
}
result = binaryStringToInt(bitString);
}
/* The following "else" composed by Jose Baiocchi Paredes, Oct 2009. This new code
will correctly translate a string representing an unsigned decimal (not hex)
value whose signed value is negative. This is the decimal equivalent of the
"then" case just above. The method was not used in this context until Release 3.6
when background highlighting of the Data Segment was added. Caused exceptions
under certain conditions.
*/
else if (!work.startsWith("0x")) {
result = 0;
for (int i = 0; i < work.length(); i++) {
char c = work.charAt(i);
if ('0' <= c && c <= '9') {
result *= 10;
result += c - '0';
} else {
throw new NumberFormatException();
}
}else if (first == '0'){ // Octal case
for(int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if ('0' <= c && c <= '7') {
result *= 8;
result += c - '0';
} else {
return null;
}
}
/* End of the Jose Paredes code */
else {
throw new NumberFormatException();
if(result < 0)return null;
} else {
int i = 0;
if(first == '-') i=1;
for(; i < s.length(); i++){
char c = s.charAt(i);
if ('0' <= c && c <= '9') {
result *= 10;
result += c - '0';
} else {
return null;
}
}
// Overflowing to min and negating keeps the value at min
if(result == Integer.MIN_VALUE && first == '-') return Integer.MIN_VALUE;
// Don't allow overflow and negation as that produces unexpected values.
if(result < 0 && first == '-') return null;
if(first == '-') result*=-1;
}
return result;
}


/**
* Attempt to validate given string whose characters represent a 64 bit long.
* Long.decode() is insufficient because it will not allow incorporation of
Expand Down

0 comments on commit 40bd684

Please sign in to comment.