Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2623.mcz ==================== Summary ==================== Name: VMMaker.oscog-eem.2623 Author: eem Time: 20 December 2019, 7:36:17.393248 pm UUID: aa831407-e9c0-4df9-9d8c-57ee755c1440 Ancestors: VMMaker.oscog-eem.2622 Cogit: Now that a processor is allowed to refuse to do CmpR: SPReg R: ?Reg, rewrite genGetActiveContextLarge:inBlock: to do its SPReg comparison the other way around. Fix a bug in an assert now that method alignment can be > 8. AbstractInstructionTests: Refactor common code into convenience methods. Implement runSubRR:on:. Two down. Quite a few to go. =============== Diff against VMMaker.oscog-eem.2622 =============== Item was added: + ----- Method: AbstractInstructionTests>>assertValidRunResult:ofAtLeast: (in category 'private') ----- + assertValidRunResult: result "{ numSubTests. numPassingSubTests }" ofAtLeast: minimumExpectedNumberOfSubTests + self assert: result isArray. + self assert: result size >= 2. + self assert: (result first isInteger and: [result second isInteger]). + self assert: result first >= minimumExpectedNumberOfSubTests. + self assert: result first = result second "All sub-tests pass"! Item was added: + ----- Method: AbstractInstructionTests>>cogitForTests (in category 'accessing') ----- + cogitForTests + "Answer a new CogitForTests, with initialization performed for the current ISA." + VMClass initializationOptions at: #ISA put: self isaName. + ^CogitForTests new! Item was added: + ----- Method: AbstractInstructionTests>>defaultCodeStart (in category 'private') ----- + defaultCodeStart + ^1024! Item was added: + ----- Method: AbstractInstructionTests>>generatedCodeFrom: (in category 'private') ----- + generatedCodeFrom: aCogit + | instructions memory | + instructions := aCogit generatedMachineCodeAt: self defaultCodeStart. "Avoid any guard page effects in the simulators, i.e. Gdb's ARM32 requires pc >= 16" + "self processor disassembleFrom: 1024 to: instructions size - 1 in: instructions" + (memory := ByteArray new: self defaultCodeStart + 1024) replaceFrom: 1 to: instructions size with: instructions startingAt: 1. + aCogit stopsFrom: instructions size to: memory size - 1 in: memory. + ^memory! Item was changed: ----- Method: AbstractInstructionTests>>runCmpRRJumpCond:on: (in category 'running') ----- runCmpRRJumpCond: assertPrintBar on: aStream + "Compile and evaluate as many combinations of CmpR:R: JumpCond: as possible, checking that they produce the - "Compile and evaluate as many combinations of CmpR;R: JumpCond: as possible, checking that they produce the expected result. Answer an array of the number of comparisons and the number of them that succeeded." "self defaultTester runCmpRRJumpCond: false" | cogit nTests nGood | + cogit := self cogitForTests. - VMClass initializationOptions at: #ISA put: self isaName. - cogit := CogitForTests new. nTests := nGood := 0. self concreteCompilerClass dataRegistersWithAccessorsGiven: self processor do: [:sreg :srgetter :srsetter| self concreteCompilerClass dataRegistersWithAccessorsGiven: self processor do: [:dreg :drgetter :drsetter| (sreg ~= dreg "N.B. We do not expect the backEnd to provide CmpR: SPReg R: reg, only CmpR: reg R: SPReg" and: [drgetter ~= #sp]) ifTrue: [#( = ~= > > >= >= < < <= <=) with: #(JumpZero: JumpNonZero: JumpGreater: JumpAbove: JumpGreaterOrEqual: JumpAboveOrEqual: JumpLess: JumpBelow: JumpLessOrEqual: JumpBelowOrEqual:) + do: [:comparison :instruction| | unsigned jmp memory | - do: [:comparison :instruction| | unsigned jmp instructions memory | unsigned := (instruction includesSubstring: 'Above') or: [instruction includesSubstring: 'Below']. "(drgetter = #sp or: [srgetter = #sp]) ifTrue: [self halt]." cogit resetGen. cogit CmpR: dreg R: sreg. jmp := cogit perform: instruction with: 0. cogit MoveCq: 0 R: cogit backEnd cResultRegister; Jump: 1536. jmp jmpTarget: (cogit MoveCq: 1 R: cogit backEnd cResultRegister). cogit Jump: 1536. + memory := self generatedCodeFrom: cogit. + "self processor disassembleFrom: 1024 to: cogit codeSize - 1024 * 2 + 1024 in: memory ''" + self pairs: { -1 << 30. "-1 << 16." -1 << 8. 0. 1 << 8. "1 << 16." 1 << 30 } do: - instructions := cogit generatedMachineCodeAt: 1024. "Avoid any guard page effects in the simulators, i.e. Gdb's ARM32 requires pc >= 16" - "self processor disassembleFrom: 1024 to: instructions size - 1 in: instructions" - (memory := ByteArray new: 2048) replaceFrom: 1 to: instructions size with: instructions startingAt: 1. - cogit stopsFrom: instructions size to: memory size - 1 in: memory. - "self processor disassembleFrom: 1024 to: instructions size - 1024 * 2 + 1024 in: memory ''" - self pairs: { "-1 << 30. -1 << 16." -1 << 8. 0. 1 << 8. "1 << 16. 1 << 30" } do: [:a :b| | bogus error expected nInsts | nTests := nTests + 1. error := false. nInsts := 0. self processor reset; + pc: self defaultCodeStart; - pc: 1024; perform: srsetter with: (processor convertIntegerToInternal: a); perform: drsetter with: (processor convertIntegerToInternal: b). [[processor pc ~= 1536 and: [nInsts < 16]] whileTrue: [processor singleStepIn: memory. nInsts := nInsts + 1]] on: Error do: [:ex| error := true]. nInsts >= 16 ifTrue: [error := true]. + "self processor disassembleInstructionAt: 0 In: memory" - "self processor printRegistersOn: Transcript. - Transcript show: (self processor disassembleInstructionAt: 0 In: memory); cr" bogus := (processor pc = 1536 and: [#[0 1] includes: processor cResultRegister]) not. assertPrintBar ifTrue: [self deny: bogus]. expected := unsigned ifTrue: [(a bitAnd: 1 << 32 - 1) perform: comparison with: (b bitAnd: 1 << 32 - 1)] ifFalse: [a perform: comparison with: b]. (bogus or: [error or: [self processor cResultRegister = 1 ~= expected]]) ifFalse: [nGood := nGood + 1]. assertPrintBar ifTrue: [self assert: self processor cResultRegister = 1 equals: expected] ifFalse: [self processor cResultRegister = 1 ~= expected ifTrue: [aStream nextPutAll: srgetter; space; nextPutAll: comparison; space; nextPutAll: drgetter. unsigned ifTrue: [aStream nextPutAll: ' (unsigned)']. aStream nextPutAll: (error ifTrue: [' ERRORED'] ifFalse: [' is incorrect']); cr; flush. bogus ifTrue: [self processor printRegistersOn: aStream. aStream nextPutAll: (self processor disassembleInstructionAt: 0 In: memory); cr; flush]]]]]]]]. assertPrintBar ifFalse: [aStream print: nTests; nextPutAll: ' tests; '; print: nGood; nextPutAll: ' good'; cr]. ^{nTests. nGood}! Item was removed: - ----- Method: AbstractInstructionTests>>runSubRR: (in category 'running') ----- - runSubRR: assertPrintBar - "self defaultTester runSubRR: false" - self concreteCompilerClass dataRegistersWithAccessorsDo: - [:sreg :srgetter :srsetter| - self concreteCompilerClass dataRegistersWithAccessorsDo: - [:dreg :drgetter :drsetter| | inst len memory | - inst := self gen: SubRR operand: sreg operand: dreg. - len := inst concretizeAt: 0. - memory := self memoryAsBytes: inst machineCode. - self pairs: (-2 to: 2) do: - [:a :b| | bogus | - self processor - reset; - perform: srsetter with: (processor convertIntegerToInternal: a); - perform: drsetter with: (processor convertIntegerToInternal: b). - [[processor pc < len] whileTrue: - [self processor singleStepIn: memory]] - on: Error - do: [:ex| ]. - "self processor printRegistersOn: Transcript. - Transcript show: (self processor disassembleInstructionAt: 0 In: memory); cr" - assertPrintBar - ifTrue: [self assert: processor pc = inst machineCodeSize] - ifFalse: [bogus := processor pc ~= inst machineCodeSize]. - self concreteCompilerClass dataRegistersWithAccessorsDo: - [:ireg :getter :setter| | expected | - expected := drgetter == srgetter - ifTrue: [0] - ifFalse: - [getter == drgetter - ifTrue: [b - a] - ifFalse: [getter = srgetter - ifTrue: [a] - ifFalse: [0]]]. - assertPrintBar - ifTrue: [self assert: (self processor convertInternalToInteger: (self processor perform: getter)) equals: expected] - ifFalse: - [(self processor convertInternalToInteger: (self processor perform: getter)) ~= expected ifTrue: - [bogus := true]]]. - assertPrintBar ifFalse: - [Transcript - nextPutAll: drgetter; nextPut: $(; print: b; nextPutAll: ') - '; - nextPutAll: srgetter; nextPut: $(; print: a; nextPutAll: ') = '; - print: (self processor convertInternalToInteger: (self processor perform: drgetter)); cr; flush. - bogus ifTrue: - [self processor printRegistersOn: Transcript. - Transcript show: (self processor disassembleInstructionAt: 0 In: memory); cr]]]]]! Item was added: + ----- Method: AbstractInstructionTests>>runSubRR:on: (in category 'running') ----- + runSubRR: assertPrintBar on: aStream + "Compile and evaluate as many combinations of SubR:R: as possible, checking that they produce the + expected result. Answer an array of the number of comparisons and the number of them that succeeded." + "self defaultTester runSubRR: false" + | cogit nTests nGood | + cogit := self cogitForTests. + nTests := nGood := 0. + self concreteCompilerClass dataRegistersWithAccessorsGiven: self processor do: + [:sreg :srgetter :srsetter| + self concreteCompilerClass dataRegistersWithAccessorsGiven: self processor do: + [:dreg :drgetter :drsetter| | memory limit | + (drgetter == #sp "Some processors can't do this easily; i.e. ARMv8" + or: [drgetter == srgetter]) ifFalse: "Some processors refuse to do this; i.e. ARMv8" + [cogit resetGen. + cogit + SubR: sreg R: dreg; + Nop. + memory := self generatedCodeFrom: cogit. + limit := cogit codeSize. + self pairs: (-2 to: 2) do: + [:a :b| | bogus error nInsts allRegistersGood | + nTests := nTests + 1. + error := false. + nInsts := 0. + self processor + reset; + pc: self defaultCodeStart; + perform: srsetter with: (processor convertIntegerToInternal: a); + perform: drsetter with: (processor convertIntegerToInternal: b). + [[processor pc < limit and: [nInsts < 16]] whileTrue: + [processor singleStepIn: memory. nInsts := nInsts + 1]] + on: Error + do: [:ex| error := true]. + nInsts >= 16 ifTrue: [error := true]. + "self processor disassembleInstructionAt: self defaultCodeStart In: memory" + bogus := processor pc ~= limit. + assertPrintBar ifTrue: [self assert: processor pc = limit]. + allRegistersGood := (bogus or: [error]) not. + self concreteCompilerClass dataRegistersWithAccessorsGiven: self processor do: + [:ireg :getter :setter| | expected | + expected := drgetter == srgetter + ifTrue: [0] + ifFalse: + [getter == drgetter + ifTrue: [b - a] + ifFalse: [getter = srgetter + ifTrue: [a] + ifFalse: [0]]]. + assertPrintBar + ifTrue: [self assert: (self processor convertInternalToInteger: (self processor perform: getter)) equals: expected] + ifFalse: + [(self processor convertInternalToInteger: (self processor perform: getter)) ~= expected ifTrue: + [bogus := true]]. + (self processor convertInternalToInteger: (self processor perform: getter)) ~= expected ifTrue: [allRegistersGood := false]. + assertPrintBar ifFalse: + [aStream + nextPutAll: drgetter; nextPut: $(; print: b; nextPutAll: ') - '; + nextPutAll: srgetter; nextPut: $(; print: a; nextPutAll: ') = '; + print: (self processor convertInternalToInteger: (self processor perform: drgetter)); cr; flush]]. + allRegistersGood ifTrue: [nGood := nGood + 1]]]]]. + assertPrintBar ifFalse: + [aStream print: nTests; nextPutAll: ' tests; '; print: nGood; nextPutAll: ' good'; cr]. + ^{nTests. nGood}! Item was added: + ----- Method: AbstractInstructionTests>>testCogitForTests (in category 'tests') ----- + testCogitForTests + self assert: (self cogitForTests backEnd isKindOf: self concreteCompilerClass)! Item was added: + ----- Method: AbstractInstructionTests>>testRunCmpRR (in category 'tests') ----- + testRunCmpRR + "self defaultTester testRunSubRR" + | result | + result := self runCmpRRJumpCond: true on: NullStream new. + "Assume at least 5 registers. There are ten comparisons. and we compare 5 values" + self assertValidRunResult: result ofAtLeast: 5 squared * 10 * 5 squared! Item was changed: ----- Method: AbstractInstructionTests>>testRunSubRR (in category 'tests') ----- testRunSubRR "self defaultTester testRunSubRR" + | result | + result := self runSubRR: true on: NullStream new. + "Assume at least 5 registers. We subtract 5 pairs" + self assertValidRunResult: result ofAtLeast: 5 squared * 5 squared! - self runSubRR: true! Item was changed: ----- Method: CogObjectRepresentationForSpur>>genGetActiveContextLarge:inBlock: (in category 'initialization') ----- genGetActiveContextLarge: isLarge inBlock: isInBlock "Create a trampoline to answer the active context that will answer it if a frame is already married, and create it otherwise. Assume numArgs is in SendNumArgsReg and ClassReg is free." | header slotSize jumpSingle loopHead jumpNeedScavenge continuation exit | <var: #jumpNeedScavenge type: #'AbstractInstruction *'> <var: #continuation type: #'AbstractInstruction *'> <var: #jumpSingle type: #'AbstractInstruction *'> <var: #loopHead type: #'AbstractInstruction *'> <var: #exit type: #'AbstractInstruction *'> cogit "load the flag; stash it in both TempReg & ClassReg; do the compare (a prime candidated for use of AndCq:R:R:)" MoveMw: FoxMethod r: FPReg R: ClassReg; AndCq: MFMethodFlagHasContextFlag R: ClassReg R: TempReg. jumpSingle := cogit JumpZero: 0. "jump if flag bit not set" cogit "since the flag bit was set, get the context in the receiver reg and return" MoveMw: FoxThisContext r: FPReg R: ReceiverResultReg; RetN: 0. jumpSingle jmpTarget: cogit Label. "OK, it doesn't exist; instantiate and initialize it" "set the hasContext flag; See CoInterpreter class>>initializeFrameIndices" cogit OrCq: MFMethodFlagHasContextFlag R: ClassReg; MoveR: ClassReg Mw: FoxMethod r: FPReg. "now get the home CogMethod into ClassReg and save for post-instantiation." isInBlock caseOf: { [InFullBlock] -> [cogit SubCq: 3 R: ClassReg]. "-3 is -(hasContext+isBlock) flags" [InVanillaBlock] -> [cogit SubCq: 3 R: ClassReg; "-3 is -(hasContext+isBlock) flags" MoveM16: 0 r: ClassReg R: TempReg; SubR: TempReg R: ClassReg]. [0] -> [cogit SubCq: 1 R: ClassReg]. "-1 is hasContext flag" }. "instantiate the context..." slotSize := isLarge ifTrue: [LargeContextSlots] ifFalse: [SmallContextSlots]. header := objectMemory headerForSlots: slotSize format: objectMemory indexablePointersFormat classIndex: ClassMethodContextCompactIndex. self flag: #endianness. cogit MoveAw: objectMemory freeStartAddress R: ReceiverResultReg. self genStoreHeader: header intoNewInstance: ReceiverResultReg using: TempReg. cogit MoveR: ReceiverResultReg R: TempReg; AddCq: (objectMemory smallObjectBytesForSlots: slotSize) R: TempReg; MoveR: TempReg Aw: objectMemory freeStartAddress; CmpCq: objectMemory getScavengeThreshold R: TempReg. jumpNeedScavenge := cogit JumpAboveOrEqual: 0. "Now initialize the fields of the context. See CoInterpreter>>marryFrame:SP:copyTemps:" "sender gets frame pointer as a SmallInteger" continuation := cogit MoveR: FPReg R: TempReg. self genSetSmallIntegerTagsIn: TempReg. cogit MoveR: TempReg Mw: objectMemory baseHeaderSize + (SenderIndex * objectMemory bytesPerOop) r: ReceiverResultReg. "pc gets frame caller as a SmallInteger" cogit MoveMw: FoxSavedFP r: FPReg R: TempReg. self genSetSmallIntegerTagsIn: TempReg. cogit MoveR: TempReg Mw: objectMemory baseHeaderSize + (InstructionPointerIndex * objectMemory bytesPerOop) r: ReceiverResultReg. "Set the method field, freeing up ClassReg again, and frame's context field," cogit MoveMw: (cogit offset: CogMethod of: #methodObject) r: ClassReg R: TempReg; MoveR: TempReg Mw: objectMemory baseHeaderSize + (MethodIndex * objectMemory wordSize) r: ReceiverResultReg; MoveR: ReceiverResultReg Mw: FoxThisContext r: FPReg. "Now compute stack pointer; this is stackPointer (- 1 for return pc if a CISC) - framePointer - wordSize (1 each for saved pc, method, context, receiver) + 1 (1-relative) + numArgs" "TPR note - the code here is actually doing context stackPointer := ((((fp - sp) / wordSize) - [3|4]) + num args) asSmallInteger" cogit SubR: SPReg R: FPReg R: TempReg; "TempReg := FPReg - SPReg" LogicalShiftRightCq: self log2BytesPerWord R: TempReg; SubCq: (cogit backEnd hasLinkRegister ifTrue: [3] ifFalse: [4]) R: TempReg; AddR: SendNumArgsReg R: TempReg. self genConvertIntegerToSmallIntegerInReg: TempReg. cogit MoveR: TempReg Mw: objectMemory baseHeaderSize + (StackPointerIndex * objectMemory bytesPerOop) r: ReceiverResultReg. "Set closureOrNil to either the stacked receiver or nil" isInBlock > 0 ifTrue: [cogit MoveR: SendNumArgsReg R: TempReg; AddCq: 2 R: TempReg; "+2 for saved fp and saved pc" MoveXwr: TempReg R: FPReg R: TempReg] ifFalse: [cogit genMoveNilR: TempReg]. cogit MoveR: TempReg Mw: objectMemory baseHeaderSize + (ClosureIndex * objectMemory bytesPerOop) r: ReceiverResultReg. "Set the receiver" cogit MoveMw: FoxMFReceiver r: FPReg R: TempReg; MoveR: TempReg Mw: objectMemory baseHeaderSize + (ReceiverIndex * objectMemory bytesPerOop) r: ReceiverResultReg. "Now copy the arguments. This is tricky because of the shortage of registers,. ClassReg ranges from 1 to numArgs (SendNumArgsReg), and from ReceiverIndex + 1 to ReceiverIndex + numArgs. 1 to: numArgs do: [:i| temp := longAt(FPReg + ((SendNumArgs - i + 2) * wordSize)). +2 for saved pc and savedfp longAtput(FPReg + FoxMFReceiver + (i * wordSize), temp)]" "TPR note: this is a prime candidate for passing off to the backend to do at least faintly optimal code" cogit MoveCq: 1 R: ClassReg. loopHead := cogit CmpR: SendNumArgsReg R: ClassReg. exit := cogit JumpGreater: 0. cogit MoveR: SendNumArgsReg R: TempReg; SubR: ClassReg R: TempReg; AddCq: 2 R: TempReg; "+2 for saved fp and saved pc" MoveXwr: TempReg R: FPReg R: TempReg; AddCq: ReceiverIndex + (objectMemory baseHeaderSize / objectMemory wordSize) R: ClassReg; "Now convert ClassReg from frame index to context index" MoveR: TempReg Xwr: ClassReg R: ReceiverResultReg; SubCq: ReceiverIndex + (objectMemory baseHeaderSize / objectMemory wordSize) - 1 R: ClassReg; "convert back adding 1 ;-)" Jump: loopHead. exit jmpTarget: cogit Label. "Finally nil or copy the non-argument temps. ClassReg := FPReg + FoxMFReceiver. SendNumArgsReg := SendNumArgsReg+ReceiverIndex. [ClassReg := ClassReg - wordSize. backEnd hasLinkRegister ifTrue: [ClassReg > SPReg] ifFalse: [ClassReg >= SPReg]] whileTrue: [receiver[SendNumArgsReg] := *ClassReg. SendNumArgsReg := SendNumArgsReg + 1]]" coInterpreter marryFrameCopiesTemps ifFalse: [cogit MoveCq: objectMemory nilObject R: TempReg]. cogit MoveR: FPReg R: ClassReg; AddCq: FoxMFReceiver R: ClassReg; AddCq: ReceiverIndex + 1 + (objectMemory baseHeaderSize / objectMemory wordSize) R: SendNumArgsReg. loopHead := cogit SubCq: objectMemory wordSize R: ClassReg. + cogit CmpR: ClassReg R: SPReg. - cogit CmpR: SPReg R: ClassReg. "If on a CISC there's a retpc for the trampoline call on top of stack; if on a RISC there isn't." exit := cogit backEnd hasLinkRegister + ifTrue: [cogit JumpAboveOrEqual: 0] + ifFalse: [cogit JumpBelow: 0]. - ifTrue: [cogit JumpBelow: 0] - ifFalse: [cogit JumpBelowOrEqual: 0]. coInterpreter marryFrameCopiesTemps ifTrue: [cogit MoveMw: 0 r: ClassReg R: TempReg]. cogit MoveR: TempReg Xwr: SendNumArgsReg R: ReceiverResultReg; AddCq: 1 R: SendNumArgsReg; Jump: loopHead. exit jmpTarget: cogit Label. cogit RetN: 0. jumpNeedScavenge jmpTarget: cogit Label. cogit backEnd saveAndRestoreLinkRegAround: [cogit CallRT: ceScheduleScavengeTrampoline registersToBeSavedMask: (cogit registerMaskFor: ReceiverResultReg and: SendNumArgsReg and: ClassReg)]. cogit Jump: continuation. ^0! Item was changed: ----- Method: Cogit>>blockAlignment (in category 'accessing') ----- blockAlignment "Block method headers must be aligned on the correct boundary, just like non-block method headers. This is because the CoInterpreter encodes flags in the least significant three bits of the method field." <api> <cmacro: '() 8'> + self assert: (methodZone roundUpLength: 1) >= 8. - self assert: (methodZone roundUpLength: 1) = 8. ^8! Item was added: + ----- Method: CogitForTests>>codeSize (in category 'generate machine code') ----- + codeSize + "Answer the size of code generated, which includes the offset at which the code was generated." + ^codeBytes size! |
Free forum by Nabble | Edit this page |