| @@ -286,6 +286,165 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token) · 285 unmodified lines |
| 286 | } | 286 | } |
| 287 | } | 287 | } |
| 288 | | 288 | |
| | 289 | static void asm_multiplication_opcode(TCCState *s1, int token) |
| | 290 | { |
| | 291 | Operand ops[4]; |
| | 292 | int nb_ops = 0; |
| | 293 | uint32_t opcode = 0x90; |
| | 294 | |
| | 295 | for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) { |
| | 296 | parse_operand(s1, &ops[nb_ops]); |
| | 297 | if (tok != ',') { |
| | 298 | ++nb_ops; |
| | 299 | break; |
| | 300 | } |
| | 301 | next(); // skip ',' |
| | 302 | } |
| | 303 | if (nb_ops < 2) |
| | 304 | expect("at least two operands"); |
| | 305 | else if (nb_ops == 2) { |
| | 306 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 307 | case TOK_ASM_mulseq: |
| | 308 | case TOK_ASM_muleq: |
| | 309 | memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this! |
| | 310 | break; |
| | 311 | default: |
| | 312 | memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2] |
| | 313 | memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit |
| | 314 | } |
| | 315 | nb_ops = 3; |
| | 316 | } |
| | 317 | |
| | 318 | // multiply (special case): |
| | 319 | // operands: |
| | 320 | // Rd: bits 19...16 |
| | 321 | // Rm: bits 3...0 |
| | 322 | // Rs: bits 11...8 |
| | 323 | // Rn: bits 15...12 |
| | 324 | |
| | 325 | if (ops[0].type == OP_REG32) |
| | 326 | opcode |= ops[0].reg << 16; |
| | 327 | else |
| | 328 | expect("(destination operand) register"); |
| | 329 | if (ops[1].type == OP_REG32) |
| | 330 | opcode |= ops[1].reg; |
| | 331 | else |
| | 332 | expect("(first source operand) register"); |
| | 333 | if (ops[2].type == OP_REG32) |
| | 334 | opcode |= ops[2].reg << 8; |
| | 335 | else |
| | 336 | expect("(second source operand) register"); |
| | 337 | if (nb_ops > 3) { |
| | 338 | if (ops[3].type == OP_REG32) |
| | 339 | opcode |= ops[3].reg << 12; |
| | 340 | else |
| | 341 | expect("(third source operand) register"); |
| | 342 | } |
| | 343 | |
| | 344 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 345 | case TOK_ASM_mulseq: |
| | 346 | opcode |= 1 << 20; // Status |
| | 347 | /* fallthrough */ |
| | 348 | case TOK_ASM_muleq: |
| | 349 | if (nb_ops != 3) |
| | 350 | expect("three operands"); |
| | 351 | else { |
| | 352 | asm_emit_opcode(token, opcode); |
| | 353 | } |
| | 354 | break; |
| | 355 | case TOK_ASM_mlaseq: |
| | 356 | opcode |= 1 << 20; // Status |
| | 357 | /* fallthrough */ |
| | 358 | case TOK_ASM_mlaeq: |
| | 359 | if (nb_ops != 4) |
| | 360 | expect("four operands"); |
| | 361 | else { |
| | 362 | opcode |= 1 << 21; // Accumulate |
| | 363 | asm_emit_opcode(token, opcode); |
| | 364 | } |
| | 365 | break; |
| | 366 | default: |
| | 367 | expect("known multiplication instruction"); |
| | 368 | } |
| | 369 | } |
| | 370 | |
| | 371 | static void asm_long_multiplication_opcode(TCCState *s1, int token) |
| | 372 | { |
| | 373 | Operand ops[4]; |
| | 374 | int nb_ops = 0; |
| | 375 | uint32_t opcode = 0x90 | (1 << 23); |
| | 376 | |
| | 377 | for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) { |
| | 378 | parse_operand(s1, &ops[nb_ops]); |
| | 379 | if (tok != ',') { |
| | 380 | ++nb_ops; |
| | 381 | break; |
| | 382 | } |
| | 383 | next(); // skip ',' |
| | 384 | } |
| | 385 | if (nb_ops != 4) { |
| | 386 | expect("four operands"); |
| | 387 | return; |
| | 388 | } |
| | 389 | |
| | 390 | // long multiply (special case): |
| | 391 | // operands: |
| | 392 | // RdLo: bits 15...12 |
| | 393 | // RdHi: bits 19...16 |
| | 394 | // Rs: bits 11...8 |
| | 395 | // Rm: bits 3...0 |
| | 396 | |
| | 397 | if (ops[0].type == OP_REG32) |
| | 398 | opcode |= ops[0].reg << 12; |
| | 399 | else |
| | 400 | expect("(destination lo accumulator) register"); |
| | 401 | if (ops[1].type == OP_REG32) |
| | 402 | opcode |= ops[1].reg << 16; |
| | 403 | else |
| | 404 | expect("(destination hi accumulator) register"); |
| | 405 | if (ops[2].type == OP_REG32) |
| | 406 | opcode |= ops[2].reg; |
| | 407 | else |
| | 408 | expect("(first source operand) register"); |
| | 409 | if (ops[3].type == OP_REG32) |
| | 410 | opcode |= ops[3].reg << 8; |
| | 411 | else |
| | 412 | expect("(second source operand) register"); |
| | 413 | |
| | 414 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 415 | case TOK_ASM_smullseq: |
| | 416 | opcode |= 1 << 20; // Status |
| | 417 | /* fallthrough */ |
| | 418 | case TOK_ASM_smulleq: |
| | 419 | opcode |= 1 << 22; // signed |
| | 420 | asm_emit_opcode(token, opcode); |
| | 421 | break; |
| | 422 | case TOK_ASM_umullseq: |
| | 423 | opcode |= 1 << 20; // Status |
| | 424 | /* fallthrough */ |
| | 425 | case TOK_ASM_umulleq: |
| | 426 | asm_emit_opcode(token, opcode); |
| | 427 | break; |
| | 428 | case TOK_ASM_smlalseq: |
| | 429 | opcode |= 1 << 20; // Status |
| | 430 | /* fallthrough */ |
| | 431 | case TOK_ASM_smlaleq: |
| | 432 | opcode |= 1 << 22; // signed |
| | 433 | opcode |= 1 << 21; // Accumulate |
| | 434 | asm_emit_opcode(token, opcode); |
| | 435 | break; |
| | 436 | case TOK_ASM_umlalseq: |
| | 437 | opcode |= 1 << 20; // Status |
| | 438 | /* fallthrough */ |
| | 439 | case TOK_ASM_umlaleq: |
| | 440 | opcode |= 1 << 21; // Accumulate |
| | 441 | asm_emit_opcode(token, opcode); |
| | 442 | break; |
| | 443 | default: |
| | 444 | expect("known long multiplication instruction"); |
| | 445 | } |
| | 446 | } |
| | 447 | |
| 289 | ST_FUNC void asm_opcode(TCCState *s1, int token) | 448 | ST_FUNC void asm_opcode(TCCState *s1, int token) |
| 290 | { | 449 | { |
| 291 | while (token == TOK_LINEFEED) { | 450 | while (token == TOK_LINEFEED) { |
| @@ -315,6 +474,22 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 23 unmodified lines |
| 315 | case TOK_ASM_uxtbeq: | 474 | case TOK_ASM_uxtbeq: |
| 316 | case TOK_ASM_uxtheq: | 475 | case TOK_ASM_uxtheq: |
| 317 | return asm_binary_opcode(s1, token); | 476 | return asm_binary_opcode(s1, token); |
| | 477 | |
| | 478 | case TOK_ASM_muleq: |
| | 479 | case TOK_ASM_mulseq: |
| | 480 | case TOK_ASM_mlaeq: |
| | 481 | case TOK_ASM_mlaseq: |
| | 482 | return asm_multiplication_opcode(s1, token); |
| | 483 | |
| | 484 | case TOK_ASM_smulleq: |
| | 485 | case TOK_ASM_smullseq: |
| | 486 | case TOK_ASM_umulleq: |
| | 487 | case TOK_ASM_umullseq: |
| | 488 | case TOK_ASM_smlaleq: |
| | 489 | case TOK_ASM_smlalseq: |
| | 490 | case TOK_ASM_umlaleq: |
| | 491 | case TOK_ASM_umlalseq: |
| | 492 | return asm_long_multiplication_opcode(s1, token); |
| 318 | default: | 493 | default: |
| 319 | expect("known instruction"); | 494 | expect("known instruction"); |
| 320 | } | 495 | } |