annotate modules/x86.tp @ 263:98147071baf6

Add support for llMessage definitions in buildMethodTables
author Michael Pavone <pavone@retrodev.com>
date Mon, 14 Jul 2014 09:30:31 -0700
parents a8dffa4d4b54
children f987bb2a1911
rev   line source
pavone@174 1 {
pavone@179 2 regnames <- #["rax" "rcx" "rdx" "rbx" "rsp" "rbp" "rsi" "rdi" "r8" "r9" "r10" "r11" "r12" "r13" "r14" "r15"]
pavone@179 3 uppernames <- #["ah" "ch" "dh" "bh"]
pavone@174 4 ireg <- :regnum {
pavone@174 5 #{
pavone@174 6 num <- { regnum }
pavone@174 7 reg <- { regnum and 7u8}
pavone@179 8 string <- { regnames get: regnum }
pavone@174 9 rm <- :tail { reg or 0xC0u8 | tail }
pavone@174 10 validforSize? <- :size { true }
pavone@174 11 isInteger? <- { false }
pavone@203 12 isString? <- { false }
pavone@174 13 register? <- { true }
pavone@181 14 label? <- { false }
pavone@198 15 upper? <- { false }
pavone@174 16 needsRex? <- { regnum >= 8u8 }
pavone@174 17 rexBitReg <- {
pavone@174 18 if: needsRex? {
pavone@174 19 4u8
pavone@174 20 } else: {
pavone@174 21 0u8
pavone@174 22 }
pavone@174 23 }
pavone@174 24 rexBitRM <- {
pavone@174 25 if: needsRex? {
pavone@174 26 1u8
pavone@174 27 } else: {
pavone@174 28 0u8
pavone@174 29 }
pavone@174 30 }
pavone@174 31 = <- :other {
pavone@174 32 (not: (other isInteger?)) && (other register?) && (not: (other upper?)) && regnum = (other num)
pavone@174 33 }
pavone@174 34 }
pavone@174 35 }
pavone@174 36
pavone@174 37 upper <- :regnum {
pavone@174 38 #{
pavone@174 39 num <- { regnum }
pavone@174 40 reg <- { regnum }
pavone@179 41 string <- { uppernames get: regnum - 4 }
pavone@174 42 rm <- :tail { regnum or 0xC0u8 | tail }
pavone@174 43 validforSize? <- :size {
pavone@174 44 size = byte
pavone@174 45 }
pavone@174 46 isInteger? <- { false }
pavone@174 47 register? <- { true }
pavone@181 48 label? <- { false }
pavone@174 49 upper? <- { true }
pavone@174 50 needsRex? <- { false }
pavone@174 51 = <- :other {
pavone@174 52 (not: (other isInteger?)) && (other register?) && (other upper?) && regnum = (other num)
pavone@174 53 }
pavone@174 54 }
pavone@174 55 }
pavone@174 56 fakesrc <- #{
pavone@174 57 needsRex? <- { false }
pavone@174 58 rexBitReg <- { 0u8 }
pavone@174 59 rexBitRM <- { 0u8 }
pavone@174 60 }
pavone@203 61 _size <- :s {
pavone@174 62 #{
pavone@174 63 num <- { s }
pavone@174 64 = <- :other {
pavone@174 65 s = (other num)
pavone@174 66 }
pavone@174 67 > <- :other {
pavone@174 68 s > (other num)
pavone@174 69 }
pavone@174 70 >= <- :other {
pavone@174 71 s >= (other num)
pavone@174 72 }
pavone@174 73 < <- :other {
pavone@174 74 s < (other num)
pavone@174 75 }
pavone@174 76 <= <- :other {
pavone@174 77 s <= (other num)
pavone@174 78 }
pavone@174 79 needsRex? <- { s = 3 }
pavone@174 80 rexBit <- {
pavone@174 81 if: needsRex? {
pavone@174 82 0x08u8
pavone@174 83 } else: {
pavone@174 84 0u8
pavone@174 85 }
pavone@174 86 }
pavone@174 87 }
pavone@174 88 }
pavone@203 89 byte <- _size: 0
pavone@203 90 word <- _size: 1
pavone@203 91 dword <- _size: 2
pavone@203 92 qword <- _size: 3
pavone@174 93
pavone@183 94 condition <- :num {
pavone@183 95 #{
pavone@183 96 cc <- { num }
pavone@183 97 }
pavone@183 98 }
pavone@183 99 _o <- condition: 0u8
pavone@183 100 _no <- condition: 1u8
pavone@183 101 _c <- condition: 2u8
pavone@183 102 _nc <- condition: 3u8
pavone@183 103 _z <- condition: 4u8
pavone@183 104 _nz <- condition: 5u8
pavone@183 105 _be <- condition: 6u8
pavone@183 106 _nbe <- condition: 7u8
pavone@183 107 _s <- condition: 8u8
pavone@183 108 _ns <- condition: 9u8
pavone@183 109 _p <- condition: 10u8
pavone@183 110 _np <- condition: 11u8
pavone@183 111 _l <- condition: 12u8
pavone@183 112 _nl <- condition: 13u8
pavone@183 113 _le <- condition: 14u8
pavone@183 114 _nle <- condition: 15u8
pavone@183 115
pavone@183 116
pavone@174 117 size_bit <- :opcode size {
pavone@174 118 if: size = byte {
pavone@174 119 opcode
pavone@174 120 } else: {
pavone@179 121 opcode or 1u8
pavone@174 122 }
pavone@174 123 }
pavone@174 124 opex <- :val {
pavone@174 125 #{
pavone@174 126 reg <- { val }
pavone@179 127 string <- { "opex " . val}
pavone@174 128 }
pavone@174 129 }
pavone@174 130
pavone@174 131 mod_rm:withTail <- :register regmem :end {
pavone@193 132 list <- regmem rm: end
pavone@193 133 (list value) or ( lshift: (register reg) by: 3u8) | (list tail)
pavone@174 134 }
pavone@174 135
pavone@174 136 mod_rm <- :reg rm {
pavone@174 137 mod_rm: reg rm withTail: []
pavone@174 138 }
pavone@174 139
pavone@175 140 int_op:withTail <- :value size :tail {
pavone@174 141 if: size >= dword {
pavone@179 142 tail <- (uint8: (rshift: value by: 16u64)) | (uint8: (rshift: value by: 24u64)) | tail
pavone@174 143 }
pavone@174 144 if: size >= word {
pavone@179 145 tail <- (uint8: (rshift: value by: 8u64)) | tail
pavone@174 146 }
pavone@174 147 (uint8: value) | tail
pavone@174 148 }
pavone@175 149 int_op <- :value size {
pavone@175 150 int_op: value size withTail: []
pavone@175 151 }
pavone@175 152 //used for mov instructions that support 64-bit immediate operands/offsets
pavone@175 153 int_op64 <- :value size {
pavone@175 154 tail <- []
pavone@183 155 value <- uint64: value
pavone@175 156 if: size = qword {
pavone@179 157 tail <- (uint8: (rshift: value by: 32u64)) | (uint8: (rshift: value by: 40u64)) | (uint8: (rshift: value by: 48u64)) | (uint8: (rshift: value by: 56u64)) | tail
pavone@175 158 }
pavone@175 159 int_op: value size withTail: tail
pavone@175 160 }
pavone@174 161
pavone@174 162 prefix:withInstruction <- :reg rm size :inst {
pavone@174 163 if: size = word {
pavone@174 164 inst <- 0x66u8 | inst
pavone@174 165 }
pavone@174 166 if: (size needsRex?) || (reg needsRex?) || (rm needsRex?) {
pavone@174 167 rex <- 0x40u8 or (size rexBit) or (reg rexBitReg) or (rm rexBitRM)
pavone@174 168 inst <- rex | inst
pavone@174 169 }
pavone@174 170 inst
pavone@174 171 }
pavone@174 172
pavone@174 173 _rax <- ireg: 0u8
pavone@174 174 _rcx <- ireg: 1u8
pavone@174 175 _rdx <- ireg: 2u8
pavone@174 176 _rbx <- ireg: 3u8
pavone@174 177 _rsp <- ireg: 4u8
pavone@174 178 _rbp <- ireg: 5u8
pavone@174 179 _rsi <- ireg: 6u8
pavone@174 180 _rdi <- ireg: 7u8
pavone@174 181 _r8 <- ireg: 8u8
pavone@174 182 _r9 <- ireg: 9u8
pavone@174 183 _r10 <- ireg: 10u8
pavone@174 184 _r11 <- ireg: 11u8
pavone@174 185 _r12 <- ireg: 12u8
pavone@174 186 _r13 <- ireg: 13u8
pavone@174 187 _r14 <- ireg: 14u8
pavone@174 188 _r15 <- ireg: 15u8
pavone@174 189 _ah <- upper: 4u8
pavone@174 190 _ch <- upper: 5u8
pavone@174 191 _dh <- upper: 6u8
pavone@174 192 _bh <- upper: 7u8
pavone@174 193
pavone@193 194 //AMD64 convention
pavone@193 195 _argregs <- #[
pavone@193 196 _rdi
pavone@193 197 _rsi
pavone@193 198 _rdx
pavone@193 199 _rcx
pavone@193 200 _r8
pavone@193 201 _r9
pavone@193 202 ]
pavone@193 203 _calleesave <- #[
pavone@193 204 _rbx
pavone@193 205 _rbp
pavone@193 206 _r12
pavone@193 207 _r13
pavone@193 208 _r14
pavone@193 209 _r15
pavone@193 210 ]
pavone@193 211 _tempregs <- #[
pavone@193 212 _r10
pavone@193 213 _r11
pavone@194 214 //TODO: Add rax back in once there's logic in il to properly
pavone@194 215 //allocate it for the instances in which it's live
pavone@194 216 //_rax
pavone@193 217 ]
pavone@193 218
pavone@193 219
pavone@180 220 inst <- :ilist {
pavone@180 221 #{
pavone@180 222 length <- { ilist length }
pavone@180 223 flattenTo:at <- :dest :idx {
pavone@180 224 ilist fold: idx with: :idx byte {
pavone@180 225 dest set: idx byte
pavone@180 226 idx + 1
pavone@180 227 }
pavone@180 228 }
pavone@180 229 }
pavone@180 230 }
pavone@204 231 multiInst <- :instarr {
pavone@204 232 #{
pavone@204 233 length <- {
pavone@204 234 instarr fold: 0 with: :acc inst {
pavone@204 235 acc + (inst length)
pavone@204 236 }
pavone@204 237 }
pavone@204 238 flattenTo:at <- :dest :idx {
pavone@204 239 instarr fold: idx with: :idx inst {
pavone@204 240 inst flattenTo: dest at: idx
pavone@204 241 }
pavone@204 242 }
pavone@204 243 }
pavone@204 244 }
pavone@180 245
pavone@175 246 op:withCode:withImmed:withOpEx <- :src dst size :normal :immed :myopex {
pavone@174 247 reg <- src
pavone@174 248 rm <- dst
pavone@174 249 base <- if: (src isInteger?) {
pavone@174 250 reg <- fakesrc
pavone@175 251 (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
pavone@174 252 } else: {
pavone@174 253 if: (src register?) {
pavone@174 254 (size_bit: normal size) | (mod_rm: src dst)
pavone@174 255 } else: {
pavone@174 256 reg <- dst
pavone@174 257 rm <- src
pavone@174 258 (size_bit: normal or 0x02u8 size) | (mod_rm: dst src)
pavone@174 259 }
pavone@174 260 }
pavone@180 261 inst: (prefix: reg rm size withInstruction: base)
pavone@174 262 }
pavone@174 263
pavone@175 264 op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt {
pavone@175 265 reg <- src
pavone@175 266 rm <- dst
pavone@175 267 if: (src isInteger?) {
pavone@175 268 reg <- fakesrc
pavone@175 269 base <- if: size > byte && (((src signed?) && src < 128 && src >= -128) || ((not: (src signed?)) && src < 256)) {
pavone@179 270 byteExt | (mod_rm: (opex: myopex) dst withTail: [(uint8: src)])
pavone@175 271 } else: {
pavone@175 272 if: dst = _rax {
pavone@175 273 (size_bit: immedRax size) | (int_op: src size)
pavone@175 274 } else: {
pavone@175 275 (size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
pavone@175 276 }
pavone@175 277 }
pavone@180 278 inst: (prefix: reg rm size withInstruction: base)
pavone@175 279 } else: {
pavone@175 280 op: src dst size withCode: normal withImmed: immed withOpEx: myopex
pavone@175 281 }
pavone@175 282 }
pavone@175 283
pavone@204 284 shiftRot:withOpEx <- :amount dst size :myopex {
pavone@204 285 opcode <- 0u8
pavone@204 286 tail <- []
pavone@204 287 pre <- #[]
pavone@204 288 post <- #[]
pavone@204 289 base <- if: (amount isInteger?) {
pavone@204 290 if: amount = 1 {
pavone@204 291 opcode <- 0xD0u8
pavone@204 292 } else: {
pavone@204 293 opcode <- 0xC0u8
pavone@204 294 tail <- [uint8: amount]
pavone@204 295 }
pavone@204 296 } else: {
pavone@204 297 opcode <- 0xD2u8
pavone@204 298 if: (not: _rcx = amount) {
pavone@204 299 pre <- #[
pavone@204 300 x86 push: _rcx
pavone@204 301 x86 mov: amount _rcx byte
pavone@204 302 ]
pavone@204 303 post <- #[
pavone@204 304 x86 pop: _rcx
pavone@204 305 ]
pavone@204 306 }
pavone@204 307 }
pavone@204 308 bytes <- prefix: fakesrc dst withInstruction: (size_bit: 0xC0u8 size) | (mod_rm: (opex: myopex) dst withTail: tail)
pavone@204 309 myinst <- inst: bytes
pavone@204 310 if: (pre length) > 0 {
pavone@204 311 pre append: myinst
pavone@204 312 foreach: post :_ inst {
pavone@204 313 pre append: inst
pavone@204 314 }
pavone@204 315 multiInst: pre
pavone@204 316 } else: {
pavone@204 317 myinst
pavone@204 318 }
pavone@204 319 }
pavone@204 320
pavone@183 321 _jmprel <- :op jmpDest {
pavone@183 322 }
pavone@183 323
pavone@174 324 #{
pavone@174 325 rax <- { _rax }
pavone@174 326 rcx <- { _rcx }
pavone@174 327 rdx <- { _rdx }
pavone@174 328 rbx <- { _rbx }
pavone@174 329 rsp <- { _rsp }
pavone@174 330 rbp <- { _rbp }
pavone@174 331 rsi <- { _rsi }
pavone@174 332 rdi <- { _rdi }
pavone@174 333 r8 <- { _r8 }
pavone@174 334 r9 <- { _r9 }
pavone@174 335 r10 <- { _r10 }
pavone@174 336 r11 <- { _r11 }
pavone@174 337 r12 <- { _r12 }
pavone@174 338 r13 <- { _r13 }
pavone@174 339 r14 <- { _r14 }
pavone@174 340 r15 <- { _r15 }
pavone@174 341 ah <- { _ah }
pavone@174 342 ch <- { _ch }
pavone@174 343 dh <- { _dh }
pavone@174 344 bh <- { _bh }
pavone@174 345
pavone@174 346 b <- { byte }
pavone@174 347 w <- { word }
pavone@174 348 d <- { dword }
pavone@174 349 q <- { qword }
pavone@174 350
pavone@183 351 o <- { _o }
pavone@183 352 no <- { _no }
pavone@183 353 c <- { _c }
pavone@183 354 nc <- { _nc }
pavone@183 355 ae <- { _nc }
pavone@183 356 z <- { _z }
pavone@183 357 e <- { _z }
pavone@183 358 nz <- { _nz }
pavone@183 359 ne <- { _nz }
pavone@183 360 be <- { _be }
pavone@183 361 nbe <- { _nbe }
pavone@183 362 a <- { _nbe }
pavone@183 363 s <- { _s }
pavone@183 364 ns <- { _ns }
pavone@183 365 p <- { _p }
pavone@183 366 pe <- { _p }
pavone@183 367 np <- { _np }
pavone@183 368 po <- { _np }
pavone@183 369 l <- { _l }
pavone@183 370 nl <- { _nl }
pavone@183 371 ge <- { _nl }
pavone@183 372 le <- { _le }
pavone@183 373 nle <- { _nle }
pavone@183 374 g <- { _nle }
pavone@183 375
pavone@174 376 add <- :src dst size {
pavone@174 377 op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8
pavone@174 378 }
pavone@174 379
pavone@175 380 sub <- :src dst size {
pavone@175 381 op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8
pavone@175 382 }
pavone@175 383
pavone@204 384 cmp <- :src dst size {
pavone@204 385 op: src dst size withCode: 0x38u8 withImmed: 0x80u8 withImmedRax: 0x3Cu8 withOpEx: 7u8 withByteExtend: 0x83u8
pavone@204 386 }
pavone@204 387
pavone@204 388 and <- :src dst size {
pavone@204 389 op: src dst size withCode: 0x20u8 withImmed: 0x80u8 withImmedRax: 0x24u8 withOpEx: 4u8 withByteExtend: 0x83u8
pavone@204 390 }
pavone@204 391
pavone@204 392 or <- :src dst size {
pavone@204 393 op: src dst size withCode: 0x08u8 withImmed: 0x80u8 withImmedRax: 0x0Cu8 withOpEx: 1u8 withByteExtend: 0x83u8
pavone@204 394 }
pavone@204 395
pavone@204 396 xor <- :src dst size {
pavone@204 397 op: src dst size withCode: 0x30u8 withImmed: 0x80u8 withImmedRax: 0x34u8 withOpEx: 6u8 withByteExtend: 0x83u8
pavone@204 398 }
pavone@204 399
pavone@175 400 mov <- :src dst size {
pavone@175 401 rm <- dst
pavone@175 402 if: (src isInteger?) && (dst register?) {
pavone@175 403 opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
pavone@183 404 base <- opval or (dst reg) | (int_op64: src size)
pavone@180 405 inst: (prefix: fakesrc rm size withInstruction: base)
pavone@175 406 } else: {
pavone@175 407 op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
pavone@175 408 }
pavone@175 409 }
pavone@175 410
pavone@204 411 shl <- :shift dst size {
pavone@204 412 shiftRot: shift dst size withOpEx: 4u8
pavone@204 413 }
pavone@204 414
pavone@204 415 shr <- :shift dst size {
pavone@204 416 shiftRot: shift dst size withOpEx: 5u8
pavone@204 417 }
pavone@204 418
pavone@204 419 sar <- :shift dst size {
pavone@204 420 shiftRot: shift dst size withOpEx: 7u8
pavone@204 421 }
pavone@204 422
pavone@204 423 rol <- :shift dst size {
pavone@204 424 shiftRot: shift dst size withOpEx: 0u8
pavone@204 425 }
pavone@204 426
pavone@204 427 ror <- :shift dst size {
pavone@204 428 shiftRot: shift dst size withOpEx: 1u8
pavone@204 429 }
pavone@204 430
pavone@180 431 ret <- { inst: [ 0xC3u8 ] }
pavone@180 432
pavone@180 433 label <- {
pavone@180 434 _offset <- -1
pavone@180 435 _forwardRefs <- #[]
pavone@180 436 #{
pavone@180 437 length <- { 0 }
pavone@180 438 hasOffset? <- { _offset >= 0 }
pavone@180 439 offset <- { _offset }
pavone@180 440 register? <- { false }
pavone@181 441 label? <- { true }
pavone@180 442 flattenTo:at <- :dest :idx {
pavone@180 443 if: (not: hasOffset?) {
pavone@180 444 _offset <- idx
pavone@180 445 foreach: _forwardRefs :idx fun {
pavone@180 446 fun: _offset
pavone@180 447 }
pavone@180 448 _forwardRefs <- #[]
pavone@180 449 }
pavone@180 450 idx
pavone@180 451 }
pavone@180 452 withOffset:else <- :fun :elsefun {
pavone@180 453 if: hasOffset? {
pavone@180 454 fun: _offset
pavone@180 455 } else: {
pavone@180 456 _forwardRefs append: fun
pavone@180 457 elsefun:
pavone@180 458 }
pavone@180 459 }
pavone@180 460 }
pavone@180 461 }
pavone@180 462
pavone@180 463 jmp <- :jmpDest {
pavone@181 464 if: (jmpDest label?) {
pavone@180 465 _size <- -1
pavone@180 466 #{
pavone@180 467 length <- { if: _size < 0 { 5 } else: { _size } }
pavone@180 468 flattenTo:at <- :dest :idx {
pavone@180 469 jmpDest withOffset: :off {
pavone@180 470 if: _size < 0 {
pavone@180 471 rel <- off - (idx + 2)
pavone@180 472 if: rel < 128 && rel >= -128 {
pavone@180 473 _size <- 2
pavone@180 474 } else: {
pavone@180 475 rel <- rel - 2
pavone@180 476 if: rel < 32768 && rel >= -32768 {
pavone@180 477 _size <- 4
pavone@180 478 } else: {
pavone@180 479 _size <- 5
pavone@180 480 }
pavone@180 481 }
pavone@180 482 }
pavone@180 483 rel <- off - (idx + _size)
pavone@180 484 if: _size = 2 {
pavone@180 485 dest set: idx 0xEBu8
pavone@180 486 dest set: (idx + 1) (uint8: rel)
pavone@180 487 } else: {
pavone@180 488 if: _size = 4 {
pavone@180 489 dest set: idx 0x66u8
pavone@180 490 dest set: (idx + 1) 0xE9u8
pavone@180 491 dest set: (idx + 2) (uint8: rel)
pavone@180 492 dest set: (idx + 3) (uint8: (rshift: rel by: 8))
pavone@180 493 } else: {
pavone@180 494 dest set: idx 0xE9u8
pavone@180 495 dest set: (idx + 1) (uint8: rel)
pavone@180 496 dest set: (idx + 2) (uint8: (rshift: rel by: 8))
pavone@180 497 dest set: (idx + 3) (uint8: (rshift: rel by: 16))
pavone@180 498 dest set: (idx + 4) (uint8: (rshift: rel by: 24))
pavone@180 499 }
pavone@180 500 }
pavone@180 501 } else: {
pavone@180 502 _size <- 5
pavone@180 503 }
pavone@180 504 idx + _size
pavone@180 505 }
pavone@180 506 }
pavone@180 507 } else: {
pavone@180 508 inst: 0xFFu8 | (mod_rm: (opex: 5u8) jmpDest)
pavone@180 509 }
pavone@180 510 }
pavone@175 511
pavone@183 512 jcc <- :cond jmpDest {
pavone@183 513 _size <- -1
pavone@183 514 #{
pavone@183 515 length <- { if: _size < 0 { 5 } else: { _size } }
pavone@183 516 flattenTo:at <- :dest :idx {
pavone@183 517 jmpDest withOffset: :off {
pavone@183 518 if: _size < 0 {
pavone@183 519 rel <- off - (idx + 2)
pavone@183 520 if: rel < 128 && rel >= -128 {
pavone@183 521 _size <- 2
pavone@183 522 } else: {
pavone@183 523 _size <- 6
pavone@183 524 }
pavone@183 525 }
pavone@183 526 rel <- off - (idx + _size)
pavone@183 527 if: _size = 2 {
pavone@183 528 dest set: idx 0x70u8 or (cond cc)
pavone@183 529 dest set: (idx + 1) (uint8: rel)
pavone@183 530 } else: {
pavone@183 531 dest set: idx 0x0Fu8
pavone@183 532 dest set: (idx + 1) 0x80u8 or (cond cc)
pavone@183 533 dest set: (idx + 2) (uint8: rel)
pavone@183 534 dest set: (idx + 3) (uint8: (rshift: rel by: 8))
pavone@183 535 dest set: (idx + 4) (uint8: (rshift: rel by: 16))
pavone@183 536 dest set: (idx + 5) (uint8: (rshift: rel by: 24))
pavone@183 537 }
pavone@183 538 } else: {
pavone@183 539 _size <- 6
pavone@183 540 }
pavone@183 541 idx + _size
pavone@183 542 }
pavone@183 543 }
pavone@183 544 }
pavone@183 545
pavone@181 546 call <- :callDest {
pavone@181 547 if: (callDest label?) {
pavone@181 548 #{
pavone@181 549 length <- { 5 }
pavone@181 550 flattenTo:at <- :dest :idx {
pavone@181 551 dest set: idx 0xE8u8
pavone@181 552 callDest withOffset: :off {
pavone@181 553 rel <- off - (idx + 5)
pavone@181 554 dest set: (idx + 1) (uint8: rel)
pavone@181 555 dest set: (idx + 2) (uint8: (rshift: rel by: 8))
pavone@181 556 dest set: (idx + 3) (uint8: (rshift: rel by: 16))
pavone@181 557 dest set: (idx + 4) (uint8: (rshift: rel by: 24))
pavone@181 558 } else: {
pavone@181 559 }
pavone@181 560 idx + 5
pavone@181 561 }
pavone@181 562 }
pavone@181 563 } else: {
pavone@181 564 inst: 0xFFu8 | (mod_rm: (opex: 2u8) callDest)
pavone@181 565 }
pavone@181 566 }
pavone@174 567
pavone@183 568 push <- :src {
pavone@183 569 if: (src isInteger?) {
pavone@183 570 if: src < 128 && src > -128 {
pavone@183 571 inst: 0x6Au8 | (uint8: src)
pavone@183 572 } else: {
pavone@183 573 inst: 0x68u8 | (uint8: src) | (uint8: (rshift: src by: 8)) | (uint8: (rshift: src by: 16)) | (uint8: (rshift: src by: 24))
pavone@183 574 }
pavone@183 575 } else: {
pavone@183 576 base <- if: (src register?) {
pavone@183 577 [0x50u8 or (src reg)]
pavone@183 578 } else: {
pavone@183 579 0xFFu8 | (mod_rm: (opex: 6u8) src)
pavone@183 580 }
pavone@183 581 inst: (prefix: fakesrc src d withInstruction: base)
pavone@183 582 }
pavone@183 583 }
pavone@183 584
pavone@183 585 pop <- :dst {
pavone@183 586 base <- if: (dst register?) {
pavone@183 587 [0x58u8 or (dst reg)]
pavone@183 588 } else: {
pavone@183 589 0x8Fu8 | (mod_rm: (opex: 0u8) dst)
pavone@183 590 }
pavone@183 591 inst: (prefix: fakesrc dst d withInstruction: base)
pavone@183 592 }
pavone@183 593
pavone@204 594 bnot <- :dst size {
pavone@204 595 base <- (size_bit: 0xF6u8 size) | (mod_rm: (opex: 2u8) dst)
pavone@204 596 inst: (prefix: fakesrc dst size withInstruction: base)
pavone@204 597 }
pavone@204 598
pavone@193 599 //TODO: support multiple calling conventions
pavone@193 600 regSource <- {
pavone@193 601 _used <- 0
pavone@193 602 _usedAllTime <- 0
pavone@193 603 _nextStackOff <- 0
pavone@193 604 _findUnused <- :size reglists{
pavone@193 605 found <- -1
pavone@193 606 foundlist <- -1
pavone@193 607 curlist <- 0
pavone@193 608 ll <- reglists length
pavone@193 609 while: { found < 0 && curlist < ll } do: {
pavone@193 610 cur <- 0
pavone@193 611 regs <- reglists get: curlist
pavone@193 612 len <- regs length
pavone@193 613 while: { found < 0 && cur < len } do: {
pavone@195 614 bit <- lshift: 1 by: ((regs get: cur) num)
pavone@193 615 if: (_used and bit) = 0 {
pavone@193 616 found <- cur
pavone@193 617 foundlist <- regs
pavone@193 618 _used <- _used or bit
pavone@193 619 _usedAllTime <- _usedAllTime or bit
pavone@193 620 }
pavone@193 621 cur <- cur + 1
pavone@193 622 }
pavone@193 623 curlist <- curlist + 1
pavone@193 624 }
pavone@193 625 if: found >= 0 {
pavone@193 626 foundlist get: found
pavone@193 627 } else: {
pavone@193 628 myoff <- _nextStackOff
pavone@193 629 _nextStackOff <- _nextStackOff + size
pavone@193 630 il base: _rsp offset: myoff
pavone@193 631 }
pavone@193 632 }
pavone@193 633 #{
pavone@193 634 alloc <- :size {
pavone@193 635 _findUnused: size #[
pavone@193 636 _calleesave
pavone@193 637 _tempregs
pavone@193 638 _argregs
pavone@193 639 ]
pavone@193 640 }
pavone@193 641 //used to allocate a register
pavone@193 642 //that will be returned before a call
pavone@193 643 allocTemp <- :size {
pavone@193 644 _findUnused: size #[
pavone@193 645 _tempregs
pavone@193 646 _argregs
pavone@193 647 _calleesave
pavone@193 648 ]
pavone@193 649 }
pavone@193 650 //allocated the return register
pavone@194 651 allocRet <- {
pavone@193 652 bit <- (lshift: 1 by: (_rax num))
pavone@193 653 _used <- _used or bit
pavone@193 654 _usedAllTime <- _usedAllTime or bit
pavone@193 655 _rax
pavone@193 656 }
pavone@193 657 allocArg <- :argnum {
pavone@193 658 if: argnum < (_argregs length) {
pavone@193 659 reg <- _argregs get: argnum
pavone@193 660 bit <- (lshift: 1 by: (reg num))
pavone@193 661 _used <- _used or bit
pavone@193 662 _usedAllTime <- _usedAllTime or bit
pavone@194 663 reg
pavone@193 664 } else: {
pavone@193 665 il base: _rsp offset: _nextStackOff + 8 * (argnum - (_argregs length))
pavone@193 666 }
pavone@193 667 }
pavone@193 668 allocSpecific <- :reg {
pavone@193 669 if: (reg register?) {
pavone@193 670 bit <- (lshift: 1 by: (reg num))
pavone@193 671 _used <- _used or bit
pavone@193 672 }
pavone@193 673 }
pavone@193 674 stackSize <- { _nextStackOff }
pavone@193 675 return <- :reg {
pavone@193 676 _used <- _used and (0xF xor (lshift: 1 by: (reg num)))
pavone@193 677 }
pavone@198 678 returnAll <- { _used <- 0 }
pavone@193 679 needSaveProlog <- {
pavone@193 680 retval <- #[]
pavone@193 681 foreach: _calleesave :idx reg {
pavone@195 682 bit <- lshift: 1 by: (reg num)
pavone@195 683 if: (_usedAllTime and bit) != 0 {
pavone@193 684 retval append: reg
pavone@193 685 }
pavone@193 686 }
pavone@193 687 retval
pavone@193 688 }
pavone@193 689 needSaveForCall <- {
pavone@193 690 retval <- #[]
pavone@198 691 foreach: #[(_tempregs) (_argregs)] :_ regs {
pavone@193 692 foreach: regs :_ reg {
pavone@193 693 if: (_used and (lshift: 1 by: (reg num))) != 0 {
pavone@193 694 retval append: reg
pavone@193 695 }
pavone@193 696 }
pavone@193 697 }
pavone@193 698 retval
pavone@193 699 }
pavone@193 700 }
pavone@193 701 }
pavone@193 702
pavone@203 703 adjustIL <- :ilfun {
pavone@203 704 il to2Op: (il allocRegs: ilfun withSource: regSource)
pavone@203 705 }
pavone@203 706
pavone@203 707 convertIL:to:withLabels:withSaved <- :inst :outarr :labels :saved {
pavone@203 708 mapSize <- :ilsize {
pavone@203 709 if: (ilsize bytes) > 2 {
pavone@203 710 if: (ilsize bytes) = 8 { q } else: { d }
pavone@203 711 } else: {
pavone@203 712 if: (ilsize bytes) = 1 { b } else: { w }
pavone@203 713 }
pavone@203 714 }
pavone@203 715 mapcond <- :ilcond {
pavone@203 716 ccmap <- #[
pavone@203 717 e
pavone@203 718 ne
pavone@203 719 ge
pavone@203 720 le
pavone@203 721 g
pavone@203 722 l
pavone@203 723 ae
pavone@203 724 be
pavone@203 725 a
pavone@203 726 c
pavone@203 727 ]
pavone@203 728 ccmap get: (ilcond cc)
pavone@203 729 }
pavone@203 730 opmap <- #[
pavone@203 731 { outarr append: (add: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 732 { outarr append: (and: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 733 { outarr append: (or: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 734 { outarr append: (xor: (inst in) (inst out) (mapSize: (inst size))) }
pavone@203 735 { outarr append: (sub: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 736 { outarr append: (cmp: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 737 { outarr append: (bnot: (inst arg) (mapSize: (inst size))) }
pavone@204 738 { outarr append: (shl: (inst in) (inst out) (mapSize: (inst size))) } //sl
pavone@204 739 { outarr append: (sar: (inst in) (inst out) (mapSize: (inst size))) } //asr
pavone@204 740 { outarr append: (shr: (inst in) (inst out) (mapSize: (inst size))) } //lsr
pavone@204 741 { outarr append: (rol: (inst in) (inst out) (mapSize: (inst size))) }
pavone@204 742 { outarr append: (ror: (inst in) (inst out) (mapSize: (inst size))) }
pavone@203 743 { outarr append: (mov: (inst in) (inst out) (mapSize: (inst size))) }
pavone@203 744 {
pavone@203 745 //call
pavone@203 746 arguments <- inst args
pavone@203 747 cur <- (arguments length) - 1
pavone@203 748 while: { cur >= 0 } do: {
pavone@203 749 src <- (arguments get: cur)
pavone@203 750 if: cur < (_argregs length) {
pavone@203 751 dst <- _argregs get: cur
pavone@203 752 if: (not: dst = src) {
pavone@203 753 //TODO: Handle edge case in which src is a caller saved
pavone@203 754 //reg that has been pusehd onto the stack to preserve
pavone@203 755 //it across this call
pavone@203 756 outarr append: (mov: src dst q)
pavone@203 757 }
pavone@203 758 } else: {
pavone@203 759 outarr append: (push: src)
pavone@203 760 }
pavone@203 761 cur <- cur - 1
pavone@203 762 }
pavone@203 763 toCall <- inst target
pavone@203 764 if: (toCall isString?) {
pavone@203 765 //TODO: Handle call to undefined label
pavone@203 766 toCall <- labels get: toCall
pavone@203 767 }
pavone@203 768 outarr append: (call: toCall)
pavone@203 769 }
pavone@203 770 {
pavone@203 771 //return
pavone@203 772 if: (not: _rax = (inst arg)) {
pavone@203 773 outarr append: (mov: (inst arg) _rax q)
pavone@203 774 }
pavone@203 775 foreach: saved :_ reg {
pavone@203 776 outarr append: (pop: reg)
pavone@203 777 }
pavone@203 778 outarr append: (ret: )
pavone@203 779 }
pavone@203 780 {
pavone@203 781 //skipIf
pavone@203 782 endlab <- label:
pavone@203 783 outarr append: (jcc: (mapcond: (inst cond)) endlab)
pavone@203 784 foreach: (inst toskip) :_ inst {
pavone@203 785 convertIL: inst to: outarr withLabels: labels withSaved: saved
pavone@203 786 }
pavone@203 787 outarr append: endlab
pavone@203 788 }
pavone@203 789 {
pavone@203 790 //save
pavone@203 791 newsave <- []
pavone@203 792 foreach: (inst tosave) :_ reg {
pavone@203 793 outarr append: (push: reg)
pavone@203 794 newsave <- reg | newsave
pavone@203 795 }
pavone@203 796 foreach: (inst scope) :_ inst {
pavone@203 797 convertIL: inst to: outarr withLabels: labels withSaved: newsave
pavone@203 798 }
pavone@203 799 if: ((inst scope) length) = 0 || (((inst scope) get: ((inst scope) length) - 1) opcode) != 14 {
pavone@203 800 foreach: newsave :_ reg {
pavone@203 801 outarr append: (pop: reg)
pavone@203 802 }
pavone@203 803 }
pavone@203 804 }
pavone@203 805 ]
pavone@203 806 fun <- opmap get: (inst opcode)
pavone@203 807 fun:
pavone@203 808 outarr
pavone@203 809 }
pavone@203 810
pavone@203 811 convertIL:to:withLabels <- :inst :outarr :labels {
pavone@203 812 convertIL: inst to: outarr withLabels: labels withSaved: []
pavone@203 813 }
pavone@203 814
pavone@174 815 main <- {
pavone@183 816 fib <- label:
pavone@183 817 notbase <- label:
pavone@179 818 prog <- #[
pavone@183 819 fib
pavone@183 820 sub: 2 rdi q
pavone@183 821 jcc: ge notbase
pavone@183 822 mov: 1 rax q
pavone@183 823 ret:
pavone@183 824
pavone@183 825 notbase
pavone@183 826 push: rdi
pavone@183 827 call: fib
pavone@183 828 pop: rdi
pavone@183 829 push: rax
pavone@183 830 add: 1 rdi q
pavone@183 831 call: fib
pavone@183 832 pop: rdi
pavone@179 833 add: rdi rax q
pavone@181 834 ret:
pavone@179 835 ]
pavone@180 836
pavone@179 837 ba <- bytearray executableFromBytes: prog
pavone@183 838 res <- ba runWithArg: 30u64
pavone@179 839 print: (string: res) . "\n"
pavone@174 840 0
pavone@174 841 }
pavone@174 842 }
pavone@174 843 }