Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/dataflowAPI/rose/semantics/DispatcherPowerpc.C
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1173 lines
52 KiB
C++

//#include "sage3basic.h"
#include "../util/StringUtility.h"
#include "BaseSemantics2.h"
//#include "Diagnostics.h"
#include "DispatcherPowerpc.h"
#include "../integerOps.h"
#include "SymEvalSemantics.h"
#include "../SgAsmExpression.h"
#include "../conversions.h"
namespace rose {
namespace BinaryAnalysis {
namespace InstructionSemantics2 {
/*******************************************************************************************************************************
* Support functions
*******************************************************************************************************************************/
/*******************************************************************************************************************************
* Functors that handle individual PowerPC instructions kinds
*******************************************************************************************************************************/
namespace Powerpc {
// An intermediate class that reduces the amount of typing in all that follows. Its process() method does some up-front
// checking, dynamic casting, and pointer dereferencing and then calls the p() method that does the real work.
class P: public BaseSemantics::InsnProcessor {
public:
typedef DispatcherPowerpc *D;
typedef BaseSemantics::RiscOperators *Ops;
typedef SgAsmPowerpcInstruction *I;
typedef const SgAsmExpressionPtrList &A;
virtual void p(D, Ops, I, A) = 0;
virtual void process(const BaseSemantics::DispatcherPtr &dispatcher_, SgAsmInstruction *insn_) {
DispatcherPowerpcPtr dispatcher = DispatcherPowerpc::promote(dispatcher_);
BaseSemantics::RiscOperatorsPtr operators = dispatcher->get_operators();
SgAsmPowerpcInstruction *insn = isSgAsmPowerpcInstruction(insn_);
ASSERT_require(insn!=NULL && insn==operators->currentInstruction());
dispatcher->advanceInstructionPointer(insn);
SgAsmExpressionPtrList &operands = insn->get_operandList()->get_operands();
p(dispatcher.get(), operators.get(), insn, operands);
}
void assert_args(I insn, A args, size_t nargs) {
if (args.size()!=nargs) {
std::string mesg = "instruction must have " + StringUtility::numberToString(nargs) + "argument" + (1==nargs?"":"s");
throw BaseSemantics::Exception(mesg, insn);
}
}
// Builds mask of 1's from the bit value starting at mb_value to me_value.
// See page 71 of PowerPC manual.
uint32_t build_mask(uint8_t mb_value, uint8_t me_value) {
uint32_t mask = 0;
constexpr uint32_t max_bit_pos{31}, sentinnel{1};
if (mb_value <= me_value) {
// PowerPC counts bits from the left.
for (int i = mb_value; i <= me_value; i++)
mask |= (sentinnel << (max_bit_pos - i));
} else {
for (auto i = mb_value; i <= max_bit_pos; i++)
mask |= (sentinnel << (max_bit_pos - i));
for (uint8_t i = 0; i <= me_value; i++)
mask |= (sentinnel << (max_bit_pos - i));
}
return mask;
}
};
// Fixed-point addition
struct IP_add: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
d->write(args[0], ops->add(d->read(args[1], 32), d->read(args[2], 32)));
}
};
// Fixed-point add carrying
struct IP_addc: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr no = ops->boolean_(false);
BaseSemantics::SValuePtr result = ops->addWithCarries(d->read(args[1], 32), d->read(args[2], 32),
no, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr ones = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), ones), v1));
}
};
// Fixed-point add extended
struct IP_adde: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr carry_in = ops->extract(ops->readRegister(d->REG_XER), 29, 30);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->addWithCarries(d->read(args[1], 32), arg2, carry_in, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr ones = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), ones), v1));
}
};
// Fixed-point addition
struct IP_addi: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr ra = d->read(args[1], 32);
// The disassembler should have built this as a DWord with a sign extended value
BaseSemantics::SValuePtr signExtended_si = ops->signExtend(ops->extract(d->read(args[2], 32), 0, 16), 32);
d->write(args[0], ops->add(ra, signExtended_si));
}
};
// Fixed-point add immediate carrying
struct IP_addic: P {
bool record;
IP_addic(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr no = ops->boolean_(false);
BaseSemantics::SValuePtr v1 = ops->signExtend(ops->extract(d->read(args[2], 32), 0, 16), 32);
BaseSemantics::SValuePtr result = ops->addWithCarries(d->read(args[1], 32), v1, no, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v2 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr ones = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), ones), v2));
if (record)
d->record(result);
}
};
// Fixed-point add immediate shifted
struct IP_addis: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->extract(d->read(args[2], 32), 0, 16);
BaseSemantics::SValuePtr v2 = ops->concat(ops->number_(16, 0), v1);
BaseSemantics::SValuePtr v3 = ops->signExtend(v2, d->addressWidth());
d->write(args[0], ops->add(d->read(args[1], 32), v3));
}
};
// Fixed-point add minus one extended
struct IP_addme: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr carry_in = ops->extract(ops->readRegister(d->REG_XER), 29, 30);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr ones = ops->number_(32, 0xffffffffu);
BaseSemantics::SValuePtr result = ops->addWithCarries(d->read(args[1], 32), ones, carry_in, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffffu is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), ones), v1));
}
};
// Fixed-point add to zero extended
struct IP_addze: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr carry_in = ops->extract(ops->readRegister(d->REG_XER), 29, 30);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr zero = d->number_(32, 0);
BaseSemantics::SValuePtr result = ops->addWithCarries(d->read(args[1], 32), zero, carry_in, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr ones = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), ones), v1));
}
};
// Fixed-point logical AND
struct IP_and: P {
bool record;
IP_and(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->and_(d->read(args[1], 32), arg2);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Fixed-point logical AND with complement
struct IP_andc: P {
bool record;
IP_andc(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->invert(d->read(args[2], 32));
BaseSemantics::SValuePtr result = ops->and_(d->read(args[1], 32), v1);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Fixed-point logical AND immediate shifted
struct IP_andis: P {
bool record;
IP_andis(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->extract(d->read(args[2], 32), 0, 16);
BaseSemantics::SValuePtr v2 = ops->concat(ops->number_(16, 0), v1);
BaseSemantics::SValuePtr result = ops->and_(d->read(args[1], 32), v2);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Branch instruction relative (optionally save link)
struct IP_b: P {
bool save_link;
IP_b(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 1);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
BaseSemantics::SValuePtr v1 = ops->number_(32, insn->get_address());
BaseSemantics::SValuePtr target = ops->add(d->read(args[0], 32), v1);
ops->writeRegister(d->REG_IAR, target);
}
};
// Branch absolute (optionally save link)
struct IP_ba: P {
bool save_link;
IP_ba(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 1);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
ops->writeRegister(d->REG_IAR, d->read(args[0], 32));
}
};
// Branch conditional instruction relative (optionally save link)
struct IP_bc: P {
bool save_link;
IP_bc(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
SgAsmIntegerValueExpression *byteValue = isSgAsmIntegerValueExpression(args[0]);
ASSERT_not_null(byteValue);
uint8_t boConstant = byteValue->get_value();
// bool bo_4 = boConstant & 0x1;
bool bo_3 = boConstant & 0x2;
bool bo_2 = boConstant & 0x4;
bool bo_1 = boConstant & 0x8;
bool bo_0 = boConstant & 0x10;
if (!bo_2) {
BaseSemantics::SValuePtr negOne = ops->number_(32, -1);
ops->writeRegister(d->REG_CTR, ops->add(ops->readRegister(d->REG_CTR), negOne));
}
BaseSemantics::SValuePtr ctr_ok;
if (bo_2) {
ctr_ok = ops->boolean_(true);
} else if (bo_3) {
ctr_ok = ops->equalToZero(ops->readRegister(d->REG_CTR));
} else {
ctr_ok = ops->invert(ops->equalToZero(ops->readRegister(d->REG_CTR)));
}
SgAsmRegisterReferenceExpression *bi = isSgAsmRegisterReferenceExpression(args[1]);
ASSERT_require(bi && bi->get_descriptor().get_major() == powerpc_regclass_cr && bi->get_descriptor().get_nbits() == 1);
BaseSemantics::SValuePtr cr_bi = ops->readRegister(bi->get_descriptor());
BaseSemantics::SValuePtr cond_ok = bo_0 ? ops->boolean_(true) : bo_1 ? cr_bi : ops->invert(cr_bi);
BaseSemantics::SValuePtr v1 = ops->number_(32, insn->get_address());
BaseSemantics::SValuePtr target = (ops->add(d->read(args[2], 32), v1));
BaseSemantics::SValuePtr iar = ops->readRegister(d->REG_IAR);
ops->writeRegister(d->REG_IAR, ops->ite(ops->and_(ctr_ok, cond_ok), target, iar));
}
};
// Branch conditional absolute (optionally save link)
struct IP_bca: P {
bool save_link;
IP_bca(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
SgAsmIntegerValueExpression *byteValue = isSgAsmIntegerValueExpression(args[0]);
ASSERT_not_null(byteValue);
uint8_t boConstant = byteValue->get_value();
// bool bo_4 = boConstant & 0x1;
bool bo_3 = boConstant & 0x2;
bool bo_2 = boConstant & 0x4;
bool bo_1 = boConstant & 0x8;
bool bo_0 = boConstant & 0x10;
if (!bo_2) {
BaseSemantics::SValuePtr negOne = ops->number_(32, -1);
ops->writeRegister(d->REG_CTR, ops->add(ops->readRegister(d->REG_CTR), negOne));
}
BaseSemantics::SValuePtr ctr_ok;
if (bo_2) {
ctr_ok = ops->boolean_(true);
} else if (bo_3) {
ctr_ok = ops->equalToZero(ops->readRegister(d->REG_CTR));
} else {
ctr_ok = ops->invert(ops->equalToZero(ops->readRegister(d->REG_CTR)));
}
SgAsmRegisterReferenceExpression *bi = isSgAsmRegisterReferenceExpression(args[1]);
ASSERT_require(bi && bi->get_descriptor().get_major() == powerpc_regclass_cr && bi->get_descriptor().get_nbits() == 1);
BaseSemantics::SValuePtr cr_bi = ops->readRegister(bi->get_descriptor());
BaseSemantics::SValuePtr cond_ok = bo_0 ? ops->boolean_(true) : bo_1 ? cr_bi : ops->invert(cr_bi);
BaseSemantics::SValuePtr target = d->read(args[2], 32);
BaseSemantics::SValuePtr iar = ops->readRegister(d->REG_IAR);
ops->writeRegister(d->REG_IAR, ops->ite(ops->and_(ctr_ok, cond_ok), target, iar));
}
};
// Branch conditional to count register
struct IP_bcctr: P {
bool save_link;
IP_bcctr(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
SgAsmIntegerValueExpression *byteValue = isSgAsmIntegerValueExpression(args[0]);
ASSERT_not_null(byteValue);
uint8_t boConstant = byteValue->get_value();
bool bo_1 = boConstant & 0x8;
bool bo_0 = boConstant & 0x10;
SgAsmRegisterReferenceExpression *bi = isSgAsmRegisterReferenceExpression(args[1]);
ASSERT_require(bi && bi->get_descriptor().get_major() == powerpc_regclass_cr && bi->get_descriptor().get_nbits() == 1);
BaseSemantics::SValuePtr cr_bi = ops->readRegister(bi->get_descriptor());
BaseSemantics::SValuePtr cond_ok = bo_0 ? ops->boolean_(true) : bo_1 ? cr_bi : ops->invert(cr_bi);
BaseSemantics::SValuePtr iar = ops->readRegister(d->REG_IAR);
BaseSemantics::SValuePtr mask = ops->number_(32, 0xfffffffc);
ops->writeRegister(d->REG_IAR, ops->ite(cond_ok, ops->and_(ops->readRegister(d->REG_CTR), mask), iar));
}
};
// Branch conditional (optionally save link)
struct IP_bclr: P {
bool save_link;
IP_bclr(bool save_link): save_link(save_link) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
if (save_link)
ops->writeRegister(d->REG_LR, ops->number_(32, insn->get_address() + 4));
SgAsmIntegerValueExpression *byteValue = isSgAsmIntegerValueExpression(args[0]);
ASSERT_not_null(byteValue);
uint8_t boConstant = byteValue->get_value();
// bool bo_4 = boConstant & 0x1;
bool bo_3 = boConstant & 0x2;
bool bo_2 = boConstant & 0x4;
bool bo_1 = boConstant & 0x8;
bool bo_0 = boConstant & 0x10;
if (!bo_2) {
BaseSemantics::SValuePtr negOne = ops->number_(32, -1);
ops->writeRegister(d->REG_CTR, ops->add(ops->readRegister(d->REG_CTR), negOne));
}
BaseSemantics::SValuePtr ctr_ok;
if (bo_2) {
ctr_ok = ops->boolean_(true);
} else if (bo_3) {
ctr_ok = ops->equalToZero(ops->readRegister(d->REG_CTR));
} else {
ctr_ok = ops->invert(ops->equalToZero(ops->readRegister(d->REG_CTR)));
}
SgAsmRegisterReferenceExpression *bi = isSgAsmRegisterReferenceExpression(args[1]);
ASSERT_require(bi && bi->get_descriptor().get_major() == powerpc_regclass_cr && bi->get_descriptor().get_nbits() == 1);
BaseSemantics::SValuePtr cr_bi = ops->readRegister(bi->get_descriptor());
BaseSemantics::SValuePtr cond_ok = bo_0 ? ops->boolean_(true) : bo_1 ? cr_bi : ops->invert(cr_bi);
BaseSemantics::SValuePtr mask = ops->number_(32, 0xfffffffc);
BaseSemantics::SValuePtr target = ops->and_(ops->readRegister(d->REG_LR), mask);
BaseSemantics::SValuePtr iar = ops->readRegister(d->REG_IAR);
ops->writeRegister(d->REG_IAR, ops->ite(ops->and_(ctr_ok, cond_ok), target, iar));
}
};
// Fixed-point compare
struct IP_cmp: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 4);
// For 32-bit case we can ignore value of L
BaseSemantics::SValuePtr ra = d->read(args[2], 32);
BaseSemantics::SValuePtr rb = d->read(args[3], 32);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
// Need to check if ops->boolean_(false) or ops->boolean_(true) should be used!
// Bias both sides and use unsigned compare.
// ops->invert(ops->xor_(RA,number<32>(0x80000000U))) yields "(RA+bias)-1"
// Check if UI + (-RA) - 1 >= 0, test for UI > RA
BaseSemantics::SValuePtr no = ops->boolean_(false);
BaseSemantics::SValuePtr v1 = ops->xor_(rb, ops->number_(32, 0x80000000u));
ops->addWithCarries(ops->invert(ops->xor_(ra, ops->number_(32, 0x80000000u))), v1, no, carries);
BaseSemantics::SValuePtr two = ops->number_(3, 2);
BaseSemantics::SValuePtr four = ops->number_(3, 4);
BaseSemantics::SValuePtr v2 = ops->ite(ops->extract(carries, 31, 32), four, two);
BaseSemantics::SValuePtr one = ops->number_(3, 1);
BaseSemantics::SValuePtr c = ops->ite(ops->equalToZero(ops->xor_(ra, rb)), one, v2);
SgAsmRegisterReferenceExpression* bf = isSgAsmRegisterReferenceExpression(args[0]);
ASSERT_require(bf && bf->get_descriptor().get_major() == powerpc_regclass_cr && bf->get_descriptor().get_nbits() == 4);
// This should be a helper function!
BaseSemantics::SValuePtr so = ops->extract(ops->readRegister(d->REG_XER), 31, 32);
ops->writeRegister(bf->get_descriptor(), ops->concat(so, c));
}
};
// Fixed-point compare immediate
struct IP_cmpi: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 4);
// For 32-bit case we can ignore value of L
BaseSemantics::SValuePtr ra = d->read(args[2], 32);
BaseSemantics::SValuePtr si = ops->signExtend(ops->extract(d->read(args[3], 32), 0, 16), 32);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
// Need to check if ops->boolean_(false) or ops->boolean_(true) should be used!
// Bias both sides and use unsigned compare.
// ops->invert(ops->xor_(RA,number<32>(0x80000000U))) yields "(RA+bias)-1"
// Check if UI + (-RA) - 1 >= 0, test for UI > RA
BaseSemantics::SValuePtr no = ops->boolean_(false);
BaseSemantics::SValuePtr v1 = ops->xor_(si, ops->number_(32, 0x80000000u));
ops->addWithCarries(ops->invert(ops->xor_(ra, ops->number_(32, 0x80000000u))), v1, no, carries);
BaseSemantics::SValuePtr two = ops->number_(3, 2);
BaseSemantics::SValuePtr four = ops->number_(3, 4);
BaseSemantics::SValuePtr v2 = ops->ite(ops->extract(carries, 31, 32), four, two);
BaseSemantics::SValuePtr one = ops->number_(3, 1);
BaseSemantics::SValuePtr c = ops->ite(ops->equalToZero(ops->xor_(ra, si)), one, v2);
SgAsmRegisterReferenceExpression *bf = isSgAsmRegisterReferenceExpression(args[0]);
ASSERT_require(bf && bf->get_descriptor().get_major() == powerpc_regclass_cr && bf->get_descriptor().get_nbits() == 4);
// This should be a helper function!
BaseSemantics::SValuePtr so = ops->extract(ops->readRegister(d->REG_XER), 31, 32);
ops->writeRegister(bf->get_descriptor(), ops->concat(so, c));
}
};
// Fixed-point compare logical immediate
struct IP_cmpl: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 4);
// For 32-bit case we can ignore value of L
BaseSemantics::SValuePtr ra = d->read(args[2], 32);
BaseSemantics::SValuePtr ui = d->read(args[3], 32);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
// Need to check if ops->boolean_(false) or ops->boolean_(true) should be used!
// ops->invert(RA) yields "(-RA)-1"
// Check if UI + (-RA) - 1 >= 0, test for UI > RA
BaseSemantics::SValuePtr no = ops->boolean_(false);
ops->addWithCarries(ops->invert(ra), ui, no, carries);
BaseSemantics::SValuePtr two = ops->number_(3, 2);
BaseSemantics::SValuePtr four = ops->number_(3, 4);
BaseSemantics::SValuePtr v1 = ops->ite(ops->extract(carries, 31, 32), four, two);
BaseSemantics::SValuePtr one = ops->number_(3, 1);
BaseSemantics::SValuePtr c = ops->ite(ops->equalToZero(ops->xor_(ra, ui)), one, v1);
SgAsmRegisterReferenceExpression* bf = isSgAsmRegisterReferenceExpression(args[0]);
ASSERT_require(bf && bf->get_descriptor().get_major() == powerpc_regclass_cr && bf->get_descriptor().get_nbits()==4);
// This should be a helper function!
BaseSemantics::SValuePtr so = ops->extract(ops->readRegister(d->REG_XER), 31, 32);
ops->writeRegister(bf->get_descriptor(), ops->concat(so, c));
}
};
// Count leading zeros word
struct IP_cntlzw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr rs = d->read(args[1], 32);
// Using xor to do the subtract from 31
BaseSemantics::SValuePtr thirtyOne = ops->number_(32, 31);
BaseSemantics::SValuePtr v1 = ops->xor_(ops->mostSignificantSetBit(rs), thirtyOne);
BaseSemantics::SValuePtr thirtyTwo = ops->number_(32, 32);
BaseSemantics::SValuePtr result = ops->ite(ops->equalToZero(rs), thirtyTwo, v1);
d->write(args[0], result);
}
};
// Fixed-point divide word
struct IP_divw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->signedDivide(d->read(args[1], 32), arg2));
}
};
// Fixed-point divide word unsigned
struct IP_divwu: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->unsignedDivide(d->read(args[1], 32), arg2));
}
};
// Load byte and zero extend
struct IP_lbz: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr zero = ops->number_(24, 0);
d->write(args[0], ops->concat(d->read(args[1], 8), zero));
}
};
// Load byte and zero extend with update
struct IP_lbzu: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
SgAsmMemoryReferenceExpression *memoryReference = isSgAsmMemoryReferenceExpression(args[1]);
SgAsmBinaryAdd *binaryAdd = isSgAsmBinaryAdd(memoryReference->get_address());
ASSERT_not_null(binaryAdd);
SgAsmExpression *ra = binaryAdd->get_lhs();
BaseSemantics::SValuePtr addr = d->effectiveAddress(args[1], 32);
BaseSemantics::SValuePtr zero = ops->number_(24, 0);
d->write(args[0], ops->concat(d->read(args[1], 8), zero));
d->write(ra, addr);
}
};
// Load half-word algebraic
struct IP_lha: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
d->write(args[0], ops->signExtend(d->read(args[1], 16), 32));
}
};
// Load half-word and zero extend
struct IP_lhz: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr zero = ops->number_(16, 0);
d->write(args[0], ops->concat(d->read(args[1], 16), zero));
}
};
// Load multiple word
struct IP_lmw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr base = d->effectiveAddress(args[1], 32);
SgAsmRegisterReferenceExpression *rt = isSgAsmRegisterReferenceExpression(args[0]);
ASSERT_require(rt && rt->get_descriptor().get_major() == powerpc_regclass_gpr);
RegisterDescriptor reg = rt->get_descriptor();
rose_addr_t offset = 0;
for (unsigned minor=reg.get_minor(); minor<32; minor+=1, offset+=4) {
BaseSemantics::SValuePtr addr = ops->add(base, ops->number_(32, offset));
BaseSemantics::SValuePtr dflt = ops->undefined_(32);
BaseSemantics::SValuePtr value = ops->readMemory(RegisterDescriptor(), addr, dflt, ops->boolean_(true));
reg.set_minor(minor);
ops->writeRegister(reg, value);
}
}
};
// Load word and zero with update
struct IP_lwzu: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
// FIXME: shouldn't DispatcherPowerpc::read() handle this? [Robb P. Matzke 2013-05-08]
SgAsmMemoryReferenceExpression *memoryReference = isSgAsmMemoryReferenceExpression(args[1]);
SgAsmBinaryAdd *binaryAdd = isSgAsmBinaryAdd(memoryReference->get_address());
ASSERT_not_null(binaryAdd);
SgAsmExpression *ra = binaryAdd->get_lhs();
BaseSemantics::SValuePtr addr = d->effectiveAddress(args[1], 32);
BaseSemantics::SValuePtr yes = ops->boolean_(true);
d->write(args[0], ops->readMemory(RegisterDescriptor(), addr, ops->undefined_(32), yes));
d->write(ra, addr);
}
};
// Move from condition register
struct IP_mfcr: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 1);
d->write(args[0], ops->readRegister(d->REG_CR));
}
};
// Copies the value from the second argument to the first argument. This is used for a variety of instructions.
struct IP_move: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
d->write(args[0], d->read(args[1], 32));
}
};
// Multiply high word
struct IP_mulhw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->extract(ops->signedMultiply(d->read(args[1], 32), arg2), 32, 64));
}
};
// Multiply high word unsigned
struct IP_mulhwu: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->extract(ops->unsignedMultiply(d->read(args[1], 32), arg2), 32, 64));
}
};
// Multiply low word
struct IP_mullw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->extract(ops->signedMultiply(d->read(args[1], 32), arg2), 0, 32));
}
};
// Fixed-point negation
struct IP_neg: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
d->write(args[0], ops->negate(d->read(args[1], 32)));
}
};
// Fixed-point logical NOR
struct IP_nor: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
d->write(args[0], ops->invert(ops->or_(d->read(args[1], 32), arg2)));
}
};
// Fixed-point logical OR
struct IP_or: P {
bool record;
IP_or(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->or_(d->read(args[1], 32), arg2);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Fixed-point logical OR with complement
struct IP_orc: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->invert(d->read(args[2], 32));
d->write(args[0], ops->or_(d->read(args[1], 32), v1));
}
};
// Fixed-point logical OR shifted
struct IP_oris: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->extract(d->read(args[2], 32), 0, 16);
BaseSemantics::SValuePtr v2 = ops->concat(ops->number_(16, 0), v1);
d->write(args[0], ops->or_(d->read(args[1], 32), v2));
}
};
// Rotate left double word immediate then clear right
struct IP_rldicr: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 4);
BaseSemantics::SValuePtr rs = d->read(args[1], 32);
BaseSemantics::SValuePtr ra = d->read(args[0], 32);
BaseSemantics::SValuePtr sh = ops->extract(d->read(args[2], 32), 0, 5);
/*
SgAsmIntegerValueExpression *mb = isSgAsmIntegerValueExpression(args[3]);
ASSERT_not_null(mb);
int mb_value = mb->get_value();
uint32_t mask = build_mask(mb_value, me_value);
*/
BaseSemantics::SValuePtr rotatedReg = ops->rotateLeft(rs, sh);
//BaseSemantics::SValuePtr bitMask = ops->number_(32, mask);
//BaseSemantics::SValuePtr v1 = ops->and_(ra, ops->invert(bitMask));
//BaseSemantics::SValuePtr result = ops->or_(ops->and_(rotatedReg, bitMask), v1);
//d->write(args[0], result);
d->write(args[0], rotatedReg);
}
};
// Rotate left word immediate then mask insert
struct IP_rlwimi: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 5);
BaseSemantics::SValuePtr rs = d->read(args[1], 32);
BaseSemantics::SValuePtr ra = d->read(args[0], 32);
BaseSemantics::SValuePtr sh = ops->extract(d->read(args[2], 32), 0, 5);
SgAsmIntegerValueExpression *mb = isSgAsmIntegerValueExpression(args[3]);
ASSERT_not_null(mb);
int mb_value = mb->get_value();
SgAsmIntegerValueExpression *me = isSgAsmIntegerValueExpression(args[4]);
ASSERT_not_null(me);
int me_value = me->get_value();
uint32_t mask = build_mask(mb_value, me_value);
BaseSemantics::SValuePtr rotatedReg = ops->rotateLeft(rs, sh);
BaseSemantics::SValuePtr bitMask = ops->number_(32, mask);
BaseSemantics::SValuePtr v1 = ops->and_(ra, ops->invert(bitMask));
BaseSemantics::SValuePtr result = ops->or_(ops->and_(rotatedReg, bitMask), v1);
d->write(args[0], result);
}
};
// Rotate left word immediate then AND with mask
struct IP_rlwinm: P {
bool record;
IP_rlwinm(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 5);
BaseSemantics::SValuePtr rs = d->read(args[1], 32);
BaseSemantics::SValuePtr sh = ops->extract(d->read(args[2], 32), 0, 5);
SgAsmIntegerValueExpression *mb = isSgAsmIntegerValueExpression(args[3]);
ASSERT_not_null(mb);
int mb_value = mb->get_value();
SgAsmIntegerValueExpression *me = isSgAsmIntegerValueExpression(args[4]);
ASSERT_not_null(me);
int me_value = me->get_value();
uint32_t mask = build_mask(mb_value, me_value);
BaseSemantics::SValuePtr rotatedReg = ops->rotateLeft(rs, sh);
BaseSemantics::SValuePtr bitMask = ops->number_(32, mask);
BaseSemantics::SValuePtr result = ops->and_(rotatedReg, bitMask);
//d->write(args[0], result);
d->write(args[0], rotatedReg);
if (record)
d->record(result);
}
};
// System call
struct IP_sc: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 1);
SgAsmIntegerValueExpression *bv = isSgAsmIntegerValueExpression(args[0]);
ASSERT_not_null(bv);
ops->interrupt(0, bv->get_value());
}
};
// Shift left word
struct IP_slw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr shiftCount = ops->extract(d->read(args[2], 32), 0, 6);
BaseSemantics::SValuePtr v1 = ops->extract(shiftCount, 0, 5);
BaseSemantics::SValuePtr v2 = ops->shiftLeft(d->read(args[1], 32), v1);
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
d->write(args[0], ops->ite(ops->extract(shiftCount, 5, 6), zero, v2));
}
};
// Shift right algebraic word immediate
struct IP_srawi: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr rs = d->read(args[1], 32);
BaseSemantics::SValuePtr sh = ops->extract(d->read(args[2], 32), 0, 5);
BaseSemantics::SValuePtr negative = ops->extract(rs, 31, 32);
BaseSemantics::SValuePtr mask = ops->invert(ops->shiftLeft(ops->number_(32, -1), sh));
BaseSemantics::SValuePtr hasValidBits = ops->invert(ops->equalToZero(ops->and_(rs, mask)));
BaseSemantics::SValuePtr carry_out = ops->and_(hasValidBits, negative);
d->write(args[0], ops->shiftRightArithmetic(rs, sh));
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr v2 = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), v2), v1));
}
};
// Shift right word
struct IP_srw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr shiftCount = ops->extract(d->read(args[2], 32), 0, 6);
BaseSemantics::SValuePtr v1 = ops->extract(shiftCount, 0, 5);
BaseSemantics::SValuePtr v2 = ops->shiftRight(d->read(args[1], 32), v1);
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
d->write(args[0], ops->ite(ops->extract(shiftCount, 5, 6), zero, v2));
}
};
// Store byte
struct IP_stb: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
d->write(args[1], ops->extract(d->read(args[0], 32), 0, 8));
}
};
// Store halfword
struct IP_sth: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
d->write(args[1], ops->extract(d->read(args[0], 32), 0, 16));
}
};
// Store multiple word
struct IP_stmw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr base = d->effectiveAddress(args[1], 32);
SgAsmRegisterReferenceExpression *rs = isSgAsmRegisterReferenceExpression(args[0]);
ASSERT_require(rs && rs->get_descriptor().get_major() == powerpc_regclass_gpr);
RegisterDescriptor reg = rs->get_descriptor();
rose_addr_t offset = 0;
for (unsigned minor=reg.get_minor(); minor<32; minor+=1, offset+=4) {
BaseSemantics::SValuePtr addr = ops->add(base, ops->number_(32, offset));
reg.set_minor(minor);
BaseSemantics::SValuePtr value = ops->readRegister(reg);
ops->writeMemory(RegisterDescriptor(), addr, value, ops->boolean_(true));
}
}
};
// Store word
struct IP_stw: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
BaseSemantics::SValuePtr result = d->read(args[0], 32);
d->write(args[1], result);
if (powerpc_stwcx_record==insn->get_kind())
d->record(result);
}
};
// Store word with update
struct IP_stwu: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
// FIXME: shouldn't this be done by DispatcherPowerpc::read()? [Robb P. Matzke 2013-05-08]
SgAsmMemoryReferenceExpression *memoryReference = isSgAsmMemoryReferenceExpression(args[1]);
SgAsmBinaryAdd *binaryAdd = isSgAsmBinaryAdd(memoryReference->get_address());
ASSERT_not_null(binaryAdd);
SgAsmExpression *ra = binaryAdd->get_lhs();
BaseSemantics::SValuePtr addr = d->effectiveAddress(args[1], 32);
BaseSemantics::SValuePtr yes = ops->boolean_(true);
ops->writeMemory(RegisterDescriptor(), addr, d->read(args[0], 32), yes);
d->write(ra, addr);
}
};
// Fixed point subtract
struct IP_subf: P {
bool record;
IP_subf(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->add(ops->negate(d->read(args[1], 32)), arg2);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Fixed-point subtract from carrying
struct IP_subfc: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr yes = ops->boolean_(true);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->addWithCarries(ops->invert(d->read(args[1], 32)), arg2, yes, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr v2 = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), v2), v1));
}
};
// Fixed-point subtract from extended
struct IP_subfe: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
// This should be a helper function to read CA (and other flags)
BaseSemantics::SValuePtr carry_in = ops->extract(ops->readRegister(d->REG_XER), 29, 30);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->addWithCarries(ops->invert(d->read(args[1], 32)), arg2, carry_in, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr v2 = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), v2), v1));
}
};
// Fixed-point subtract from immediate carrying
struct IP_subfic: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
// To do the subtraction we invert the first operand and add. To add "1" we set the carry in to true.
BaseSemantics::SValuePtr yes = ops->boolean_(true);
BaseSemantics::SValuePtr v1 = ops->signExtend(ops->extract(d->read(args[2], 32), 0, 16), 32);
BaseSemantics::SValuePtr result = ops->addWithCarries(ops->invert(d->read(args[1], 32)), v1, yes, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xDFFFFFFFU is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr v2 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr v3 = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), v3), v2));
}
};
// Fixed-point subtract from zero extended
struct IP_subfze: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 2);
// This should be a helper function to read CA (and other flags)
BaseSemantics::SValuePtr carry_in = ops->extract(ops->readRegister(d->REG_XER), 29, 30);
BaseSemantics::SValuePtr carries = ops->number_(32, 0);
BaseSemantics::SValuePtr zero = ops->number_(32, 0);
BaseSemantics::SValuePtr result = ops->addWithCarries(ops->invert(d->read(args[1], 32)), zero, carry_in, carries);
BaseSemantics::SValuePtr carry_out = ops->extract(carries, 31, 32);
d->write(args[0], result);
// This should be a helper function to read/write CA (and other flags)
// The value 0xdfffffff is the mask for the Carry (CA) flag
BaseSemantics::SValuePtr v1 = ops->ite(carry_out, ops->number_(32, 0x20000000u), zero);
BaseSemantics::SValuePtr v2 = ops->number_(32, 0xdfffffffu);
ops->writeRegister(d->REG_XER, ops->or_(ops->and_(ops->readRegister(d->REG_XER), v2), v1));
}
};
// Fixed-point logical XOR
struct IP_xor: P {
bool record;
IP_xor(bool record): record(record) {}
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr arg2 = d->read(args[2], 32);
BaseSemantics::SValuePtr result = ops->xor_(d->read(args[1], 32), arg2);
d->write(args[0], result);
if (record)
d->record(result);
}
};
// Fixed-point logical XOR shifted
struct IP_xoris: P {
void p(D d, Ops ops, I insn, A args) {
assert_args(insn, args, 3);
BaseSemantics::SValuePtr v1 = ops->extract(d->read(args[2], 32), 0, 16);
BaseSemantics::SValuePtr v2 = ops->concat(ops->number_(16, 0), v1);
d->write(args[0], ops->xor_(d->read(args[1], 32), v2));
}
};
} // namespace
/*******************************************************************************************************************************
* DispatcherPowerpc
*******************************************************************************************************************************/
void
DispatcherPowerpc::iproc_init()
{
iproc_set(powerpc_add, new Powerpc::IP_add);
iproc_set(powerpc_addc, new Powerpc::IP_addc);
iproc_set(powerpc_adde, new Powerpc::IP_adde);
iproc_set(powerpc_addi, new Powerpc::IP_addi);
iproc_set(powerpc_addic, new Powerpc::IP_addic(false));
iproc_set(powerpc_addic_record, new Powerpc::IP_addic(true));
iproc_set(powerpc_addis, new Powerpc::IP_addis);
iproc_set(powerpc_addme, new Powerpc::IP_addme);
iproc_set(powerpc_addze, new Powerpc::IP_addze);
iproc_set(powerpc_and, new Powerpc::IP_and(false));
iproc_set(powerpc_and_record, new Powerpc::IP_and(true));
iproc_set(powerpc_andc, new Powerpc::IP_andc(false));
iproc_set(powerpc_andc_record, new Powerpc::IP_andc(true));
iproc_set(powerpc_andi_record, new Powerpc::IP_and(true));
iproc_set(powerpc_andis_record, new Powerpc::IP_andis(true));
iproc_set(powerpc_b, new Powerpc::IP_b(false));
iproc_set(powerpc_ba, new Powerpc::IP_ba(false));
iproc_set(powerpc_bc, new Powerpc::IP_bc(false));
iproc_set(powerpc_bca, new Powerpc::IP_bca(false));
iproc_set(powerpc_bcctr, new Powerpc::IP_bcctr(false));
iproc_set(powerpc_bcctrl, new Powerpc::IP_bcctr(true));
iproc_set(powerpc_bcl, new Powerpc::IP_bc(true));
iproc_set(powerpc_bcla, new Powerpc::IP_bca(true));
iproc_set(powerpc_bclr, new Powerpc::IP_bclr(false));
iproc_set(powerpc_bclrl, new Powerpc::IP_bclr(true));
iproc_set(powerpc_bl, new Powerpc::IP_b(true));
iproc_set(powerpc_bla, new Powerpc::IP_ba(true));
iproc_set(powerpc_cmp, new Powerpc::IP_cmp);
iproc_set(powerpc_cmpi, new Powerpc::IP_cmpi);
iproc_set(powerpc_cmpl, new Powerpc::IP_cmpl);
iproc_set(powerpc_cmpli, new Powerpc::IP_cmpl);
iproc_set(powerpc_cntlzw, new Powerpc::IP_cntlzw);
iproc_set(powerpc_fmr, new Powerpc::IP_move);
iproc_set(powerpc_divw, new Powerpc::IP_divw);
iproc_set(powerpc_divwu, new Powerpc::IP_divwu);
iproc_set(powerpc_extsw, new Powerpc::IP_move);
iproc_set(powerpc_lbz, new Powerpc::IP_lbz);
iproc_set(powerpc_lbzu, new Powerpc::IP_lbzu);
iproc_set(powerpc_lbzux, new Powerpc::IP_lbzu);
iproc_set(powerpc_lbzx, new Powerpc::IP_lbz);
iproc_set(powerpc_ld, new Powerpc::IP_move);
iproc_set(powerpc_lha, new Powerpc::IP_lha);
iproc_set(powerpc_lhax, new Powerpc::IP_lha);
iproc_set(powerpc_lhz, new Powerpc::IP_lhz);
iproc_set(powerpc_lhzx, new Powerpc::IP_lhz);
iproc_set(powerpc_lmw, new Powerpc::IP_lmw);
iproc_set(powerpc_lwarx, new Powerpc::IP_move);
iproc_set(powerpc_lwax, new Powerpc::IP_move);
iproc_set(powerpc_lwz, new Powerpc::IP_move);
iproc_set(powerpc_lwzu, new Powerpc::IP_lwzu);
iproc_set(powerpc_lwzx, new Powerpc::IP_move);
iproc_set(powerpc_mfcr, new Powerpc::IP_mfcr);
iproc_set(powerpc_mfspr, new Powerpc::IP_move);
iproc_set(powerpc_mtspr, new Powerpc::IP_move);
iproc_set(powerpc_mulhw, new Powerpc::IP_mulhw);
iproc_set(powerpc_mulhwu, new Powerpc::IP_mulhwu);
iproc_set(powerpc_mullw, new Powerpc::IP_mullw);
iproc_set(powerpc_mulli, new Powerpc::IP_mullw);
iproc_set(powerpc_neg, new Powerpc::IP_neg);
iproc_set(powerpc_nor, new Powerpc::IP_nor);
iproc_set(powerpc_or, new Powerpc::IP_or(false));
iproc_set(powerpc_or_record, new Powerpc::IP_or(true));
iproc_set(powerpc_orc, new Powerpc::IP_orc);
iproc_set(powerpc_ori, new Powerpc::IP_or(false));
iproc_set(powerpc_oris, new Powerpc::IP_oris);
iproc_set(powerpc_rldic, new Powerpc::IP_rldicr);
iproc_set(powerpc_rldicr, new Powerpc::IP_rldicr);
iproc_set(powerpc_rldicl, new Powerpc::IP_rldicr);
iproc_set(powerpc_rlwimi, new Powerpc::IP_rlwimi);
iproc_set(powerpc_rlwinm, new Powerpc::IP_rlwinm(false));
iproc_set(powerpc_rlwinm_record, new Powerpc::IP_rlwinm(true));
iproc_set(powerpc_sc, new Powerpc::IP_sc);
iproc_set(powerpc_slw, new Powerpc::IP_slw);
iproc_set(powerpc_srawi, new Powerpc::IP_srawi);
iproc_set(powerpc_srw, new Powerpc::IP_srw);
iproc_set(powerpc_stb, new Powerpc::IP_stb);
iproc_set(powerpc_stbx, new Powerpc::IP_stb);
iproc_set(powerpc_sth, new Powerpc::IP_sth);
iproc_set(powerpc_stmw, new Powerpc::IP_stmw);
iproc_set(powerpc_stw, new Powerpc::IP_stw);
iproc_set(powerpc_stwcx_record, new Powerpc::IP_stw);
iproc_set(powerpc_stwu, new Powerpc::IP_stwu);
iproc_set(powerpc_stwux, new Powerpc::IP_stwu);
iproc_set(powerpc_stwx, new Powerpc::IP_stw);
iproc_set(powerpc_subf, new Powerpc::IP_subf(false));
iproc_set(powerpc_subf_record, new Powerpc::IP_subf(true));
iproc_set(powerpc_subfc, new Powerpc::IP_subfc);
iproc_set(powerpc_subfe, new Powerpc::IP_subfe);
iproc_set(powerpc_subfic, new Powerpc::IP_subfic);
iproc_set(powerpc_subfze, new Powerpc::IP_subfze);
iproc_set(powerpc_xor, new Powerpc::IP_xor(false));
iproc_set(powerpc_xor_record, new Powerpc::IP_xor(true));
iproc_set(powerpc_xori, new Powerpc::IP_xor(false));
iproc_set(powerpc_xoris, new Powerpc::IP_xoris);
}
void
DispatcherPowerpc::regcache_init()
{
if (regdict) {
REG_IAR = findRegister("iar", 32); // instruction address register (instruction pointer)
REG_LR = findRegister("lr", 32); // link register
REG_XER = findRegister("xer", 32); // fixed-point exception register
REG_CR = findRegister("cr", 32); // condition register
REG_CR0 = findRegister("cr0", 4); // CR Field 0, result of fixed-point instruction; set by record()
REG_CTR = findRegister("ctr", 32); // count register
}
}
void
DispatcherPowerpc::memory_init() {
if (BaseSemantics::StatePtr state = currentState()) {
if (BaseSemantics::MemoryStatePtr memory = state->memoryState()) {
switch (memory->get_byteOrder()) {
case ByteOrder::ORDER_LSB:
break;
case ByteOrder::ORDER_MSB:
//mlog[WARN] <<"x86 memory state is using big-endian byte order\n";
break;
case ByteOrder::ORDER_UNSPECIFIED:
memory->set_byteOrder(ByteOrder::ORDER_LSB);
break;
}
}
}
}
void
DispatcherPowerpc::set_register_dictionary(const RegisterDictionary *regdict)
{
BaseSemantics::Dispatcher::set_register_dictionary(regdict);
regcache_init();
}
RegisterDescriptor
DispatcherPowerpc::instructionPointerRegister() const {
return REG_IAR;
}
RegisterDescriptor
DispatcherPowerpc::stackPointerRegister() const {
return findRegister("r1");
}
void
DispatcherPowerpc::record(const BaseSemantics::SValuePtr &result)
{
BaseSemantics::SValuePtr two = operators->number_(3, 2);
BaseSemantics::SValuePtr four = operators->number_(3, 4);
BaseSemantics::SValuePtr v1 = operators->ite(operators->extract(result, 31, 32), four, two);
BaseSemantics::SValuePtr one = operators->number_(3, 1);
BaseSemantics::SValuePtr c = operators->ite(operators->equalToZero(result), one, v1);
BaseSemantics::SValuePtr so = operators->extract(operators->readRegister(REG_XER), 31, 32);
// Put "SO" into the lower bits, and "c" into the higher order bits
operators->writeRegister(REG_CR0, operators->concat(so, c));
}
} // namespace
} // namespace
} // namespace