| @@ -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 | 448 | ST_FUNC void asm_opcode(TCCState *s1, int token) |
| 290 | 449 | { |
| 291 | 450 | while (token == TOK_LINEFEED) { |
| @@ -315,6 +474,22 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 23 unmodified lines |
| 315 | 474 | case TOK_ASM_uxtbeq: |
| 316 | 475 | case TOK_ASM_uxtheq: |
| 317 | 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 | 493 | default: |
| 319 | 494 | expect("known instruction"); |
| 320 | 495 | } |