+ shift_code :: (Operand -> Operand -> Instr)
+ -> StixTree
+ -> StixTree
+ -> UniqSM Register
+ {- Case1: shift length as immediate -}
+ -- Code is the same as the first eq. for trivialCode -- sigh.
+ shift_code instr x y{-amount-}
+ | maybeToBool imm
+ = getRegister x `thenUs` \ register ->
+ let
+ op_imm = OpImm imm__2
+ code__2 dst =
+ let
+ code = registerCode register dst
+ src = registerName register dst
+ in
+ mkSeqInstr (COMMENT SLIT("shift_code")) .
+ code .
+ if isFixed register && src /= dst
+ then
+ mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
+ instr op_imm (OpReg dst)]
+ else
+ mkSeqInstr (instr op_imm (OpReg src))
+ in
+ returnUs (Any IntRep code__2)
+ where
+ imm = maybeImm y
+ imm__2 = case imm of Just x -> x
+
+ {- Case2: shift length is complex (non-immediate) -}
+ shift_code instr x y{-amount-}
+ = getRegister y `thenUs` \ register1 ->
+ getRegister x `thenUs` \ register2 ->
+-- getNewRegNCG IntRep `thenUs` \ dst ->
+ let
+ -- Note: we force the shift length to be loaded
+ -- into ECX, so that we can use CL when shifting.
+ -- (only register location we are allowed
+ -- to put shift amounts.)
+ --
+ -- The shift instruction is fed ECX as src reg,
+ -- but we coerce this into CL when printing out.
+ src1 = registerName register1 ecx
+ code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
+ registerCode register1 ecx .
+ mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
+ else
+ registerCode register1 ecx
+ code__2 =
+ let
+ code2 = registerCode register2 eax
+ src2 = registerName register2 eax
+ in
+ code1 . code2 .
+ mkSeqInstr (instr (OpReg ecx) (OpReg eax))
+ in
+ returnUs (Fixed IntRep eax code__2)
+