diff --git a/src/backend_x64/emit_x64_data_processing.cpp b/src/backend_x64/emit_x64_data_processing.cpp index 2c187f68..489d60b1 100644 --- a/src/backend_x64/emit_x64_data_processing.cpp +++ b/src/backend_x64/emit_x64_data_processing.cpp @@ -901,6 +901,28 @@ void EmitX64::EmitMul64(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(inst, result); } +void EmitX64::EmitUnsignedMultiplyHigh64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.ScratchGpr({HostLoc::RDX}); + ctx.reg_alloc.UseScratch(args[0], HostLoc::RAX); + OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]); + code.mul(*op_arg); + + ctx.reg_alloc.DefineValue(inst, rdx); +} + +void EmitX64::EmitSignedMultiplyHigh64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + + ctx.reg_alloc.ScratchGpr({HostLoc::RDX}); + ctx.reg_alloc.UseScratch(args[0], HostLoc::RAX); + OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]); + code.imul(*op_arg); + + ctx.reg_alloc.DefineValue(inst, rdx); +} + void EmitX64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 60685608..b4a6e104 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -299,10 +299,10 @@ INST(MADD, "MADD", "z0011 INST(MSUB, "MSUB", "z0011011000mmmmm1aaaaannnnnddddd") INST(SMADDL, "SMADDL", "10011011001mmmmm0aaaaannnnnddddd") INST(SMSUBL, "SMSUBL", "10011011001mmmmm1aaaaannnnnddddd") -//INST(SMULH, "SMULH", "10011011010mmmmm011111nnnnnddddd") +INST(SMULH, "SMULH", "10011011010mmmmm011111nnnnnddddd") INST(UMADDL, "UMADDL", "10011011101mmmmm0aaaaannnnnddddd") INST(UMSUBL, "UMSUBL", "10011011101mmmmm1aaaaannnnnddddd") -//INST(UMULH, "UMULH", "10011011110mmmmm011111nnnnnddddd") +INST(UMULH, "UMULH", "10011011110mmmmm011111nnnnnddddd") // Data Processing - FP and SIMD - AES INST(AESE, "AESE", "0100111000101000010010nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/data_processing_multiply.cpp b/src/frontend/A64/translate/impl/data_processing_multiply.cpp index 16c4b9c1..2d13b6ab 100644 --- a/src/frontend/A64/translate/impl/data_processing_multiply.cpp +++ b/src/frontend/A64/translate/impl/data_processing_multiply.cpp @@ -56,6 +56,16 @@ bool TranslatorVisitor::SMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { return true; } +bool TranslatorVisitor::SMULH(Reg Rm, Reg Rn, Reg Rd) { + const IR::U64 m = X(64, Rm); + const IR::U64 n = X(64, Rn); + + const IR::U64 result = ir.SignedMultiplyHigh(n, m); + + X(64, Rd, result); + return true; +} + bool TranslatorVisitor::UMADDL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { const IR::U64 a = X(64, Ra); const IR::U64 m = ir.ZeroExtendToLong(X(32, Rm)); @@ -78,6 +88,16 @@ bool TranslatorVisitor::UMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { return true; } +bool TranslatorVisitor::UMULH(Reg Rm, Reg Rn, Reg Rd) { + const IR::U64 m = X(64, Rm); + const IR::U64 n = X(64, Rn); + + const IR::U64 result = ir.UnsignedMultiplyHigh(n, m); + + X(64, Rd, result); + return true; +} + bool TranslatorVisitor::UDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) { const size_t datasize = sf ? 64 : 32; diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 8db9736f..ded7f2d1 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -280,6 +280,14 @@ U32U64 IREmitter::Mul(const U32U64& a, const U32U64& b) { return Inst(Opcode::Mul64, a, b); } +U64 IREmitter::UnsignedMultiplyHigh(const U64& a, const U64& b) { + return Inst(Opcode::UnsignedMultiplyHigh64, a, b); +} + +U64 IREmitter::SignedMultiplyHigh(const U64& a, const U64& b) { + return Inst(Opcode::SignedMultiplyHigh64, a, b); +} + U32 IREmitter::UnsignedDiv(const U32& a, const U32& b) { return Inst(Opcode::UnsignedDiv32, a, b); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index ecfd9c1b..1c5cc261 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -112,6 +112,8 @@ public: U32 Mul(const U32& a, const U32& b); U64 Mul(const U64& a, const U64& b); U32U64 Mul(const U32U64& a, const U32U64& b); + U64 UnsignedMultiplyHigh(const U64& a, const U64& b); + U64 SignedMultiplyHigh(const U64& a, const U64& b); U32 UnsignedDiv(const U32& a, const U32& b); U64 UnsignedDiv(const U64& a, const U64& b); U32U64 UnsignedDiv(const U32U64& a, const U32U64& b); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 538f76e9..8a04a217 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -98,6 +98,8 @@ OPCODE(Sub32, T::U32, T::U32, T::U32, OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 ) OPCODE(Mul32, T::U32, T::U32, T::U32 ) OPCODE(Mul64, T::U64, T::U64, T::U64 ) +OPCODE(SignedMultiplyHigh64, T::U64, T::U64, T::U64 ) +OPCODE(UnsignedMultiplyHigh64, T::U64, T::U64, T::U64 ) OPCODE(UnsignedDiv32, T::U32, T::U32, T::U32 ) OPCODE(UnsignedDiv64, T::U64, T::U64, T::U64 ) OPCODE(SignedDiv32, T::U32, T::U32, T::U32 )