From 3fdc093d1075db549446d5fa8c497af2bd5f82f5 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 4 Aug 2016 22:04:42 +0100 Subject: [PATCH] Add more IR opcodes for multiply instructions Pack2x32To1x64, LeastSignificantWord, MostSignificantWord, IsZero64, Add64, Mul, Mul64, SignExtendWordToLong, ZeroExtendWordToLong --- src/backend_x64/emit_x64.cpp | 73 ++++++++++++++++++++++++++++++++++ src/frontend/ir/ir_emitter.cpp | 51 ++++++++++++++++++++++++ src/frontend/ir/ir_emitter.h | 11 +++++ src/frontend/ir/opcodes.inc | 9 +++++ 4 files changed, 144 insertions(+) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 68e2e62a..673dcfd5 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -272,6 +272,23 @@ void EmitX64::EmitGetOverflowFromOp(IR::Block&, IR::Inst*) { ASSERT_MSG(0, "should never happen"); } +void EmitX64::EmitPack2x32To1x64(IR::Block&, IR::Inst* inst) { + auto lo = reg_alloc.UseRegister(inst->GetArg(0), any_gpr); + auto hi = reg_alloc.UseDefRegister(inst->GetArg(1), inst, any_gpr); + code->SHL(64, R(hi), Imm8(32)); + code->OR(64, R(hi), R(lo)); +} + +void EmitX64::EmitLeastSignificantWord(IR::Block&, IR::Inst* inst) { + // TODO: Optimize + reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); +} + +void EmitX64::EmitMostSignificantWord(IR::Block&, IR::Inst* inst) { + auto u64 = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); + code->SHR(64, R(u64), Imm8(32)); +} + void EmitX64::EmitLeastSignificantHalf(IR::Block&, IR::Inst* inst) { // TODO: Optimize @@ -302,6 +319,16 @@ void EmitX64::EmitIsZero(IR::Block&, IR::Inst* inst) { code->MOVZX(32, 8, result, R(result)); } +void EmitX64::EmitIsZero64(IR::Block&, IR::Inst* inst) { + X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); + + // TODO: Flag optimization + + code->TEST(64, R(result), R(result)); + code->SETcc(CCFlags::CC_E, R(result)); + code->MOVZX(32, 8, result, R(result)); +} + void EmitX64::EmitLogicalShiftLeft(IR::Block& block, IR::Inst* inst) { auto carry_inst = FindUseWithOpcode(inst, IR::Opcode::GetCarryFromOp); @@ -706,6 +733,16 @@ void EmitX64::EmitAddWithCarry(IR::Block& block, IR::Inst* inst) { } } +void EmitX64::EmitAdd64(IR::Block& block, IR::Inst* inst) { + IR::Value a = inst->GetArg(0); + IR::Value b = inst->GetArg(1); + + X64Reg result = reg_alloc.UseDefRegister(a, inst, any_gpr); + OpArg op_arg = R(reg_alloc.UseRegister(b, any_gpr)); + + code->ADD(64, R(result), op_arg); +} + void EmitX64::EmitSubWithCarry(IR::Block& block, IR::Inst* inst) { auto carry_inst = FindUseWithOpcode(inst, IR::Opcode::GetCarryFromOp); auto overflow_inst = FindUseWithOpcode(inst, IR::Opcode::GetOverflowFromOp); @@ -751,6 +788,28 @@ void EmitX64::EmitSubWithCarry(IR::Block& block, IR::Inst* inst) { } } +void EmitX64::EmitMul(IR::Block&, IR::Inst* inst) { + IR::Value a = inst->GetArg(0); + IR::Value b = inst->GetArg(1); + if (a.IsImmediate()) + std::swap(a, b); + X64Reg result = reg_alloc.UseDefRegister(a, inst, any_gpr); + if (b.IsImmediate()) { + code->IMUL(32, result, R(result), Imm32(b.GetU32())); + } else { + OpArg op_arg = R(reg_alloc.UseRegister(b.GetInst(), any_gpr)); + code->IMUL(32, result, op_arg); + } +} + +void EmitX64::EmitMul64(IR::Block&, IR::Inst* inst) { + IR::Value a = inst->GetArg(0); + IR::Value b = inst->GetArg(1); + X64Reg result = reg_alloc.UseDefRegister(a, inst, any_gpr); + OpArg op_arg = R(reg_alloc.UseRegister(b.GetInst(), any_gpr)); + code->IMUL(64, result, op_arg); +} + void EmitX64::EmitAnd(IR::Block&, IR::Inst* inst) { IR::Value a = inst->GetArg(0); IR::Value b = inst->GetArg(1); @@ -801,6 +860,13 @@ void EmitX64::EmitNot(IR::Block&, IR::Inst* inst) { } } +void EmitX64::EmitSignExtendWordToLong(IR::Block&, IR::Inst* inst) { + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); + + code->MOVSX(64, 32, result, R(result)); +} + void EmitX64::EmitSignExtendHalfToWord(IR::Block&, IR::Inst* inst) { // TODO: Remove unnecessary mov that may occur here X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); @@ -815,6 +881,13 @@ void EmitX64::EmitSignExtendByteToWord(IR::Block&, IR::Inst* inst) { code->MOVSX(32, 8, result, R(result)); } +void EmitX64::EmitZeroExtendWordToLong(IR::Block&, IR::Inst* inst) { + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); + + code->MOVZX(64, 32, result, R(result)); +} + void EmitX64::EmitZeroExtendHalfToWord(IR::Block&, IR::Inst* inst) { // TODO: Remove unnecessary mov that may occur here X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index d025d1d5..bdaf854a 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -98,6 +98,19 @@ void IREmitter::SetVFlag(const IR::Value& value) { Inst(IR::Opcode::SetVFlag, {value}); } +IR::Value IREmitter::Pack2x32To1x64(const IR::Value& lo, const IR::Value& hi) +{ + return Inst(IR::Opcode::Pack2x32To1x64, {lo, hi}); +} + +IR::Value IREmitter::LeastSignificantWord(const IR::Value& value) { + return Inst(IR::Opcode::LeastSignificantWord, {value}); +} + +IR::Value IREmitter::MostSignificantWord(const IR::Value& value) { + return Inst(IR::Opcode::MostSignificantWord, {value}); +} + IR::Value IREmitter::LeastSignificantHalf(const IR::Value& value) { return Inst(IR::Opcode::LeastSignificantHalf, {value}); } @@ -114,6 +127,10 @@ IR::Value IREmitter::IsZero(const IR::Value& value) { return Inst(IR::Opcode::IsZero, {value}); } +IR::Value IREmitter::IsZero64(const IR::Value& value) { + return Inst(IR::Opcode::IsZero64, {value}); +} + IREmitter::ResultAndCarry IREmitter::LogicalShiftLeft(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in) { auto result = Inst(IR::Opcode::LogicalShiftLeft, {value_in, shift_amount, carry_in}); auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result}); @@ -155,6 +172,10 @@ IR::Value IREmitter::Add(const IR::Value& a, const IR::Value& b) { return Inst(IR::Opcode::AddWithCarry, {a, b, Imm1(0)}); } +IR::Value IREmitter::Add64(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::Add64, {a, b}); +} + IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in) { // This is equivalent to AddWithCarry(a, Not(b), carry_in). auto result = Inst(IR::Opcode::SubWithCarry, {a, b, carry_in}); @@ -167,6 +188,28 @@ IR::Value IREmitter::Sub(const IR::Value& a, const IR::Value& b) { return Inst(IR::Opcode::SubWithCarry, {a, b, Imm1(1)}); } +IR::Value IREmitter::Mul(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::Mul, {a, b}); +} + +IR::Value IREmitter::Mul64(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::Mul64, {a, b}); +} + +IR::Value IREmitter::SignedMulHi(const IR::Value& a, const IR::Value& b) { + auto a64 = ZeroExtendWordToLong(a); + auto b64 = ZeroExtendWordToLong(b); + auto product64 = Mul64(a64, b64); + return LogicalShiftRight(product64, Imm8(32), Imm8(0)).result; +} + +IR::Value IREmitter::UnsignedMulHi(const IR::Value& a, const IR::Value& b) { + auto a64 = SignExtendWordToLong(a); + auto b64 = SignExtendWordToLong(b); + auto product64 = Mul64(a64, b64); + return LogicalShiftRight(product64, Imm8(32), Imm8(0)).result; +} + IR::Value IREmitter::And(const IR::Value& a, const IR::Value& b) { return Inst(IR::Opcode::And, {a, b}); } @@ -183,6 +226,10 @@ IR::Value IREmitter::Not(const IR::Value& a) { return Inst(IR::Opcode::Not, {a}); } +IR::Value IREmitter::SignExtendWordToLong(const IR::Value& a) { + return Inst(IR::Opcode::SignExtendWordToLong, {a}); +} + IR::Value IREmitter::SignExtendHalfToWord(const IR::Value& a) { return Inst(IR::Opcode::SignExtendHalfToWord, {a}); } @@ -191,6 +238,10 @@ IR::Value IREmitter::SignExtendByteToWord(const IR::Value& a) { return Inst(IR::Opcode::SignExtendByteToWord, {a}); } +IR::Value IREmitter::ZeroExtendWordToLong(const IR::Value& a) { + return Inst(IR::Opcode::ZeroExtendWordToLong, {a}); +} + IR::Value IREmitter::ZeroExtendHalfToWord(const IR::Value& a) { return Inst(IR::Opcode::ZeroExtendHalfToWord, {a}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 202c12f3..b63b86c2 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -54,10 +54,14 @@ public: void SetCFlag(const IR::Value& value); void SetVFlag(const IR::Value& value); + IR::Value Pack2x32To1x64(const IR::Value& lo, const IR::Value& hi); + IR::Value LeastSignificantWord(const IR::Value& value); + IR::Value MostSignificantWord(const IR::Value& value); IR::Value LeastSignificantHalf(const IR::Value& value); IR::Value LeastSignificantByte(const IR::Value& value); IR::Value MostSignificantBit(const IR::Value& value); IR::Value IsZero(const IR::Value& value); + IR::Value IsZero64(const IR::Value& value); ResultAndCarry LogicalShiftLeft(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in); ResultAndCarry LogicalShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in); @@ -66,14 +70,21 @@ public: ResultAndCarry RotateRightExtended(const IR::Value& value_in, const IR::Value& carry_in); ResultAndCarryAndOverflow AddWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in); IR::Value Add(const IR::Value& a, const IR::Value& b); + IR::Value Add64(const IR::Value& a, const IR::Value& b); ResultAndCarryAndOverflow SubWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in); IR::Value Sub(const IR::Value& a, const IR::Value& b); + IR::Value Mul(const IR::Value& a, const IR::Value& b); + IR::Value Mul64(const IR::Value& a, const IR::Value& b); + IR::Value SignedMulHi(const IR::Value& a, const IR::Value& b); + IR::Value UnsignedMulHi(const IR::Value& a, const IR::Value& b); IR::Value And(const IR::Value& a, const IR::Value& b); IR::Value Eor(const IR::Value& a, const IR::Value& b); IR::Value Or(const IR::Value& a, const IR::Value& b); IR::Value Not(const IR::Value& a); + IR::Value SignExtendWordToLong(const IR::Value& a); IR::Value SignExtendHalfToWord(const IR::Value& a); IR::Value SignExtendByteToWord(const IR::Value& a); + IR::Value ZeroExtendWordToLong(const IR::Value& a); IR::Value ZeroExtendHalfToWord(const IR::Value& a); IR::Value ZeroExtendByteToWord(const IR::Value& a); IR::Value ByteReverseWord(const IR::Value& a); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index a1f2754c..ea21f66f 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -21,10 +21,14 @@ OPCODE(GetCarryFromOp, T::U1, T::U32 OPCODE(GetOverflowFromOp, T::U1, T::U32 ) // Calculations +OPCODE(Pack2x32To1x64, T::U64, T::U32, T::U32 ) +OPCODE(LeastSignificantWord, T::U32, T::U64 ) +OPCODE(MostSignificantWord, T::U32, T::U64 ) OPCODE(LeastSignificantHalf, T::U16, T::U32 ) OPCODE(LeastSignificantByte, T::U8, T::U32 ) OPCODE(MostSignificantBit, T::U1, T::U32 ) OPCODE(IsZero, T::U1, T::U32 ) +OPCODE(IsZero64, T::U1, T::U64 ) OPCODE(LogicalShiftLeft, T::U32, T::U32, T::U8, T::U1 ) OPCODE(LogicalShiftRight, T::U32, T::U32, T::U8, T::U1 ) OPCODE(ArithmeticShiftRight, T::U32, T::U32, T::U8, T::U1 ) @@ -32,12 +36,17 @@ OPCODE(RotateRight, T::U32, T::U32, T::U8, OPCODE(RotateRightExtended, T::U32, T::U32, T::U1 ) OPCODE(AddWithCarry, T::U32, T::U32, T::U32, T::U1 ) OPCODE(SubWithCarry, T::U32, T::U32, T::U32, T::U1 ) +OPCODE(Add64, T::U64, T::U64, T::U64 ) +OPCODE(Mul, T::U32, T::U32, T::U32 ) +OPCODE(Mul64, T::U64, T::U64, T::U64 ) OPCODE(And, T::U32, T::U32, T::U32 ) OPCODE(Eor, T::U32, T::U32, T::U32 ) OPCODE(Or, T::U32, T::U32, T::U32 ) OPCODE(Not, T::U32, T::U32 ) +OPCODE(SignExtendWordToLong, T::U64, T::U32 ) OPCODE(SignExtendHalfToWord, T::U32, T::U16 ) OPCODE(SignExtendByteToWord, T::U32, T::U8 ) +OPCODE(ZeroExtendWordToLong, T::U64, T::U32 ) OPCODE(ZeroExtendHalfToWord, T::U32, T::U16 ) OPCODE(ZeroExtendByteToWord, T::U32, T::U8 ) OPCODE(ByteReverseWord, T::U32, T::U32 )