Files
Xenia-Canary/src/xenia/cpu/ppc/ppc_emit_alu.cc

1353 lines
35 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/cpu/ppc/ppc_emit-private.h"
#include "xenia/base/assert.h"
#include "xenia/cpu/ppc/ppc_context.h"
#include "xenia/cpu/ppc/ppc_hir_builder.h"
namespace xe {
namespace cpu {
namespace ppc {
// TODO(benvanik): remove when enums redefined.
using namespace xe::cpu::hir;
using xe::cpu::hir::Value;
// Integer arithmetic (A-3)
Value* AddDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) {
return f.CompareUGT(f.Truncate(v2, INT32_TYPE),
f.Not(f.Truncate(v1, INT32_TYPE)));
}
Value* SubDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2) {
return f.Or(f.CompareUGT(f.Truncate(v1, INT32_TYPE),
f.Not(f.Neg(f.Truncate(v2, INT32_TYPE)))),
f.IsFalse(f.Truncate(v2, INT32_TYPE)));
}
// https://github.com/sebastianbiallas/pearpc/blob/0b3c823f61456faa677f6209545a7b906e797421/src/cpu/cpu_generic/ppc_tools.h#L26
Value* AddWithCarryDidCarry(PPCHIRBuilder& f, Value* v1, Value* v2, Value* v3) {
v1 = f.Truncate(v1, INT32_TYPE);
v2 = f.Truncate(v2, INT32_TYPE);
assert_true(v3->type == INT8_TYPE);
v3 = f.ZeroExtend(v3, INT32_TYPE);
return f.Or(f.CompareULT(f.Add(f.Add(v1, v2), v3), v3),
f.CompareULT(f.Add(v1, v2), v1));
}
int InstrEmit_addx(PPCHIRBuilder& f, const InstrData& i) {
// RD <- (RA) + (RB)
Value* v = f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB));
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
// e.update_xer_with_overflow(EFLAGS OF?);
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_addcx(PPCHIRBuilder& f, const InstrData& i) {
// RD <- (RA) + (RB)
// CA <- carry bit
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.Add(ra, rb);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
// e.update_xer_with_overflow(EFLAGS OF?);
} else {
f.StoreCA(AddDidCarry(f, ra, rb));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_addex(PPCHIRBuilder& f, const InstrData& i) {
// RD <- (RA) + (RB) + XER[CA]
// CA <- carry bit
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.AddWithCarry(ra, rb, f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
// e.update_xer_with_overflow(EFLAGS OF?);
} else {
f.StoreCA(AddWithCarryDidCarry(f, ra, rb, f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_addi(PPCHIRBuilder& f, const InstrData& i) {
// if RA = 0 then
// RT <- EXTS(SI)
// else
// RT <- (RA) + EXTS(SI)
Value* si = f.LoadConstantInt64(XEEXTS16(i.D.DS));
Value* v = si;
if (i.D.RA) {
v = f.Add(f.LoadGPR(i.D.RA), si);
}
f.StoreGPR(i.D.RT, v);
return 0;
}
int InstrEmit_addic(PPCHIRBuilder& f, const InstrData& i) {
// RT <- (RA) + EXTS(SI)
// CA <- carry bit
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Add(ra, f.LoadConstantInt64(XEEXTS16(i.D.DS)));
f.StoreGPR(i.D.RT, v);
f.StoreCA(AddDidCarry(f, ra, f.LoadConstantInt64(XEEXTS16(i.D.DS))));
return 0;
}
int InstrEmit_addicx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- (RA) + EXTS(SI)
// CA <- carry bit
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstantInt64(XEEXTS16(i.D.DS)));
f.StoreGPR(i.D.RT, v);
f.StoreCA(AddDidCarry(f, ra, f.LoadConstantInt64(XEEXTS16(i.D.DS))));
f.UpdateCR(0, v);
return 0;
}
int InstrEmit_addis(PPCHIRBuilder& f, const InstrData& i) {
// if RA = 0 then
// RT <- EXTS(SI) || i16.0
// else
// RT <- (RA) + EXTS(SI) || i16.0
Value* si = f.LoadConstantInt64(XEEXTS16(i.D.DS) << 16);
Value* v = si;
if (i.D.RA) {
v = f.Add(f.LoadGPR(i.D.RA), si);
}
f.StoreGPR(i.D.RT, v);
return 0;
}
int InstrEmit_addmex(PPCHIRBuilder& f, const InstrData& i) {
// RT <- (RA) + CA - 1
// CA <- carry bit
Value* ra = f.LoadGPR(i.XO.RA);
Value* v = f.AddWithCarry(ra, f.LoadConstantInt64(-1), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// With XER[SO] update too.
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
XEINSTRNOTIMPLEMENTED();
} else {
// Just CA update.
f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadConstantInt64(-1), f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_addzex(PPCHIRBuilder& f, const InstrData& i) {
// RT <- (RA) + CA
// CA <- carry bit
Value* ra = f.LoadGPR(i.XO.RA);
Value* v = f.AddWithCarry(ra, f.LoadZeroInt64(), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// With XER[SO] update too.
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
XEINSTRNOTIMPLEMENTED();
return 1;
} else {
// Just CA update.
f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadZeroInt64(), f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_divdx(PPCHIRBuilder& f, const InstrData& i) {
// dividend <- (RA)
// divisor <- (RB)
// if divisor = 0 then
// if OE = 1 then
// XER[OV] <- 1
// return
// RT <- dividend ÷ divisor
Value* divisor = f.LoadGPR(i.XO.RB);
// TODO(benvanik): check if zero
// if OE=1, set XER[OV] = 1
// else skip the divide
Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// If we are OE=1 we need to clear the overflow bit.
// e.update_xer_with_overflow(e.get_uint64(0));
XEINSTRNOTIMPLEMENTED();
return 1;
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_divdux(PPCHIRBuilder& f, const InstrData& i) {
// dividend <- (RA)
// divisor <- (RB)
// if divisor = 0 then
// if OE = 1 then
// XER[OV] <- 1
// return
// RT <- dividend ÷ divisor
Value* divisor = f.LoadGPR(i.XO.RB);
// TODO(benvanik): check if zero
// if OE=1, set XER[OV] = 1
// else skip the divide
Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor, ARITHMETIC_UNSIGNED);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// If we are OE=1 we need to clear the overflow bit.
// e.update_xer_with_overflow(e.get_uint64(0));
XEINSTRNOTIMPLEMENTED();
return 1;
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_divwx(PPCHIRBuilder& f, const InstrData& i) {
// dividend[0:31] <- (RA)[32:63]
// divisor[0:31] <- (RB)[32:63]
// if divisor = 0 then
// if OE = 1 then
// XER[OV] <- 1
// return
// RT[32:63] <- dividend ÷ divisor
// RT[0:31] <- undefined
Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE);
// TODO(benvanik): check if zero
// if OE=1, set XER[OV] = 1
// else skip the divide
Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor);
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// If we are OE=1 we need to clear the overflow bit.
// e.update_xer_with_overflow(e.get_uint64(0));
XEINSTRNOTIMPLEMENTED();
return 1;
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_divwux(PPCHIRBuilder& f, const InstrData& i) {
// dividend[0:31] <- (RA)[32:63]
// divisor[0:31] <- (RB)[32:63]
// if divisor = 0 then
// if OE = 1 then
// XER[OV] <- 1
// return
// RT[32:63] <- dividend ÷ divisor
// RT[0:31] <- undefined
Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE);
// TODO(benvanik): check if zero
// if OE=1, set XER[OV] = 1
// else skip the divide
Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor,
ARITHMETIC_UNSIGNED);
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
// If we are OE=1 we need to clear the overflow bit.
// e.update_xer_with_overflow(e.get_uint64(0));
XEINSTRNOTIMPLEMENTED();
return 1;
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulhdx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ((RA) × (RB) as 128)[0:63]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.MulHi(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB));
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulhdux(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ((RA) × (RB) as 128)[0:63]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v =
f.MulHi(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), ARITHMETIC_UNSIGNED);
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulhwx(PPCHIRBuilder& f, const InstrData& i) {
// RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.SignExtend(f.MulHi(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE),
f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE)),
INT64_TYPE);
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulhwux(PPCHIRBuilder& f, const InstrData& i) {
// RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.ZeroExtend(
f.MulHi(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE),
f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), ARITHMETIC_UNSIGNED),
INT64_TYPE);
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulldx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ((RA) × (RB))[64:127]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.Mul(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB));
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_mulli(PPCHIRBuilder& f, const InstrData& i) {
// prod[0:127] <- (RA) × EXTS(SI)
// RT <- prod[64:127]
Value* v = f.Mul(f.LoadGPR(i.D.RA), f.LoadConstantInt64(XEEXTS16(i.D.DS)));
f.StoreGPR(i.D.RT, v);
return 0;
}
int InstrEmit_mullwx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- (RA)[32:63] × (RB)[32:63]
if (i.XO.OE) {
// With XER update.
XEINSTRNOTIMPLEMENTED();
return 1;
}
Value* v = f.Mul(
f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE),
f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE));
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_negx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + 1
if (i.XO.OE) {
// With XER update.
// This is a different codepath as we need to use llvm.ssub.with.overflow.
// if RA == 0x8000000000000000 then no-op and set OV=1
// This may just magically do that...
XEINSTRNOTIMPLEMENTED();
return 1;
// Function* ssub_with_overflow = Intrinsic::getDeclaration(
// e.gen_module(), Intrinsic::ssub_with_overflow, jit_type_nint);
// jit_value_t v = b.CreateCall2(ssub_with_overflow,
// e.get_int64(0), f.LoadGPR(i.XO.RA));
// jit_value_t v0 = b.CreateExtractValue(v, 0);
// f.StoreGPR(i.XO.RT, v0);
// e.update_xer_with_overflow(b.CreateExtractValue(v, 1));
// if (i.XO.Rc) {
// // With cr0 update.
// f.UpdateCR(0, v0, e.get_int64(0), true);
//}
} else {
// No OE bit setting.
Value* v = f.Neg(f.LoadGPR(i.XO.RA));
f.StoreGPR(i.XO.RT, v);
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
}
return 0;
}
int InstrEmit_subfx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + (RB) + 1
Value* v = f.Sub(f.LoadGPR(i.XO.RB), f.LoadGPR(i.XO.RA));
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
return 1;
// e.update_xer_with_overflow(EFLAGS??);
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_subfcx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + (RB) + 1
Value* ra = f.LoadGPR(i.XO.RA);
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.Sub(rb, ra);
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
return 1;
// e.update_xer_with_overflow(EFLAGS??);
} else {
f.StoreCA(SubDidCarry(f, rb, ra));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_subficx(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + EXTS(SI) + 1
Value* ra = f.LoadGPR(i.D.RA);
Value* v = f.Sub(f.LoadConstantInt64(XEEXTS16(i.D.DS)), ra);
f.StoreGPR(i.D.RT, v);
f.StoreCA(SubDidCarry(f, f.LoadConstantInt64(XEEXTS16(i.D.DS)), ra));
return 0;
}
int InstrEmit_subfex(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + (RB) + CA
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* rb = f.LoadGPR(i.XO.RB);
Value* v = f.AddWithCarry(not_ra, rb, f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
return 1;
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(AddWithCarryDidCarry(f, not_ra, rb, f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_subfmex(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + CA - 1
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* v = f.AddWithCarry(not_ra, f.LoadConstantInt64(-1), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
return 1;
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(
AddWithCarryDidCarry(f, not_ra, f.LoadConstantInt64(-1), f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_subfzex(PPCHIRBuilder& f, const InstrData& i) {
// RT <- ¬(RA) + CA
Value* not_ra = f.Not(f.LoadGPR(i.XO.RA));
Value* v = f.AddWithCarry(not_ra, f.LoadZeroInt64(), f.LoadCA());
f.StoreGPR(i.XO.RT, v);
if (i.XO.OE) {
XEINSTRNOTIMPLEMENTED();
return 1;
// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1));
} else {
f.StoreCA(AddWithCarryDidCarry(f, not_ra, f.LoadZeroInt64(), f.LoadCA()));
}
if (i.XO.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
// Integer compare (A-4)
int InstrEmit_cmp(PPCHIRBuilder& f, const InstrData& i) {
// if L = 0 then
// a <- EXTS((RA)[32:63])
// b <- EXTS((RB)[32:63])
// else
// a <- (RA)
// b <- (RB)
// if a < b then
// c <- 0b100
// else if a > b then
// c <- 0b010
// else
// c <- 0b001
// CR[4×BF+32:4×BF+35] <- c || XER[SO]
uint32_t BF = i.X.RT >> 2;
uint32_t L = i.X.RT & 1;
Value* lhs;
Value* rhs;
if (L) {
lhs = f.LoadGPR(i.X.RA);
rhs = f.LoadGPR(i.X.RB);
} else {
lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE);
rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE);
}
f.UpdateCR(BF, lhs, rhs);
return 0;
}
int InstrEmit_cmpi(PPCHIRBuilder& f, const InstrData& i) {
// if L = 0 then
// a <- EXTS((RA)[32:63])
// else
// a <- (RA)
// if a < EXTS(SI) then
// c <- 0b100
// else if a > EXTS(SI) then
// c <- 0b010
// else
// c <- 0b001
// CR[4×BF+32:4×BF+35] <- c || XER[SO]
uint32_t BF = i.D.RT >> 2;
uint32_t L = i.D.RT & 1;
Value* lhs;
Value* rhs;
if (L) {
lhs = f.LoadGPR(i.D.RA);
rhs = f.LoadConstantInt64(XEEXTS16(i.D.DS));
} else {
lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE);
rhs = f.LoadConstantInt32(int32_t(XEEXTS16(i.D.DS)));
}
f.UpdateCR(BF, lhs, rhs);
return 0;
}
int InstrEmit_cmpl(PPCHIRBuilder& f, const InstrData& i) {
// if L = 0 then
// a <- i32.0 || (RA)[32:63]
// b <- i32.0 || (RB)[32:63]
// else
// a <- (RA)
// b <- (RB)
// if a <u b then
// c <- 0b100
// else if a >u b then
// c <- 0b010
// else
// c <- 0b001
// CR[4×BF+32:4×BF+35] <- c || XER[SO]
uint32_t BF = i.X.RT >> 2;
uint32_t L = i.X.RT & 1;
Value* lhs;
Value* rhs;
if (L) {
lhs = f.LoadGPR(i.X.RA);
rhs = f.LoadGPR(i.X.RB);
} else {
lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE);
rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE);
}
f.UpdateCR(BF, lhs, rhs, false);
return 0;
}
int InstrEmit_cmpli(PPCHIRBuilder& f, const InstrData& i) {
// if L = 0 then
// a <- i32.0 || (RA)[32:63]
// else
// a <- (RA)
// if a <u i48.0 || SI then
// c <- 0b100
// else if a >u i48.0 || SI then
// c <- 0b010
// else
// c <- 0b001
// CR[4×BF+32:4×BF+35] <- c || XER[SO]
uint32_t BF = i.D.RT >> 2;
uint32_t L = i.D.RT & 1;
Value* lhs;
Value* rhs;
if (L) {
lhs = f.LoadGPR(i.D.RA);
rhs = f.LoadConstantUint64(i.D.DS);
} else {
lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE);
rhs = f.LoadConstantUint32(i.D.DS);
}
f.UpdateCR(BF, lhs, rhs, false);
return 0;
}
// Integer logical (A-5)
int InstrEmit_andx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) & (RB)
Value* ra = f.And(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_andcx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) & ¬(RB)
Value* ra = f.AndNot(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_andix(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) & (i48.0 || UI)
Value* ra = f.And(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS)));
f.StoreGPR(i.D.RA, ra);
f.UpdateCR(0, ra);
return 0;
}
int InstrEmit_andisx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) & (i32.0 || UI || i16.0)
Value* ra =
f.And(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16));
f.StoreGPR(i.D.RA, ra);
f.UpdateCR(0, ra);
return 0;
}
int InstrEmit_cntlzdx(PPCHIRBuilder& f, const InstrData& i) {
// n <- 0
// do while n < 64
// if (RS)[n] = 1 then leave n
// n <- n + 1
// RA <- n
Value* v = f.CountLeadingZeros(f.LoadGPR(i.X.RT));
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_cntlzwx(PPCHIRBuilder& f, const InstrData& i) {
// n <- 32
// do while n < 64
// if (RS)[n] = 1 then leave n
// n <- n + 1
// RA <- n - 32
Value* v = f.CountLeadingZeros(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE));
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_eqvx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) == (RB)
Value* ra = f.Not(f.Xor(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_extsbx(PPCHIRBuilder& f, const InstrData& i) {
// s <- (RS)[56]
// RA[56:63] <- (RS)[56:63]
// RA[0:55] <- i56.s
Value* rt = f.LoadGPR(i.X.RT);
rt = f.SignExtend(f.Truncate(rt, INT8_TYPE), INT64_TYPE);
f.StoreGPR(i.X.RA, rt);
if (i.X.Rc) {
f.UpdateCR(0, rt);
}
return 0;
}
int InstrEmit_extshx(PPCHIRBuilder& f, const InstrData& i) {
// s <- (RS)[48]
// RA[48:63] <- (RS)[48:63]
// RA[0:47] <- 48.s
Value* rt = f.LoadGPR(i.X.RT);
rt = f.SignExtend(f.Truncate(rt, INT16_TYPE), INT64_TYPE);
f.StoreGPR(i.X.RA, rt);
if (i.X.Rc) {
f.UpdateCR(0, rt);
}
return 0;
}
int InstrEmit_extswx(PPCHIRBuilder& f, const InstrData& i) {
// s <- (RS)[32]
// RA[32:63] <- (RS)[32:63]
// RA[0:31] <- i32.s
Value* rt = f.LoadGPR(i.X.RT);
rt = f.SignExtend(f.Truncate(rt, INT32_TYPE), INT64_TYPE);
f.StoreGPR(i.X.RA, rt);
if (i.X.Rc) {
f.UpdateCR(0, rt);
}
return 0;
}
int InstrEmit_nandx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- ¬((RS) & (RB))
Value* ra = f.Not(f.And(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_norx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- ¬((RS) | (RB))
Value* ra = f.Not(f.Or(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_orx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) | (RB)
if (i.X.RT == i.X.RB && i.X.RT == i.X.RA && !i.X.Rc) {
// Sometimes used as no-op.
f.Nop();
return 0;
}
Value* ra;
if (i.X.RT == i.X.RB) {
ra = f.LoadGPR(i.X.RT);
} else {
ra = f.Or(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB));
}
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_orcx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) | ¬(RB)
Value* ra = f.Or(f.LoadGPR(i.X.RT), f.Not(f.LoadGPR(i.X.RB)));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_ori(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) | (i48.0 || UI)
if (!i.D.RA && !i.D.RT && !i.D.DS) {
f.Nop();
return 0;
}
Value* ra = f.Or(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS)));
f.StoreGPR(i.D.RA, ra);
return 0;
}
int InstrEmit_oris(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) | (i32.0 || UI || i16.0)
Value* ra =
f.Or(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16));
f.StoreGPR(i.D.RA, ra);
return 0;
}
int InstrEmit_xorx(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) XOR (RB)
Value* ra = f.Xor(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB));
f.StoreGPR(i.X.RA, ra);
if (i.X.Rc) {
f.UpdateCR(0, ra);
}
return 0;
}
int InstrEmit_xori(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) XOR (i48.0 || UI)
Value* ra = f.Xor(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS)));
f.StoreGPR(i.D.RA, ra);
return 0;
}
int InstrEmit_xoris(PPCHIRBuilder& f, const InstrData& i) {
// RA <- (RS) XOR (i32.0 || UI || i16.0)
Value* ra =
f.Xor(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16));
f.StoreGPR(i.D.RA, ra);
return 0;
}
// Integer rotate (A-6)
int InstrEmit_rldclx(PPCHIRBuilder& f, const InstrData& i) {
// n <- rB[58:63]
// r <- ROTL[64](rS, n)
// b <- mb[5] || mb[0:4]
// m <- MASK(b, 63)
// rA <- r & m
Value* n = f.And(f.Truncate(f.LoadGPR(i.MDS.RB), INT8_TYPE),
f.LoadConstantInt8(0x3F));
uint32_t mb = (i.MDS.MB5 << 5) | i.MDS.MB;
uint64_t m = XEMASK(mb, 63);
Value* v = f.LoadGPR(i.MDS.RT);
v = f.RotateLeft(v, n);
if (m != 0xFFFFFFFFFFFFFFFF) {
v = f.And(v, f.LoadConstantUint64(m));
}
f.StoreGPR(i.MDS.RA, v);
if (i.MDS.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rldcrx(PPCHIRBuilder& f, const InstrData& i) {
// n <- rB[58:63]
// r <- ROTL[64](rS, n)
// b <- mb[5] || mb[0:4]
// m <- MASK(0, b)
// rA <- r & m
Value* n = f.And(f.Truncate(f.LoadGPR(i.MDS.RB), INT8_TYPE),
f.LoadConstantInt8(0x3F));
uint32_t mb = (i.MDS.MB5 << 5) | i.MDS.MB;
uint64_t m = XEMASK(0, mb);
Value* v = f.LoadGPR(i.MDS.RT);
v = f.RotateLeft(v, n);
if (m != 0xFFFFFFFFFFFFFFFF) {
v = f.And(v, f.LoadConstantUint64(m));
}
f.StoreGPR(i.MDS.RA, v);
if (i.MDS.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rldicx(PPCHIRBuilder& f, const InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
int InstrEmit_rldiclx(PPCHIRBuilder& f, const InstrData& i) {
// n <- sh[5] || sh[0:4]
// r <- ROTL64((RS), n)
// b <- mb[5] || mb[0:4]
// m <- MASK(b, 63)
// RA <- r & m
uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH;
uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB;
uint64_t m = XEMASK(mb, 63);
Value* v = f.LoadGPR(i.MD.RT);
if (sh == 64 - mb) {
// srdi == rldicl ra,rs,64-n,n
v = f.Shr(v, int8_t(mb));
} else {
if (sh) {
v = f.RotateLeft(v, f.LoadConstantInt8(sh));
}
if (m != 0xFFFFFFFFFFFFFFFF) {
v = f.And(v, f.LoadConstantUint64(m));
}
}
f.StoreGPR(i.MD.RA, v);
if (i.MD.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rldicrx(PPCHIRBuilder& f, const InstrData& i) {
// n <- sh[5] || sh[0:4]
// r <- ROTL64((RS), n)
// e <- me[5] || me[0:4]
// m <- MASK(0, e)
// RA <- r & m
uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH;
uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB;
uint64_t m = XEMASK(0, mb);
Value* v = f.LoadGPR(i.MD.RT);
if (mb == 63 - sh) {
// sldi == rldicr ra,rs,n,63-n
v = f.Shl(v, int8_t(sh));
} else {
if (sh) {
v = f.RotateLeft(v, f.LoadConstantInt8(sh));
}
if (m != 0xFFFFFFFFFFFFFFFF) {
v = f.And(v, f.LoadConstantUint64(m));
}
}
f.StoreGPR(i.MD.RA, v);
if (i.MD.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rldimix(PPCHIRBuilder& f, const InstrData& i) {
// n <- sh[5] || sh[0:4]
// r <- ROTL64((RS), n)
// b <- me[5] || me[0:4]
// m <- MASK(b, ¬n)
// RA <- (r & m) | ((RA)&¬m)
uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH;
uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB;
uint64_t m = XEMASK(mb, ~sh);
Value* v = f.LoadGPR(i.MD.RT);
if (sh) {
v = f.RotateLeft(v, f.LoadConstantInt8(sh));
}
if (m != 0xFFFFFFFFFFFFFFFF) {
Value* ra = f.LoadGPR(i.MD.RA);
v = f.Or(f.And(v, f.LoadConstantUint64(m)),
f.And(ra, f.LoadConstantUint64(~m)));
}
f.StoreGPR(i.MD.RA, v);
if (i.MD.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rlwimix(PPCHIRBuilder& f, const InstrData& i) {
// n <- SH
// r <- ROTL32((RS)[32:63], n)
// m <- MASK(MB+32, ME+32)
// RA <- r&m | (RA)&¬m
Value* v = f.LoadGPR(i.M.RT);
// (x||x)
v = f.Or(f.Shl(v, 32), f.ZeroExtend(f.Truncate(v, INT32_TYPE), INT64_TYPE));
if (i.M.SH) {
v = f.RotateLeft(v, f.LoadConstantInt8(i.M.SH));
}
// Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here
// as our truncation/zero-extend does it for us.
uint64_t m = XEMASK(i.M.MB + 32, i.M.ME + 32);
if (m != 0xFFFFFFFFFFFFFFFFull) {
v = f.And(v, f.LoadConstantUint64(m));
}
v = f.Or(v, f.And(f.LoadGPR(i.M.RA), f.LoadConstantUint64(~m)));
f.StoreGPR(i.M.RA, v);
if (i.M.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rlwinmx(PPCHIRBuilder& f, const InstrData& i) {
// n <- SH
// r <- ROTL32((RS)[32:63], n)
// m <- MASK(MB+32, ME+32)
// RA <- r & m
Value* v = f.LoadGPR(i.M.RT);
// (x||x)
v = f.Or(f.Shl(v, 32), f.ZeroExtend(f.Truncate(v, INT32_TYPE), INT64_TYPE));
// TODO(benvanik): optimize srwi
// TODO(benvanik): optimize slwi
// The compiler will generate a bunch of these for the special case of SH=0.
// Which seems to just select some bits and set cr0 for use with a branch.
// We can detect this and do less work.
if (i.M.SH) {
v = f.RotateLeft(v, f.LoadConstantInt8(i.M.SH));
}
// Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here
// as our truncation/zero-extend does it for us.
uint64_t m = XEMASK(i.M.MB + 32, i.M.ME + 32);
if (m != 0xFFFFFFFFFFFFFFFFull) {
v = f.And(v, f.LoadConstantUint64(m));
}
f.StoreGPR(i.M.RA, v);
if (i.M.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_rlwnmx(PPCHIRBuilder& f, const InstrData& i) {
// n <- (RB)[59:63]
// r <- ROTL32((RS)[32:63], n)
// m <- MASK(MB+32, ME+32)
// RA <- r & m
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.M.SH), INT8_TYPE), f.LoadConstantInt8(0x1F));
Value* v = f.LoadGPR(i.M.RT);
// (x||x)
v = f.Or(f.Shl(v, 32), f.ZeroExtend(f.Truncate(v, INT32_TYPE), INT64_TYPE));
v = f.RotateLeft(v, sh);
v = f.And(v, f.LoadConstantUint64(XEMASK(i.M.MB + 32, i.M.ME + 32)));
f.StoreGPR(i.M.RA, v);
if (i.M.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
// Integer shift (A-7)
int InstrEmit_sldx(PPCHIRBuilder& f, const InstrData& i) {
// n <- (RB)[58:63]
// r <- ROTL64((RS), n)
// if (RB)[57] = 0 then
// m <- MASK(0, 63-n)
// else
// m <- i64.0
// RA <- r & m
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F));
Value* v = f.Select(f.IsTrue(f.Shr(sh, 6)), f.LoadZeroInt64(),
f.Shl(f.LoadGPR(i.X.RT), sh));
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_slwx(PPCHIRBuilder& f, const InstrData& i) {
// n <- (RB)[59:63]
// r <- ROTL32((RS)[32:63], n)
// if (RB)[58] = 0 then
// m <- MASK(32, 63-n)
// else
// m <- i64.0
// RA <- r & m
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F));
Value* v = f.Select(f.IsTrue(f.Shr(sh, 5)), f.LoadZeroInt32(),
f.Shl(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), sh));
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_srdx(PPCHIRBuilder& f, const InstrData& i) {
// n <- (RB)[58:63]
// r <- ROTL64((RS), 64-n)
// if (RB)[57] = 0 then
// m <- MASK(n, 63)
// else
// m <- i64.0
// RA <- r & m
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F));
Value* v = f.Select(f.IsTrue(f.And(sh, f.LoadConstantInt8(0x40))),
f.LoadZeroInt64(), f.Shr(f.LoadGPR(i.X.RT), sh));
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_srwx(PPCHIRBuilder& f, const InstrData& i) {
// n <- (RB)[59:63]
// r <- ROTL32((RS)[32:63], 64-n)
// if (RB)[58] = 0 then
// m <- MASK(n+32, 63)
// else
// m <- i64.0
// RA <- r & m
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F));
Value* v =
f.Select(f.IsTrue(f.And(sh, f.LoadConstantInt8(0x20))), f.LoadZeroInt32(),
f.Shr(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), sh));
v = f.ZeroExtend(v, INT64_TYPE);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_sradx(PPCHIRBuilder& f, const InstrData& i) {
// n <- rB[58-63]
// r <- ROTL[64](rS, 64 - n)
// if rB[57] = 0 then m ← MASK(n, 63)
// else m ← (64)0
// S ← rS[0]
// rA <- (r & m) | (((64)S) & ¬ m)
// XER[CA] <- S & ((r & ¬ m) ¦ 0)
// if n == 0: rA <- rS, XER[CA] = 0
// if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS
Value* rt = f.LoadGPR(i.X.RT);
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F));
Value* clamp_sh = f.Min(sh, f.LoadConstantInt8(0x3F));
Value* v = f.Sha(rt, clamp_sh);
// CA is set if any bits are shifted out of the right and if the result
// is negative.
Value* ca =
f.And(f.IsTrue(f.Shr(rt, 63)), f.CompareNE(f.Shl(v, clamp_sh), rt));
f.StoreCA(ca);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_sradix(PPCHIRBuilder& f, const InstrData& i) {
// n <- sh[5] || sh[0-4]
// r <- ROTL[64](rS, 64 - n)
// m ← MASK(n, 63)
// S ← rS[0]
// rA <- (r & m) | (((64)S) & ¬ m)
// XER[CA] <- S & ((r & ¬ m) ¦ 0)
// if n == 0: rA <- rS, XER[CA] = 0
// if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS
Value* v = f.LoadGPR(i.XS.RT);
int8_t sh = (i.XS.SH5 << 5) | i.XS.SH;
// CA is set if any bits are shifted out of the right and if the result
// is negative.
if (sh) {
uint64_t mask = XEMASK(64 - sh, 63);
Value* ca = f.And(f.Truncate(f.Shr(v, 63), INT8_TYPE),
f.IsTrue(f.And(v, f.LoadConstantUint64(mask))));
f.StoreCA(ca);
v = f.Sha(v, sh);
} else {
f.StoreCA(f.LoadZeroInt8());
}
f.StoreGPR(i.XS.RA, v);
if (i.XS.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_srawx(PPCHIRBuilder& f, const InstrData& i) {
// n <- rB[59-63]
// r <- ROTL32((RS)[32:63], 64-n)
// m <- MASK(n+32, 63)
// s <- (RS)[32]
// RA <- r&m | (i64.s)&¬m
// CA <- s & ((r&¬m)[32:63]≠0)
// if n == 0: rA <- sign_extend(rS), XER[CA] = 0
// if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS)
Value* rt = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE);
Value* sh =
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F));
Value* clamp_sh = f.Min(sh, f.LoadConstantInt8(0x1F));
Value* v = f.Sha(rt, f.Min(sh, clamp_sh));
// CA is set if any bits are shifted out of the right and if the result
// is negative.
Value* ca =
f.And(f.IsTrue(f.Shr(rt, 31)), f.CompareNE(f.Shl(v, clamp_sh), rt));
f.StoreCA(ca);
v = f.SignExtend(v, INT64_TYPE);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
int InstrEmit_srawix(PPCHIRBuilder& f, const InstrData& i) {
// n <- SH
// r <- ROTL32((RS)[32:63], 64-n)
// m <- MASK(n+32, 63)
// s <- (RS)[32]
// RA <- r&m | (i64.s)&¬m
// CA <- s & ((r&¬m)[32:63]≠0)
// if n == 0: rA <- sign_extend(rS), XER[CA] = 0
// if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS)
Value* v = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE);
Value* ca;
if (!i.X.RB) {
// No shift, just a fancy sign extend and CA clearer.
v = f.SignExtend(v, INT64_TYPE);
ca = f.LoadZeroInt8();
} else {
// CA is set if any bits are shifted out of the right and if the result
// is negative.
uint32_t mask = (uint32_t)XEMASK(64 - i.X.RB, 63);
ca = f.And(f.Truncate(f.Shr(v, 31), INT8_TYPE),
f.IsTrue(f.And(v, f.LoadConstantUint32(mask))));
v = f.Sha(v, (int8_t)i.X.RB), v = f.SignExtend(v, INT64_TYPE);
}
f.StoreCA(ca);
f.StoreGPR(i.X.RA, v);
if (i.X.Rc) {
f.UpdateCR(0, v);
}
return 0;
}
void RegisterEmitCategoryALU() {
XEREGISTERINSTR(addx);
XEREGISTERINSTR(addcx);
XEREGISTERINSTR(addex);
XEREGISTERINSTR(addi);
XEREGISTERINSTR(addic);
XEREGISTERINSTR(addicx);
XEREGISTERINSTR(addis);
XEREGISTERINSTR(addmex);
XEREGISTERINSTR(addzex);
XEREGISTERINSTR(divdx);
XEREGISTERINSTR(divdux);
XEREGISTERINSTR(divwx);
XEREGISTERINSTR(divwux);
XEREGISTERINSTR(mulhdx);
XEREGISTERINSTR(mulhdux);
XEREGISTERINSTR(mulhwx);
XEREGISTERINSTR(mulhwux);
XEREGISTERINSTR(mulldx);
XEREGISTERINSTR(mulli);
XEREGISTERINSTR(mullwx);
XEREGISTERINSTR(negx);
XEREGISTERINSTR(subfx);
XEREGISTERINSTR(subfcx);
XEREGISTERINSTR(subficx);
XEREGISTERINSTR(subfex);
XEREGISTERINSTR(subfmex);
XEREGISTERINSTR(subfzex);
XEREGISTERINSTR(cmp);
XEREGISTERINSTR(cmpi);
XEREGISTERINSTR(cmpl);
XEREGISTERINSTR(cmpli);
XEREGISTERINSTR(andx);
XEREGISTERINSTR(andcx);
XEREGISTERINSTR(andix);
XEREGISTERINSTR(andisx);
XEREGISTERINSTR(cntlzdx);
XEREGISTERINSTR(cntlzwx);
XEREGISTERINSTR(eqvx);
XEREGISTERINSTR(extsbx);
XEREGISTERINSTR(extshx);
XEREGISTERINSTR(extswx);
XEREGISTERINSTR(nandx);
XEREGISTERINSTR(norx);
XEREGISTERINSTR(orx);
XEREGISTERINSTR(orcx);
XEREGISTERINSTR(ori);
XEREGISTERINSTR(oris);
XEREGISTERINSTR(xorx);
XEREGISTERINSTR(xori);
XEREGISTERINSTR(xoris);
XEREGISTERINSTR(rldclx);
XEREGISTERINSTR(rldcrx);
XEREGISTERINSTR(rldicx);
XEREGISTERINSTR(rldiclx);
XEREGISTERINSTR(rldicrx);
XEREGISTERINSTR(rldimix);
XEREGISTERINSTR(rlwimix);
XEREGISTERINSTR(rlwinmx);
XEREGISTERINSTR(rlwnmx);
XEREGISTERINSTR(sldx);
XEREGISTERINSTR(slwx);
XEREGISTERINSTR(srdx);
XEREGISTERINSTR(srwx);
XEREGISTERINSTR(sradx);
XEREGISTERINSTR(sradix);
XEREGISTERINSTR(srawx);
XEREGISTERINSTR(srawix);
}
} // namespace ppc
} // namespace cpu
} // namespace xe