VM Maker: VMMaker.oscog-lw.194.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-lw.194.mcz

commits-2
 
Lars Wassermann uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-lw.194.mcz

==================== Summary ====================

Name: VMMaker.oscog-lw.194
Author: lw
Time: 7 August 2012, 8:54:48.906 pm
UUID: c7f87bb5-3022-db47-9d6b-76fa8f5b2d13
Ancestors: VMMaker.oscog-lw.193

Results of a nice pair programming session with Eliot.

- Changed nopsFrom:To: to padIfPossibleWithNopsFrom:To:, because on arm, a nop is 4 byte long. Therefore, on IA32, this is padded with nop, on ARM, all 4byte chunks are filled with nop, the rest is zero-padded.

- Changed the addressSpaceMask, because ARM (without Thumb) can only jump to 4-divisible addresses.

- Refactored printStateOn: to accomodate for register names which are not part of RTLOpcodes

- Fixed bugs in the jump-construction in ARM. When you want to reset the state, go back as far as #cog:selector:. There, the state is reset and you can step into the generation, if needed.

=============== Diff against VMMaker.oscog-lw.193 ===============

Item was added:
+ ----- Method: CogARMCompiler>>callTargetFromReturnAddress: (in category 'inline cacheing') -----
+ callTargetFromReturnAddress: callSiteReturnAddress
+ "Answer the address the call immediately preceeding callSiteReturnAddress will jump to."
+ | callDistance call |
+ call := self instructionBeforeAddress: callSiteReturnAddress.
+ (self isBranch: call)
+ ifTrue: [ callDistance := (call bitAnd: 16r00FFFFFF) << 2.
+ "The distance is a signed 24bit number. Therefore, the highest (26th) bit has to be expanded"
+ (callDistance bitAnd: 16r02000000) ~= 0
+ ifTrue: [callDistance := callDistance bitOr: 16rFC000000]]
+ ifFalse: [ "A Long Jump. Extract the value saved to RISCTempReg from all the instructions before."
+ self notYetImplemented ].
+ ^callSiteReturnAddress + 4 + callDistance signedIntFromLong!

Item was changed:
  ----- Method: CogARMCompiler>>concretizeCall (in category 'generate machine code - concretize') -----
  concretizeCall
  "Will get inlined into concretizeAt: switch."
  <inline: true>
  | offset |
  self assert: (operands at: 0) ~= 0.
  self assert: (operands at: 0) \\ 4 = 0.
  offset := (operands at: 0) signedIntFromLong - (address + 8) signedIntFromLong.
  (self isQuick: offset)
  ifTrue: [
  self machineCodeAt: 0 put: (self t: 5 o: 8) + (offset >> 2 bitAnd: 16r00FFFFFF). "BL offset"
  ^machineCodeSize := 4]
  ifFalse: [
+ self notYetImplemented]
- self halt]
  "We should push at least lr. The problem is, that any push added here is only executed after return, and therefore useless."!

Item was changed:
  ----- Method: CogARMCompiler>>concretizeConditionalJumpLong: (in category 'generate machine code - concretize') -----
  concretizeConditionalJumpLong: conditionCode
  "Will get inlined into concretizeAt: switch."
  "Sizing/generating jumps.
  Jump targets can be to absolute addresses or other abstract instructions.
  Generating initial trampolines instructions may have no maxSize and be to absolute addresses.
  Otherwise instructions must have a machineCodeSize which must be kept to."
  <inline: true>
  | jumpTarget |
  <var: #jumpTarget type: #'AbstractInstruction *'>
+ jumpTarget := self longJumpTargetAddress.
- jumpTarget := self jumpTargetAddress.
  self at: 0 moveCw: jumpTarget intoR: RISCTempReg.
  "mov lr, pc"
  "Because the pc always points to the actual address + 8, the value at pc is the address of the instruction after the branch (add pc, r3, #<byte0>"
  self machineCodeAt: 12 put: (self t: 0 o: 16rD s: 0 rn: 0 rd: LR shifterOperand: PC).
  "add pc, r3, #<byte 0>"
  self machineCodeAt: 16 put: (self t: 1 o: 4 s: 0 rn: RISCTempReg rd: PC shifterOperand: (jumpTarget bitAnd: 16rFF)).
  ^machineCodeSize := 20!

Item was added:
+ ----- Method: CogARMCompiler>>genSubstituteReturnAddress: (in category 'abstract instructions') -----
+ genSubstituteReturnAddress: retpc
+ <inline: true>
+ <returnTypeC: #'AbstractInstruction *'>
+ ^cogit MoveCw: retpc R: LR!

Item was added:
+ ----- Method: CogARMCompiler>>instructionBeforeAddress: (in category 'inline cacheing') -----
+ instructionBeforeAddress: followingAddress
+ "Answer the instruction immediately preceeding followingAddress."
+ ^  ((objectMemory byteAt: followingAddress - 1) << 24)
+ +  ((objectMemory byteAt: followingAddress - 2) << 16)
+ +  ((objectMemory byteAt: followingAddress - 3) << 8)
+ +   (objectMemory byteAt: followingAddress - 4)
+ !

Item was added:
+ ----- Method: CogARMCompiler>>isBranch: (in category 'testing') -----
+ isBranch: anInstruction
+
+ ^ (anInstruction >> 24 bitAnd: 16r0E) = 16rA!

Item was added:
+ ----- Method: CogARMCompiler>>nameForRegister: (in category 'printing') -----
+ nameForRegister: reg "<Integer>"
+ "subclasses with special purpose registers may need to override."
+ <doNotGenerate>
+ ^#(LR SP PC) detect: [:sym| (self class classPool at: sym) = reg] ifNone: [super nameForRegister: reg]!

Item was added:
+ ----- Method: CogARMCompiler>>padIfPossibleWithNopsFrom:to: (in category 'generate machine code - concretize') -----
+ padIfPossibleWithNopsFrom: startAddr to: endAddr
+ | nullBytes |
+ nullBytes := (endAddr - startAddr + 1) \\ 4.
+ self nopsFrom: startAddr to: endAddr - nullBytes.
+ endAddr - nullBytes + 1 to: endAddr
+ do: [ :p | objectMemory byteAt: p put: 16r0]!

Item was changed:
  ----- Method: CogARMCompiler>>sizePCDependentInstructionAt: (in category 'generate machine code') -----
  sizePCDependentInstructionAt: eventualAbsoluteAddress
  "Size a jump and set its address.  The target may be another instruction
  or an absolute address.  On entry the address inst var holds our virtual
  address. On exit address is set to eventualAbsoluteAddress, which is
  where this instruction will be output.  The span of a jump to a following
  instruction is therefore between that instruction's address and this
  instruction's address ((which are both still their virtual addresses), but the
  span of a jump to a preceeding instruction or to an absolute address is
  between that instruction's address (which by now is its eventual absolute
  address) or absolute address and eventualAbsoluteAddress."
 
  | target maximumSpan |
  <var: #abstractInstruction type: #'AbstractInstruction *'>
  opcode = AlignmentNops ifTrue:
  [| alignment |
  address := eventualAbsoluteAddress.
  alignment := operands at: 0.
  ^machineCodeSize := (eventualAbsoluteAddress + (alignment - 1) bitAnd: alignment negated)
    - eventualAbsoluteAddress].
  self assert: (self isJump or: [opcode = Call]).
+ self isJump ifTrue: [self resolveJumpTarget].
  target := operands at: 0.
  "maximumSpan calculation copied from CogIA32Compiler TODO: extract method?"
  (self isAnInstruction: (cogit cCoerceSimple: target to: #'void *'))
  ifTrue:
  [| abstractInstruction |
  abstractInstruction := cogit cCoerceSimple: target to: #'AbstractInstruction *'.
  maximumSpan := abstractInstruction address
  - (((cogit abstractInstruction: self follows: abstractInstruction)
  ifTrue: [eventualAbsoluteAddress]
  ifFalse: [address]) + 2)]
  ifFalse:
  [maximumSpan := target - (eventualAbsoluteAddress + 2)].
  address := eventualAbsoluteAddress.
+ ^machineCodeSize := (self isLongJump not and: [self isQuick: maximumSpan])
+ ifTrue: [4] "branch"
+ ifFalse: [20] "load address to register, add"!
- ^machineCodeSize := (self isQuick: maximumSpan)
- ifTrue: [4] "branch"
- ifFalse: [20] "load address to register, mov"!

Item was changed:
  ----- Method: CogAbstractInstruction>>computeJumpTargetOffsetPlus: (in category 'generate machine code') -----
+ computeJumpTargetOffsetPlus: anPCOffset
- computeJumpTargetOffsetPlus: anInteger
  <inline: true> "Since it's an extraction from other methods."
  | jumpTarget |
  <var: #jumpTarget type: #'AbstractInstruction *'>
  jumpTarget := self jumpTargetAddress.
+ ^jumpTarget signedIntFromLong - (address + anPCOffset) signedIntFromLong.!
- ^jumpTarget signedIntFromLong - (address + anInteger) signedIntFromLong.!

Item was added:
+ ----- Method: CogAbstractInstruction>>isLongJump (in category 'testing') -----
+ isLongJump
+ ^opcode between: FirstJump and: FirstShortJump - 1!

Item was added:
+ ----- Method: CogAbstractInstruction>>longJumpTargetAddress (in category 'generate machine code') -----
+ longJumpTargetAddress
+ <inline: true> "Since it's an extraction from other methods."
+ "This needs to be digfferent from jumpTargetAddress because long jumps can
+ be to absolute addresses and hence we can't assert that the jump target is sane."
+ | jumpTarget |
+ <var: #jumpTarget type: #'AbstractInstruction *'>
+ jumpTarget := cogit cCoerceSimple: (operands at: 0) to: #'AbstractInstruction *'.
+ (self isAnInstruction: jumpTarget) ifTrue:
+ [jumpTarget := cogit cCoerceSimple: jumpTarget address to: #'AbstractInstruction *'].
+ self assert: jumpTarget ~= 0.
+ ^jumpTarget!

Item was added:
+ ----- Method: CogAbstractInstruction>>nameForRegister: (in category 'printing') -----
+ nameForRegister: reg "<Integer>"
+ "subclasses with special purpose registers may need to override."
+ <doNotGenerate>
+ ^CogRTLOpcodes nameForRegister: reg!

Item was changed:
  ----- Method: CogAbstractInstruction>>printStateOn: (in category 'printing') -----
  printStateOn: aStream
  | opcodeName orneryOperands format |
  <doNotGenerate> "Smalltalk-side only"
  opcode isNil ifTrue:
  [^self].
  aStream space; nextPut: $(; nextPutAll: (opcodeName := self class nameForOpcode: opcode).
  orneryOperands := operands isCObjectAccessor
  ifTrue: [operands object]
  ifFalse: [operands].
  (cogit isKindOf: Cogit) ifTrue:
  [format := CogRTLOpcodes printFormatForOpcodeName: opcodeName].
  orneryOperands withIndexDo:
  [:operand :index|
  operand notNil ifTrue:
  [aStream space.
  index >= (orneryOperands identityIndexOf: nil ifAbsent: [orneryOperands size + 1]) ifTrue:
  [aStream print: index - 1; nextPut: $:].
  (format notNil and: [(format at: index ifAbsent: nil) = $r])
+ ifTrue: [aStream nextPutAll: (self nameForRegister: operand)]
- ifTrue: [aStream nextPutAll: (CogRTLOpcodes nameForRegister: operand)]
  ifFalse:
  [aStream print: operand.
  (operand isInteger and: [operand > 16 and: [opcode ~= Label]]) ifTrue:
  [(operand allMask: 16r80000000) ifTrue:
  [aStream nextPut: $/; print: operand signedIntFromLong].
  aStream nextPut: $/.
  operand printOn: aStream base: 16]]]].
  machineCodeSize ifNotNil:
  [(machineCodeSize between: 1 and: machineCode size) ifTrue:
  [0 to: machineCodeSize - 1 do:
  [:i|
  aStream space.
  (machineCode at: i) printOn: aStream base: 16]]].
  address ifNotNil:
  [aStream nextPut: $@.
  address printOn: aStream base: 16].
  aStream nextPut: $)!

Item was changed:
  ----- Method: CogAbstractInstruction>>resolveJumpTarget (in category 'generate machine code') -----
  resolveJumpTarget
  <var: #fixup type: #'BytecodeFixup *'>
  | fixup |
  self assert: self isJump.
  fixup := cogit cCoerceSimple: (operands at: 0) to: #'BytecodeFixup *'.
  self cCode: [] inSmalltalk:
  [(fixup isKindOf: CogBytecodeFixup) ifTrue:
  [self assert: (self isAFixup: fixup)]].
  (self isAFixup: fixup) ifTrue:
  [self assert: (cogit addressIsInInstructions: fixup targetInstruction).
  self jmpTarget: fixup targetInstruction]!

Item was added:
+ ----- Method: CogIA32Compiler>>padIfPossibleWithNopsFrom:to: (in category 'generate machine code') -----
+ padIfPossibleWithNopsFrom: startAddr to: endAddr
+ ^self nopsFrom: startAddr to: endAddr!

Item was added:
+ ----- Method: CogRTLOpcodes class>>nameForAbstractRegister: (in category 'debug printing') -----
+ nameForAbstractRegister: reg "<Integer>"
+ ^#(Arg0Reg Arg1Reg ClassReg FPReg ReceiverResultReg SPReg SendNumArgsReg TempReg
+ DPFPReg0 DPFPReg1 DPFPReg2 DPFPReg3 DPFPReg4 DPFPReg5 DPFPReg6 DPFPReg7)
+ detect: [:sym| (classPool at: sym) = reg]!

Item was changed:
  ----- Method: Cogit class>>initializeCompilationWithConstantsOptions: (in category 'class initialization') -----
  initializeCompilationWithConstantsOptions: optionsDictionary
  ProcessorClass := (optionsDictionary at: #ISA ifAbsent: [#IA32]) caseOf: {
  [#IA32] -> [BochsIA32Alien].
+ [#ARMv5] -> [GdbARMAlien]. }.
- [#ARMV5] -> [GdbARMAlien]. }.
  NumSendTrampolines := 4!

Item was changed:
  ----- Method: Cogit>>addressSpaceMask (in category 'accessing') -----
  addressSpaceMask
  <doNotGenerate>
+ "The first parenthesis generates a word of ones, -3 removes the two lowest bits because of ARM's requirement to have 4-aligned jumping addresses"
+ ^((1 << (8 * BytesPerWord)) - 1) - 3!
- ^(1 << (8 * BytesPerWord)) - 1!

Item was changed:
  ----- Method: Cogit>>generateCogMethod: (in category 'generate machine code') -----
  generateCogMethod: selector
  "We handle jump sizing simply.  First we make a pass that asks each
  instruction to compute its maximum size.  Then we make a pass that
  sizes jumps based on the maxmimum sizes.  Then we make a pass
  that fixes up jumps.  When fixing up a jump the jump is not allowed to
  choose a smaller offset but must stick to the size set in the second pass."
  | codeSize headerSize mapSize totalSize startAddress result method |
  <var: #method type: #'CogMethod *'>
  <var: #blockStart type: #'BlockStart *'>
  <var: #headerReference type: #'AbstractInstruction *'>
  <returnTypeC: #'CogMethod *'>
  headerSize := self sizeof: CogMethod.
  methodLabel address: headerSize negated.
  self computeMaximumSizes.
  methodLabel concretizeAt: (methodZone allocate: 0).
  codeSize := self generateInstructionsAt: methodLabel address + headerSize.
  mapSize := self generateMapAt: 0 start: methodLabel address + cmNoCheckEntryOffset.
  totalSize := methodZone roundUpLength: headerSize + codeSize + mapSize.
  startAddress := methodZone allocate: totalSize.
  startAddress = 0 ifTrue:
  [^self cCoerceSimple: InsufficientCodeSpace to: #'CogMethod *'].
  self assert: startAddress + cmEntryOffset = entry address.
  self assert: startAddress + cmNoCheckEntryOffset = noCheckEntry address.
  result := self outputInstructionsAt: startAddress + headerSize.
  self assert: startAddress + headerSize + codeSize = result.
+ backEnd padIfPossibleWithNopsFrom: result to: startAddress + totalSize - mapSize.
- backEnd nopsFrom: result to: startAddress + totalSize - mapSize.
  self generateMapAt: startAddress + totalSize - 1 start: startAddress + cmNoCheckEntryOffset.
  self fillInBlockHeadersAt: startAddress.
  method := self fillInMethodHeader: (self cCoerceSimple: startAddress to: #'CogMethod *')
  size: totalSize
  selector: selector.
  postCompileHook notNil ifTrue:
  [self perform: postCompileHook with: method with: primInvokeLabel.
  postCompileHook := nil].
  processor flushICacheFrom: startAddress to: startAddress + headerSize + codeSize.
  ^method!