pavone@174: { pavone@179: regnames <- #["rax" "rcx" "rdx" "rbx" "rsp" "rbp" "rsi" "rdi" "r8" "r9" "r10" "r11" "r12" "r13" "r14" "r15"] pavone@179: uppernames <- #["ah" "ch" "dh" "bh"] pavone@174: ireg <- :regnum { pavone@174: #{ pavone@174: num <- { regnum } pavone@174: reg <- { regnum and 7u8} pavone@179: string <- { regnames get: regnum } pavone@174: rm <- :tail { reg or 0xC0u8 | tail } pavone@174: validforSize? <- :size { true } pavone@174: isInteger? <- { false } pavone@203: isString? <- { false } pavone@174: register? <- { true } pavone@181: label? <- { false } pavone@198: upper? <- { false } pavone@174: needsRex? <- { regnum >= 8u8 } pavone@174: rexBitReg <- { pavone@174: if: needsRex? { pavone@174: 4u8 pavone@174: } else: { pavone@174: 0u8 pavone@174: } pavone@174: } pavone@174: rexBitRM <- { pavone@174: if: needsRex? { pavone@174: 1u8 pavone@174: } else: { pavone@174: 0u8 pavone@174: } pavone@174: } pavone@174: = <- :other { pavone@174: (not: (other isInteger?)) && (other register?) && (not: (other upper?)) && regnum = (other num) pavone@174: } pavone@174: } pavone@174: } pavone@174: pavone@174: upper <- :regnum { pavone@174: #{ pavone@174: num <- { regnum } pavone@174: reg <- { regnum } pavone@179: string <- { uppernames get: regnum - 4 } pavone@174: rm <- :tail { regnum or 0xC0u8 | tail } pavone@174: validforSize? <- :size { pavone@174: size = byte pavone@174: } pavone@174: isInteger? <- { false } pavone@174: register? <- { true } pavone@181: label? <- { false } pavone@174: upper? <- { true } pavone@174: needsRex? <- { false } pavone@174: = <- :other { pavone@174: (not: (other isInteger?)) && (other register?) && (other upper?) && regnum = (other num) pavone@174: } pavone@174: } pavone@174: } pavone@174: fakesrc <- #{ pavone@174: needsRex? <- { false } pavone@174: rexBitReg <- { 0u8 } pavone@174: rexBitRM <- { 0u8 } pavone@174: } pavone@203: _size <- :s { pavone@174: #{ pavone@174: num <- { s } pavone@174: = <- :other { pavone@174: s = (other num) pavone@174: } pavone@174: > <- :other { pavone@174: s > (other num) pavone@174: } pavone@174: >= <- :other { pavone@174: s >= (other num) pavone@174: } pavone@174: < <- :other { pavone@174: s < (other num) pavone@174: } pavone@174: <= <- :other { pavone@174: s <= (other num) pavone@174: } pavone@174: needsRex? <- { s = 3 } pavone@174: rexBit <- { pavone@174: if: needsRex? { pavone@174: 0x08u8 pavone@174: } else: { pavone@174: 0u8 pavone@174: } pavone@174: } pavone@174: } pavone@174: } pavone@203: byte <- _size: 0 pavone@203: word <- _size: 1 pavone@203: dword <- _size: 2 pavone@203: qword <- _size: 3 pavone@174: pavone@183: condition <- :num { pavone@183: #{ pavone@183: cc <- { num } pavone@183: } pavone@183: } pavone@183: _o <- condition: 0u8 pavone@183: _no <- condition: 1u8 pavone@183: _c <- condition: 2u8 pavone@183: _nc <- condition: 3u8 pavone@183: _z <- condition: 4u8 pavone@183: _nz <- condition: 5u8 pavone@183: _be <- condition: 6u8 pavone@183: _nbe <- condition: 7u8 pavone@183: _s <- condition: 8u8 pavone@183: _ns <- condition: 9u8 pavone@183: _p <- condition: 10u8 pavone@183: _np <- condition: 11u8 pavone@183: _l <- condition: 12u8 pavone@183: _nl <- condition: 13u8 pavone@183: _le <- condition: 14u8 pavone@183: _nle <- condition: 15u8 pavone@183: pavone@183: pavone@174: size_bit <- :opcode size { pavone@174: if: size = byte { pavone@174: opcode pavone@174: } else: { pavone@179: opcode or 1u8 pavone@174: } pavone@174: } pavone@174: opex <- :val { pavone@174: #{ pavone@174: reg <- { val } pavone@179: string <- { "opex " . val} pavone@174: } pavone@174: } pavone@174: pavone@174: mod_rm:withTail <- :register regmem :end { pavone@193: list <- regmem rm: end pavone@193: (list value) or ( lshift: (register reg) by: 3u8) | (list tail) pavone@174: } pavone@174: pavone@174: mod_rm <- :reg rm { pavone@174: mod_rm: reg rm withTail: [] pavone@174: } pavone@174: pavone@175: int_op:withTail <- :value size :tail { pavone@174: if: size >= dword { pavone@179: tail <- (uint8: (rshift: value by: 16u64)) | (uint8: (rshift: value by: 24u64)) | tail pavone@174: } pavone@174: if: size >= word { pavone@179: tail <- (uint8: (rshift: value by: 8u64)) | tail pavone@174: } pavone@174: (uint8: value) | tail pavone@174: } pavone@175: int_op <- :value size { pavone@175: int_op: value size withTail: [] pavone@175: } pavone@175: //used for mov instructions that support 64-bit immediate operands/offsets pavone@175: int_op64 <- :value size { pavone@175: tail <- [] pavone@183: value <- uint64: value pavone@175: if: size = qword { pavone@179: tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail pavone@175: } pavone@175: int_op: value size withTail: tail pavone@175: } pavone@174: pavone@174: prefix:withInstruction <- :reg rm size :inst { pavone@174: if: size = word { pavone@174: inst <- 0x66u8 | inst pavone@174: } pavone@174: if: (size needsRex?) || (reg needsRex?) || (rm needsRex?) { pavone@174: rex <- 0x40u8 or (size rexBit) or (reg rexBitReg) or (rm rexBitRM) pavone@174: inst <- rex | inst pavone@174: } pavone@174: inst pavone@174: } pavone@174: pavone@174: _rax <- ireg: 0u8 pavone@174: _rcx <- ireg: 1u8 pavone@174: _rdx <- ireg: 2u8 pavone@174: _rbx <- ireg: 3u8 pavone@174: _rsp <- ireg: 4u8 pavone@174: _rbp <- ireg: 5u8 pavone@174: _rsi <- ireg: 6u8 pavone@174: _rdi <- ireg: 7u8 pavone@174: _r8 <- ireg: 8u8 pavone@174: _r9 <- ireg: 9u8 pavone@174: _r10 <- ireg: 10u8 pavone@174: _r11 <- ireg: 11u8 pavone@174: _r12 <- ireg: 12u8 pavone@174: _r13 <- ireg: 13u8 pavone@174: _r14 <- ireg: 14u8 pavone@174: _r15 <- ireg: 15u8 pavone@174: _ah <- upper: 4u8 pavone@174: _ch <- upper: 5u8 pavone@174: _dh <- upper: 6u8 pavone@174: _bh <- upper: 7u8 pavone@174: pavone@193: //AMD64 convention pavone@193: _argregs <- #[ pavone@193: _rdi pavone@193: _rsi pavone@193: _rdx pavone@193: _rcx pavone@193: _r8 pavone@193: _r9 pavone@193: ] pavone@193: _calleesave <- #[ pavone@193: _rbx pavone@193: _rbp pavone@193: _r12 pavone@193: _r13 pavone@193: _r14 pavone@193: _r15 pavone@193: ] pavone@193: _tempregs <- #[ pavone@193: _r10 pavone@193: _r11 pavone@194: //TODO: Add rax back in once there's logic in il to properly pavone@194: //allocate it for the instances in which it's live pavone@194: //_rax pavone@193: ] pavone@193: pavone@193: pavone@180: inst <- :ilist { pavone@180: #{ pavone@180: length <- { ilist length } pavone@180: flattenTo:at <- :dest :idx { pavone@180: ilist fold: idx with: :idx byte { pavone@180: dest set: idx byte pavone@180: idx + 1 pavone@180: } pavone@180: } pavone@180: } pavone@180: } pavone@204: multiInst <- :instarr { pavone@204: #{ pavone@204: length <- { pavone@204: instarr fold: 0 with: :acc inst { pavone@204: acc + (inst length) pavone@204: } pavone@204: } pavone@204: flattenTo:at <- :dest :idx { pavone@204: instarr fold: idx with: :idx inst { pavone@204: inst flattenTo: dest at: idx pavone@204: } pavone@204: } pavone@204: } pavone@204: } pavone@180: pavone@175: op:withCode:withImmed:withOpEx <- :src dst size :normal :immed :myopex { pavone@174: reg <- src pavone@174: rm <- dst pavone@174: base <- if: (src isInteger?) { pavone@174: reg <- fakesrc pavone@175: (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size)) pavone@174: } else: { pavone@174: if: (src register?) { pavone@174: (size_bit: normal size) | (mod_rm: src dst) pavone@174: } else: { pavone@174: reg <- dst pavone@174: rm <- src pavone@174: (size_bit: normal or 0x02u8 size) | (mod_rm: dst src) pavone@174: } pavone@174: } pavone@180: inst: (prefix: reg rm size withInstruction: base) pavone@174: } pavone@174: pavone@175: op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt { pavone@175: reg <- src pavone@175: rm <- dst pavone@175: if: (src isInteger?) { pavone@175: reg <- fakesrc pavone@175: base <- if: size > byte && (((src signed?) && src < 128 && src >= -128) || ((not: (src signed?)) && src < 256)) { pavone@179: byteExt | (mod_rm: (opex: myopex) dst withTail: [(uint8: src)]) pavone@175: } else: { pavone@175: if: dst = _rax { pavone@175: (size_bit: immedRax size) | (int_op: src size) pavone@175: } else: { pavone@175: (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size)) pavone@175: } pavone@175: } pavone@180: inst: (prefix: reg rm size withInstruction: base) pavone@175: } else: { pavone@175: op: src dst size withCode: normal withImmed: immed withOpEx: myopex pavone@175: } pavone@175: } pavone@175: pavone@204: shiftRot:withOpEx <- :amount dst size :myopex { pavone@204: opcode <- 0u8 pavone@204: tail <- [] pavone@204: pre <- #[] pavone@204: post <- #[] pavone@204: base <- if: (amount isInteger?) { pavone@204: if: amount = 1 { pavone@204: opcode <- 0xD0u8 pavone@204: } else: { pavone@204: opcode <- 0xC0u8 pavone@204: tail <- [uint8: amount] pavone@204: } pavone@204: } else: { pavone@204: opcode <- 0xD2u8 pavone@204: if: (not: _rcx = amount) { pavone@204: pre <- #[ pavone@204: x86 push: _rcx pavone@204: x86 mov: amount _rcx byte pavone@204: ] pavone@204: post <- #[ pavone@204: x86 pop: _rcx pavone@204: ] pavone@204: } pavone@204: } pavone@204: bytes <- prefix: fakesrc dst withInstruction: (size_bit: 0xC0u8 size) | (mod_rm: (opex: myopex) dst withTail: tail) pavone@204: myinst <- inst: bytes pavone@204: if: (pre length) > 0 { pavone@204: pre append: myinst pavone@204: foreach: post :_ inst { pavone@204: pre append: inst pavone@204: } pavone@204: multiInst: pre pavone@204: } else: { pavone@204: myinst pavone@204: } pavone@204: } pavone@204: pavone@183: _jmprel <- :op jmpDest { pavone@183: } pavone@183: pavone@174: #{ pavone@174: rax <- { _rax } pavone@174: rcx <- { _rcx } pavone@174: rdx <- { _rdx } pavone@174: rbx <- { _rbx } pavone@174: rsp <- { _rsp } pavone@174: rbp <- { _rbp } pavone@174: rsi <- { _rsi } pavone@174: rdi <- { _rdi } pavone@174: r8 <- { _r8 } pavone@174: r9 <- { _r9 } pavone@174: r10 <- { _r10 } pavone@174: r11 <- { _r11 } pavone@174: r12 <- { _r12 } pavone@174: r13 <- { _r13 } pavone@174: r14 <- { _r14 } pavone@174: r15 <- { _r15 } pavone@174: ah <- { _ah } pavone@174: ch <- { _ch } pavone@174: dh <- { _dh } pavone@174: bh <- { _bh } pavone@174: pavone@174: b <- { byte } pavone@174: w <- { word } pavone@174: d <- { dword } pavone@174: q <- { qword } pavone@174: pavone@183: o <- { _o } pavone@183: no <- { _no } pavone@183: c <- { _c } pavone@183: nc <- { _nc } pavone@183: ae <- { _nc } pavone@183: z <- { _z } pavone@183: e <- { _z } pavone@183: nz <- { _nz } pavone@183: ne <- { _nz } pavone@183: be <- { _be } pavone@183: nbe <- { _nbe } pavone@183: a <- { _nbe } pavone@183: s <- { _s } pavone@183: ns <- { _ns } pavone@183: p <- { _p } pavone@183: pe <- { _p } pavone@183: np <- { _np } pavone@183: po <- { _np } pavone@183: l <- { _l } pavone@183: nl <- { _nl } pavone@183: ge <- { _nl } pavone@183: le <- { _le } pavone@183: nle <- { _nle } pavone@183: g <- { _nle } pavone@183: pavone@174: add <- :src dst size { pavone@174: op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8 pavone@174: } pavone@174: pavone@175: sub <- :src dst size { pavone@175: op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8 pavone@175: } pavone@175: pavone@204: cmp <- :src dst size { pavone@204: op: src dst size withCode: 0x38u8 withImmed: 0x80u8 withImmedRax: 0x3Cu8 withOpEx: 7u8 withByteExtend: 0x83u8 pavone@204: } pavone@204: pavone@204: and <- :src dst size { pavone@204: op: src dst size withCode: 0x20u8 withImmed: 0x80u8 withImmedRax: 0x24u8 withOpEx: 4u8 withByteExtend: 0x83u8 pavone@204: } pavone@204: pavone@204: or <- :src dst size { pavone@204: op: src dst size withCode: 0x08u8 withImmed: 0x80u8 withImmedRax: 0x0Cu8 withOpEx: 1u8 withByteExtend: 0x83u8 pavone@204: } pavone@204: pavone@204: xor <- :src dst size { pavone@204: op: src dst size withCode: 0x30u8 withImmed: 0x80u8 withImmedRax: 0x34u8 withOpEx: 6u8 withByteExtend: 0x83u8 pavone@204: } pavone@204: pavone@175: mov <- :src dst size { pavone@175: rm <- dst pavone@175: if: (src isInteger?) && (dst register?) { pavone@175: opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 } pavone@183: base <- opval or (dst reg) | (int_op64: src size) pavone@180: inst: (prefix: fakesrc rm size withInstruction: base) pavone@175: } else: { pavone@175: op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8 pavone@175: } pavone@175: } pavone@175: pavone@204: shl <- :shift dst size { pavone@204: shiftRot: shift dst size withOpEx: 4u8 pavone@204: } pavone@204: pavone@204: shr <- :shift dst size { pavone@204: shiftRot: shift dst size withOpEx: 5u8 pavone@204: } pavone@204: pavone@204: sar <- :shift dst size { pavone@204: shiftRot: shift dst size withOpEx: 7u8 pavone@204: } pavone@204: pavone@204: rol <- :shift dst size { pavone@204: shiftRot: shift dst size withOpEx: 0u8 pavone@204: } pavone@204: pavone@204: ror <- :shift dst size { pavone@204: shiftRot: shift dst size withOpEx: 1u8 pavone@204: } pavone@204: pavone@180: ret <- { inst: [ 0xC3u8 ] } pavone@180: pavone@180: label <- { pavone@180: _offset <- -1 pavone@180: _forwardRefs <- #[] pavone@180: #{ pavone@180: length <- { 0 } pavone@180: hasOffset? <- { _offset >= 0 } pavone@180: offset <- { _offset } pavone@180: register? <- { false } pavone@181: label? <- { true } pavone@180: flattenTo:at <- :dest :idx { pavone@180: if: (not: hasOffset?) { pavone@180: _offset <- idx pavone@180: foreach: _forwardRefs :idx fun { pavone@180: fun: _offset pavone@180: } pavone@180: _forwardRefs <- #[] pavone@180: } pavone@180: idx pavone@180: } pavone@180: withOffset:else <- :fun :elsefun { pavone@180: if: hasOffset? { pavone@180: fun: _offset pavone@180: } else: { pavone@180: _forwardRefs append: fun pavone@180: elsefun: pavone@180: } pavone@180: } pavone@180: } pavone@180: } pavone@180: pavone@180: jmp <- :jmpDest { pavone@181: if: (jmpDest label?) { pavone@180: _size <- -1 pavone@180: #{ pavone@180: length <- { if: _size < 0 { 5 } else: { _size } } pavone@180: flattenTo:at <- :dest :idx { pavone@180: jmpDest withOffset: :off { pavone@180: if: _size < 0 { pavone@180: rel <- off - (idx + 2) pavone@180: if: rel < 128 && rel >= -128 { pavone@180: _size <- 2 pavone@180: } else: { pavone@180: rel <- rel - 2 pavone@180: if: rel < 32768 && rel >= -32768 { pavone@180: _size <- 4 pavone@180: } else: { pavone@180: _size <- 5 pavone@180: } pavone@180: } pavone@180: } pavone@180: rel <- off - (idx + _size) pavone@180: if: _size = 2 { pavone@180: dest set: idx 0xEBu8 pavone@180: dest set: (idx + 1) (uint8: rel) pavone@180: } else: { pavone@180: if: _size = 4 { pavone@180: dest set: idx 0x66u8 pavone@180: dest set: (idx + 1) 0xE9u8 pavone@180: dest set: (idx + 2) (uint8: rel) pavone@180: dest set: (idx + 3) (uint8: (rshift: rel by: 8)) pavone@180: } else: { pavone@180: dest set: idx 0xE9u8 pavone@180: dest set: (idx + 1) (uint8: rel) pavone@180: dest set: (idx + 2) (uint8: (rshift: rel by: 8)) pavone@180: dest set: (idx + 3) (uint8: (rshift: rel by: 16)) pavone@180: dest set: (idx + 4) (uint8: (rshift: rel by: 24)) pavone@180: } pavone@180: } pavone@180: } else: { pavone@180: _size <- 5 pavone@180: } pavone@180: idx + _size pavone@180: } pavone@180: } pavone@180: } else: { pavone@180: inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest) pavone@180: } pavone@180: } pavone@175: pavone@183: jcc <- :cond jmpDest { pavone@183: _size <- -1 pavone@183: #{ pavone@183: length <- { if: _size < 0 { 5 } else: { _size } } pavone@183: flattenTo:at <- :dest :idx { pavone@183: jmpDest withOffset: :off { pavone@183: if: _size < 0 { pavone@183: rel <- off - (idx + 2) pavone@183: if: rel < 128 && rel >= -128 { pavone@183: _size <- 2 pavone@183: } else: { pavone@183: _size <- 6 pavone@183: } pavone@183: } pavone@183: rel <- off - (idx + _size) pavone@183: if: _size = 2 { pavone@183: dest set: idx 0x70u8 or (cond cc) pavone@183: dest set: (idx + 1) (uint8: rel) pavone@183: } else: { pavone@183: dest set: idx 0x0Fu8 pavone@183: dest set: (idx + 1) 0x80u8 or (cond cc) pavone@183: dest set: (idx + 2) (uint8: rel) pavone@183: dest set: (idx + 3) (uint8: (rshift: rel by: 8)) pavone@183: dest set: (idx + 4) (uint8: (rshift: rel by: 16)) pavone@183: dest set: (idx + 5) (uint8: (rshift: rel by: 24)) pavone@183: } pavone@183: } else: { pavone@183: _size <- 6 pavone@183: } pavone@183: idx + _size pavone@183: } pavone@183: } pavone@183: } pavone@183: pavone@181: call <- :callDest { pavone@181: if: (callDest label?) { pavone@181: #{ pavone@181: length <- { 5 } pavone@181: flattenTo:at <- :dest :idx { pavone@181: dest set: idx 0xE8u8 pavone@181: callDest withOffset: :off { pavone@181: rel <- off - (idx + 5) pavone@181: dest set: (idx + 1) (uint8: rel) pavone@181: dest set: (idx + 2) (uint8: (rshift: rel by: 8)) pavone@181: dest set: (idx + 3) (uint8: (rshift: rel by: 16)) pavone@181: dest set: (idx + 4) (uint8: (rshift: rel by: 24)) pavone@181: } else: { pavone@181: } pavone@181: idx + 5 pavone@181: } pavone@181: } pavone@181: } else: { pavone@181: inst: 0xFFu8 | (mod_rm: (opex: 2u8) callDest) pavone@181: } pavone@181: } pavone@174: pavone@183: push <- :src { pavone@183: if: (src isInteger?) { pavone@183: if: src < 128 && src > -128 { pavone@183: inst: 0x6Au8 | (uint8: src) pavone@183: } else: { pavone@183: inst: 0x68u8 | (uint8: src) | (uint8: (rshift: src by: 8)) | (uint8: (rshift: src by: 16)) | (uint8: (rshift: src by: 24)) pavone@183: } pavone@183: } else: { pavone@183: base <- if: (src register?) { pavone@183: [0x50u8 or (src reg)] pavone@183: } else: { pavone@183: 0xFFu8 | (mod_rm: (opex: 6u8) src) pavone@183: } pavone@183: inst: (prefix: fakesrc src d withInstruction: base) pavone@183: } pavone@183: } pavone@183: pavone@183: pop <- :dst { pavone@183: base <- if: (dst register?) { pavone@183: [0x58u8 or (dst reg)] pavone@183: } else: { pavone@183: 0x8Fu8 | (mod_rm: (opex: 0u8) dst) pavone@183: } pavone@183: inst: (prefix: fakesrc dst d withInstruction: base) pavone@183: } pavone@183: pavone@204: bnot <- :dst size { pavone@204: base <- (size_bit: 0xF6u8 size) | (mod_rm: (opex: 2u8) dst) pavone@204: inst: (prefix: fakesrc dst size withInstruction: base) pavone@204: } pavone@204: pavone@193: //TODO: support multiple calling conventions pavone@193: regSource <- { pavone@193: _used <- 0 pavone@193: _usedAllTime <- 0 pavone@193: _nextStackOff <- 0 pavone@193: _findUnused <- :size reglists{ pavone@193: found <- -1 pavone@193: foundlist <- -1 pavone@193: curlist <- 0 pavone@193: ll <- reglists length pavone@193: while: { found < 0 && curlist < ll } do: { pavone@193: cur <- 0 pavone@193: regs <- reglists get: curlist pavone@193: len <- regs length pavone@193: while: { found < 0 && cur < len } do: { pavone@195: bit <- lshift: 1 by: ((regs get: cur) num) pavone@193: if: (_used and bit) = 0 { pavone@193: found <- cur pavone@193: foundlist <- regs pavone@193: _used <- _used or bit pavone@193: _usedAllTime <- _usedAllTime or bit pavone@193: } pavone@193: cur <- cur + 1 pavone@193: } pavone@193: curlist <- curlist + 1 pavone@193: } pavone@193: if: found >= 0 { pavone@193: foundlist get: found pavone@193: } else: { pavone@193: myoff <- _nextStackOff pavone@193: _nextStackOff <- _nextStackOff + size pavone@193: il base: _rsp offset: myoff pavone@193: } pavone@193: } pavone@193: #{ pavone@193: alloc <- :size { pavone@193: _findUnused: size #[ pavone@193: _calleesave pavone@193: _tempregs pavone@193: _argregs pavone@193: ] pavone@193: } pavone@193: //used to allocate a register pavone@193: //that will be returned before a call pavone@193: allocTemp <- :size { pavone@193: _findUnused: size #[ pavone@193: _tempregs pavone@193: _argregs pavone@193: _calleesave pavone@193: ] pavone@193: } pavone@193: //allocated the return register pavone@194: allocRet <- { pavone@193: bit <- (lshift: 1 by: (_rax num)) pavone@193: _used <- _used or bit pavone@193: _usedAllTime <- _usedAllTime or bit pavone@193: _rax pavone@193: } pavone@193: allocArg <- :argnum { pavone@193: if: argnum < (_argregs length) { pavone@193: reg <- _argregs get: argnum pavone@193: bit <- (lshift: 1 by: (reg num)) pavone@193: _used <- _used or bit pavone@193: _usedAllTime <- _usedAllTime or bit pavone@194: reg pavone@193: } else: { pavone@193: il base: _rsp offset: _nextStackOff + 8 * (argnum - (_argregs length)) pavone@193: } pavone@193: } pavone@193: allocSpecific <- :reg { pavone@193: if: (reg register?) { pavone@193: bit <- (lshift: 1 by: (reg num)) pavone@193: _used <- _used or bit pavone@193: } pavone@193: } pavone@193: stackSize <- { _nextStackOff } pavone@193: return <- :reg { pavone@193: _used <- _used and (0xF xor (lshift: 1 by: (reg num))) pavone@193: } pavone@198: returnAll <- { _used <- 0 } pavone@193: needSaveProlog <- { pavone@193: retval <- #[] pavone@193: foreach: _calleesave :idx reg { pavone@195: bit <- lshift: 1 by: (reg num) pavone@195: if: (_usedAllTime and bit) != 0 { pavone@193: retval append: reg pavone@193: } pavone@193: } pavone@193: retval pavone@193: } pavone@193: needSaveForCall <- { pavone@193: retval <- #[] pavone@198: foreach: #[(_tempregs) (_argregs)] :_ regs { pavone@193: foreach: regs :_ reg { pavone@193: if: (_used and (lshift: 1 by: (reg num))) != 0 { pavone@193: retval append: reg pavone@193: } pavone@193: } pavone@193: } pavone@193: retval pavone@193: } pavone@193: } pavone@193: } pavone@193: pavone@203: adjustIL <- :ilfun { pavone@203: il to2Op: (il allocRegs: ilfun withSource: regSource) pavone@203: } pavone@203: pavone@203: convertIL:to:withLabels:withSaved <- :inst :outarr :labels :saved { pavone@203: mapSize <- :ilsize { pavone@203: if: (ilsize bytes) > 2 { pavone@203: if: (ilsize bytes) = 8 { q } else: { d } pavone@203: } else: { pavone@203: if: (ilsize bytes) = 1 { b } else: { w } pavone@203: } pavone@203: } pavone@203: mapcond <- :ilcond { pavone@203: ccmap <- #[ pavone@203: e pavone@203: ne pavone@203: ge pavone@203: le pavone@203: g pavone@203: l pavone@203: ae pavone@203: be pavone@203: a pavone@203: c pavone@203: ] pavone@203: ccmap get: (ilcond cc) pavone@203: } pavone@203: opmap <- #[ pavone@203: { outarr append: (add: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (and: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (or: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (xor: (inst in) (inst out) (mapSize: (inst size))) } pavone@203: { outarr append: (sub: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (cmp: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (bnot: (inst arg) (mapSize: (inst size))) } pavone@204: { outarr append: (shl: (inst in) (inst out) (mapSize: (inst size))) } //sl pavone@204: { outarr append: (sar: (inst in) (inst out) (mapSize: (inst size))) } //asr pavone@204: { outarr append: (shr: (inst in) (inst out) (mapSize: (inst size))) } //lsr pavone@204: { outarr append: (rol: (inst in) (inst out) (mapSize: (inst size))) } pavone@204: { outarr append: (ror: (inst in) (inst out) (mapSize: (inst size))) } pavone@203: { outarr append: (mov: (inst in) (inst out) (mapSize: (inst size))) } pavone@203: { pavone@203: //call pavone@203: arguments <- inst args pavone@203: cur <- (arguments length) - 1 pavone@203: while: { cur >= 0 } do: { pavone@203: src <- (arguments get: cur) pavone@203: if: cur < (_argregs length) { pavone@203: dst <- _argregs get: cur pavone@203: if: (not: dst = src) { pavone@203: //TODO: Handle edge case in which src is a caller saved pavone@203: //reg that has been pusehd onto the stack to preserve pavone@203: //it across this call pavone@203: outarr append: (mov: src dst q) pavone@203: } pavone@203: } else: { pavone@203: outarr append: (push: src) pavone@203: } pavone@203: cur <- cur - 1 pavone@203: } pavone@203: toCall <- inst target pavone@203: if: (toCall isString?) { pavone@203: //TODO: Handle call to undefined label pavone@203: toCall <- labels get: toCall pavone@203: } pavone@203: outarr append: (call: toCall) pavone@203: } pavone@203: { pavone@203: //return pavone@203: if: (not: _rax = (inst arg)) { pavone@203: outarr append: (mov: (inst arg) _rax q) pavone@203: } pavone@203: foreach: saved :_ reg { pavone@203: outarr append: (pop: reg) pavone@203: } pavone@203: outarr append: (ret: ) pavone@203: } pavone@203: { pavone@203: //skipIf pavone@203: endlab <- label: pavone@203: outarr append: (jcc: (mapcond: (inst cond)) endlab) pavone@203: foreach: (inst toskip) :_ inst { pavone@203: convertIL: inst to: outarr withLabels: labels withSaved: saved pavone@203: } pavone@203: outarr append: endlab pavone@203: } pavone@203: { pavone@203: //save pavone@203: newsave <- [] pavone@203: foreach: (inst tosave) :_ reg { pavone@203: outarr append: (push: reg) pavone@203: newsave <- reg | newsave pavone@203: } pavone@203: foreach: (inst scope) :_ inst { pavone@203: convertIL: inst to: outarr withLabels: labels withSaved: newsave pavone@203: } pavone@203: if: ((inst scope) length) = 0 || (((inst scope) get: ((inst scope) length) - 1) opcode) != 14 { pavone@203: foreach: newsave :_ reg { pavone@203: outarr append: (pop: reg) pavone@203: } pavone@203: } pavone@203: } pavone@203: ] pavone@203: fun <- opmap get: (inst opcode) pavone@203: fun: pavone@203: outarr pavone@203: } pavone@203: pavone@203: convertIL:to:withLabels <- :inst :outarr :labels { pavone@203: convertIL: inst to: outarr withLabels: labels withSaved: [] pavone@203: } pavone@203: pavone@174: main <- { pavone@183: fib <- label: pavone@183: notbase <- label: pavone@179: prog <- #[ pavone@183: fib pavone@183: sub: 2 rdi q pavone@183: jcc: ge notbase pavone@183: mov: 1 rax q pavone@183: ret: pavone@183: pavone@183: notbase pavone@183: push: rdi pavone@183: call: fib pavone@183: pop: rdi pavone@183: push: rax pavone@183: add: 1 rdi q pavone@183: call: fib pavone@183: pop: rdi pavone@179: add: rdi rax q pavone@181: ret: pavone@179: ] pavone@180: pavone@179: ba <- bytearray executableFromBytes: prog pavone@183: res <- ba runWithArg: 30u64 pavone@179: print: (string: res) . "\n" pavone@174: 0 pavone@174: } pavone@174: } pavone@174: }