From e0d782e3a3434e18c4169c79be9ddabd0f3df89a Mon Sep 17 00:00:00 2001 From: Jan Vrany Date: Mon, 27 Nov 2023 11:56:44 +0000 Subject: [PATCH] Remove (old) linear scan and (even older) naive constraint solving register allocators This commit removes `TRLinearScanRegisterAllocator` and `TRNaiveConstraintSolvingRegisterAllocator` register allocators. The main reason is that commit "Let the register allocator to handle (virtual) register dependencies" moves the responsibility to move values to argument registers and from return register(s) to register allocator based on register dependencies. Neither `TRLinearScanRegisterAllocator` and `TRNaiveConstraintSolvingRegisterAllocator` can be easily updated to work with this change, so this commit removes them. --- .../TRLinearScanRegisterAllocator.class.st | 126 ------------------ ...onstraintSolvingRegisterAllocator.class.st | 59 -------- 2 files changed, 185 deletions(-) delete mode 100644 src/Tinyrossa/TRLinearScanRegisterAllocator.class.st delete mode 100644 src/Tinyrossa/TRNaiveConstraintSolvingRegisterAllocator.class.st diff --git a/src/Tinyrossa/TRLinearScanRegisterAllocator.class.st b/src/Tinyrossa/TRLinearScanRegisterAllocator.class.st deleted file mode 100644 index 4a4d8a4..0000000 --- a/src/Tinyrossa/TRLinearScanRegisterAllocator.class.st +++ /dev/null @@ -1,126 +0,0 @@ -" -`TRLinearScanRegisterAllocator` is the old register allocator superseded by -`TRReverseLinearScanRegisterAllocator`. - -It's straightforward reimplementation from original 1999 paper [1] Note that -there's no need to deal with virtual registers being used across -basic block boundary - in Tinyrossa (as well as in Testarossa), the only way -to transfer value from one (extended) block to another is via `?store` and -`?load` IL operations. - -[1]: MASSIMILIANO POLETTO and VIVEK SARKAR: Linear Scan Register Allocation - http://web.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf - -" -Class { - #name : #TRLinearScanRegisterAllocator, - #superclass : #TRRegisterAllocator, - #instVars : [ - 'liveRanges', - 'activeRanges', - 'allocatableRegisters', - 'availableRegisters' - ], - #category : #'Tinyrossa-Codegen-Register Allocation' -} - -{ #category : #allocation } -TRLinearScanRegisterAllocator >> allocateRegisterFor: aTRVirtualRegister [ - self assert: aTRVirtualRegister allocation isNil. - - allocatableRegisters do: [:rReg | - (availableRegisters includes: rReg) ifTrue: [ - aTRVirtualRegister allocation: rReg. - availableRegisters remove: rReg. - ^ self. - ]. - ]. - self error: 'Should not happen!'. -] - -{ #category : #allocation } -TRLinearScanRegisterAllocator >> allocateRegisters [ - | insns | - - insns := codegen instructions. - allocatableRegisters := codegen linkage allocatableRegisters. - availableRegisters := allocatableRegisters asSet. - activeRanges := SortedCollection sortBlock: [ :a :b | a stop < b stop ]. - - "Step 1 - compute live intervals." - liveRanges := Dictionary new. - codegen virtualRegisters do: [:vReg | - liveRanges at: vReg put: (TRRegisterLiveInterval forRegister: vReg). - ]. - 1 to: insns size do: [:i | - | insn | - - insn := insns at: i. - codegen virtualRegistersUsedBy: insn do: [:vreg | - | liveRange | - - liveRange := liveRanges at: vreg. - liveRange used: i. - ]. - ]. - - " - Step 2. Allocate registers using collected intervals. - " - liveRanges := liveRanges associations sort: [ :a :b | a start < b start ]. - liveRanges do: [:liveRange | - self assert: liveRange start odd. - self assert: liveRange stop even. - self assert: liveRange start < liveRange stop. - - self expireOldIntervals: liveRange. - availableRegisters isEmpty ifTrue: [ - self error: 'Spilling not supported yet!' - ] ifFalse: [ - self allocateRegisterFor: liveRange. - activeRanges add: liveRange - ]. - ]. - - " - Step 3. Insert register moves to satisfy register dependencies - " - insns size downTo: 1 do: [:i | - | insn deps | - - insn := insns at: i. - deps := insn dependencies. - - deps notEmptyOrNil ifTrue: [ - codegen cursor: i. - deps post do: [:dep | - dep isDependency ifTrue:[ - self insertMoveFrom: dep rreg to: dep vreg. - ]. - ]. - - codegen cursor: i - 1. - deps pre do: [:dep | - dep isDependency ifTrue:[ - self insertMoveFrom: dep vreg to: dep rreg. - ]. - - ]. - ]. - ]. -] - -{ #category : #allocation } -TRLinearScanRegisterAllocator >> expireOldIntervals: newRange [ - self expireOldIntervalsAt: newRange start -] - -{ #category : #allocation } -TRLinearScanRegisterAllocator >> expireOldIntervalsAt: i [ - [ activeRanges notEmpty and:[ activeRanges first stop <= i ] ] whileTrue: [ - | expiredRange | - - expiredRange := activeRanges removeFirst. - availableRegisters add: expiredRange allocation - ]. -] diff --git a/src/Tinyrossa/TRNaiveConstraintSolvingRegisterAllocator.class.st b/src/Tinyrossa/TRNaiveConstraintSolvingRegisterAllocator.class.st deleted file mode 100644 index 4fefa49..0000000 --- a/src/Tinyrossa/TRNaiveConstraintSolvingRegisterAllocator.class.st +++ /dev/null @@ -1,59 +0,0 @@ -Class { - #name : #TRNaiveConstraintSolvingRegisterAllocator, - #superclass : #TRRegisterAllocator, - #category : #'Tinyrossa-Codegen-Register Allocation' -} - -{ #category : #allocation } -TRNaiveConstraintSolvingRegisterAllocator >> allocateRegisters [ - " - Following code is bogus, it does not really work. - Cannot handle running out of registers. Cannot spill. - Does not handle register liveness. Essentially it does - work only for very simple cases. - But hey, it does simulate register allocation and - it took mi literraly 5 mins to write it :-) - " - - | realRegisters insns solver | - - insns := codegen instructions. - realRegisters := codegen linkage allocatableRegisters. - solver := Z3Solver new. - - " - First, make sure each virtual register gets mapped to - some real, allocatable register. - " - codegen virtualRegisters do: [:vReg | - solver assert: (Bool or: (realRegisters collect: [ :rReg | vReg toInt eq: rReg toInt ])). - ]. - - " - Third, make sure that mapping has no conflicts. - Following code is absolutely bogus as it does not - take liveness into an account, but will do for now. - " - insns do: [:insn | - | used | - - used := codegen virtualRegistersUsedBy: insn. - used do: [:usedReg1 | used do: [:usedReg2 | - usedReg1 ~~ usedReg2 ifTrue: [ - solver assert: (usedReg1 toInt eq: usedReg2 toInt) not - ]. - ]]. - ]. - - solver check ifFalse: [ - self error: 'I give up, you''d better ask mr Chaitin help you here!' - ]. - - solver getModel constants keysAndValuesDo: [:vRegName :rRegValue | - | vReg rReg | - - vReg := codegen virtualRegisters at: vRegName. - rReg := realRegisters detect: [:each | each value = rRegValue value ]. - vReg allocation: rReg. - ]. -]