Skip to content

Commit

Permalink
RISC-V: implement overflowchk evaluator for some operation / operan…
Browse files Browse the repository at this point in the history
…d sizes
  • Loading branch information
janvrany authored and shingarov committed Nov 2, 2023
1 parent 4d46e2e commit 8b07582
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 3 deletions.
64 changes: 61 additions & 3 deletions src/Tinyrossa-RISCV/TRRV64GCodeEvaluator.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ TRRV64GCodeEvaluator >> evaluate_Xloadi: node [
"FIXME: we can do better by checking for loads in form
Xloadi
aXadd
...
Xconst offset
aXadd
...
Xconst offset
and check if offset fits into displacement immediate and if
so, generate
Expand Down Expand Up @@ -484,6 +484,64 @@ TRRV64GCodeEvaluator >> evaluate_lsub: node [
^self emitBin: node opcodeR: 'sub' opcodeI: 'addi'
]

{ #category : #evaluation }
TRRV64GCodeEvaluator >> evaluate_overflowchk: node [
| operationNode src1Reg src2Reg |

self assert: node child1 opcode mayOverflow.
self assert: node child1 child1 == node child2.
self assert: node child1 child2 == node child3.

operationNode := node child1.
src1Reg := self evaluate: operationNode child1.
src2Reg := self evaluate: operationNode child2.

operationNode opcode isAdd ifTrue: [
operationNode type == Int32 ifTrue: [
| dstReg tmpReg |

dstReg := self evaluate: operationNode.
tmpReg := self codegen allocateRegister.

generate
add: tmpReg, src1Reg, src2Reg;
bne: dstReg, tmpReg, node symbol.

^ nil.
].
].
operationNode opcode isMul ifTrue: [
operationNode type == Int32 ifTrue: [
| dstReg tmpReg |

dstReg := self evaluate: operationNode.
tmpReg := self codegen allocateRegister.

generate
mul: tmpReg, src1Reg, src2Reg;
bne: dstReg, tmpReg, node symbol.

^ nil.
].
operationNode type == Int64 ifTrue: [
| dstReg tmp1Reg tmp2Reg |

dstReg := self evaluate: operationNode.
tmp1Reg := self codegen allocateRegister.
tmp2Reg := self codegen allocateRegister.

generate
mulh: tmp1Reg, src1Reg, src2Reg;
srai: tmp2Reg, dstReg, 63;
bne: tmp1Reg, tmp2Reg, node symbol.

^ nil
]

].
self error: 'Operation or type not yet supported'
]

{ #category : #evaluation }
TRRV64GCodeEvaluator >> evaluate_sconst: node [
^ self evaluate_iconst: node
Expand Down
45 changes: 45 additions & 0 deletions src/Tinyrossa-Tests-POWER/TRPPC64CompilationTests.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,48 @@ TRPPC64CompilationTests >> test_example09_signum_2 [
debugger c.
self assert: (debugger getRegister: 'r4') equals: 0.
]

{ #category : #'tests - examples' }
TRPPC64CompilationTests >> test_example15_add_with_overflow_check [
| debugger |

(TRPPC64CodeEvaluator methodDictionary at: #evaluate_overflowchk: ifAbsent:[nil]) isNil ifTrue: [
self skip: 'Skipped since #evaluate_overflowchk: is not implemented for POWER'
].

TRCompilationExamples new
compilation: compilation;
example15_add_with_overflow_check.

debugger := shell debugger.
debugger memoryAt: shell nzone put: compilation codeBuffer bytes.
debugger setRegister: 'r4' to: 0x7FFFFFFE.
debugger setRegister: 'r5' to: 2.
debugger c.
self assert: (debugger getRegister: 'gr4') equals: 0.
]

{ #category : #'tests - examples' }
TRPPC64CompilationTests >> test_example16_factorial_i_with_overflow [
| debugger |

(TRPPC64CodeEvaluator methodDictionary at: #evaluate_overflowchk: ifAbsent:[nil]) isNil ifTrue: [
self skip: 'Skipped since #evaluate_overflowchk: is not implemented for POWER'
].

TRCompilationExamples new
compilation: compilation;
example16_factorial_i_with_overflow.

debugger := shell debugger.
debugger memoryAt: shell nzone put: compilation codeBuffer bytes.
debugger setRegister: 'r4' to: 13.
debugger c.
self assert: (debugger getRegister: 'r4') equals: -1.


"
13 factorial > 0x7FFFFFFF
22 factorial > 0x7FFFFFFFFFFFFFFF
"
]
37 changes: 37 additions & 0 deletions src/Tinyrossa-Tests-RISCV/TRRV64GCompilationTests.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,40 @@ TRRV64GCompilationTests >> test_example09_signum_2 [
debugger c.
self assert: (debugger getRegister: 'a0') equals: -1.
]

{ #category : #'tests - examples' }
TRRV64GCompilationTests >> test_example15_add_with_overflow_check [
| debugger |

TRCompilationExamples new
compilation: compilation;
example15_add_with_overflow_check.

debugger := shell debugger.
debugger memoryAt: shell nzone put: compilation codeBuffer bytes.
debugger setRegister: 'a0' to: 16r7FFFFFFE.
debugger setRegister: 'a1' to: 2.
debugger c.
self assert: (debugger getRegister: 'a0') equals: 0.
]

{ #category : #'tests - examples' }
TRRV64GCompilationTests >> test_example16_factorial_i_with_overflow [
| debugger |

TRCompilationExamples new
compilation: compilation;
example16_factorial_i_with_overflow.

debugger := shell debugger.
debugger memoryAt: shell nzone put: compilation codeBuffer bytes.
debugger setRegister: 'a0' to: 13.
debugger c.
self assert: (debugger getRegister: 'a0') equals: -1.


"
13 factorial > 0x7FFFFFFF
22 factorial > 0x7FFFFFFFFFFFFFFF
"
]
86 changes: 86 additions & 0 deletions src/Tinyrossa/TRCompilationExamples.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,92 @@ TRCompilationExamples >> example13_indirect_call [
compilation codeBuffer. "Only convenience inspection."
]

{ #category : #examples }
TRCompilationExamples >> example15_add_with_overflow_check [
| builder handler add |

"Define function add_with_overflow which adds two integers
(`a` and `b`) and returns its sum or zero, of addition overflows."

builder := compilation builder.
builder defineName: 'add_with_overflow_check' type: Int32.
builder defineParameter: 'a' type: Int32.
builder defineParameter: 'b' type: Int32.
builder defineAutomatic: 't' type: Int32.

"First, define overflow handler:"
handler := builder orphan.
handler ireturn: { handler iconst: 0 }.

"Now, build the main body"
add := builder iadd: { builder iload:'a' . builder iload: 'b' }.
builder overflowchk: { add . add child1 . add child2 . handler }.
builder ireturn: { add }.


compilation optimize.

compilation compile.

compilation codeBuffer. "Only convenience inspection."
]

{ #category : #examples }
TRCompilationExamples >> example16_factorial_i_with_overflow [
"Like #example04_factorial_i but return -1 on overflow"

| builder handler |

builder := compilation builder.
builder defineName: 'factorial_i' type: Int32.
builder defineParameter: 'x' type: Int32.
builder defineAutomatic: 'r' type: Int32.

"
def factorial_i(x):
r = 1
while x > 0:
r = r * x
x = x - 1
return r
"

handler := builder orphan.

builder
"r = 1"
istore: {
builder iconst: 1 .
'r' };

"while x > 0:"
while: (builder icmpgt: { builder iload: 'x' . builder iconst: 0 }) do: [:builder |
| rMx |

"r = r * x on overflow go to handler"

rMx := (builder imul: { builder iload: 'r' . builder iload: 'x' }).
builder overflowchk: { rMx . rMx child1 . rMx child2 . "on overflow go to" handler }.
builder istore: {
rMx .
'r' }.
"x = x - 1"
builder istore: {
(builder isub: { builder iload: 'x' . builder iconst: 1 }) .
'x' }
];
"return r"
ireturn: { builder iload: 'r' }.

handler ireturn: { handler iconst: -1 }.

compilation optimize.

compilation compile.

compilation codeBuffer. "Only convenience inspection."
]

{ #category : #examples }
TRCompilationExamples >> example17_call_external_function_in_aot_mode [
| builder |
Expand Down

0 comments on commit 8b07582

Please sign in to comment.