Commit becb85f1 by Sagar Thakur Committed by Jim Stichnoth

[Subzero][MIPS] Implements atomic intrinsics for MIPS32

R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2504253002 . Patch from Sagar Thakur <sagar.thakur@imgtec.com>.
parent 6e03343b
......@@ -160,14 +160,14 @@ template <typename Type> struct ThreadData {
};
template <typename Type> void *threadWrapper(void *Data) {
#ifdef ARM32
#if defined(ARM32) || defined(MIPS32)
// Given that most of times these crosstests for ARM are run under qemu, we
// set a lower NumReps to allow crosstests to complete within a reasonable
// amount of time.
static const size_t NumReps = 1000;
#else // ARM32
#else // ARM32 || MIPS32
static const size_t NumReps = 8000;
#endif // ARM32
#endif // ARM32 || MIPS32
ThreadData<Type> *TData = reinterpret_cast<ThreadData<Type> *>(Data);
for (size_t i = 0; i < NumReps; ++i) {
......
......@@ -696,6 +696,12 @@ void AssemblerMIPS32::ldc1(const Operand *OpRt, const Operand *OpBase,
emitInst(Opcode);
}
void AssemblerMIPS32::ll(const Operand *OpRt, const Operand *OpBase,
const uint32_t Offset) {
static constexpr IValueT Opcode = 0xC0000000;
emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "ll");
}
void AssemblerMIPS32::lw(const Operand *OpRt, const Operand *OpBase,
const uint32_t Offset) {
switch (OpRt->getType()) {
......@@ -959,6 +965,12 @@ void AssemblerMIPS32::ret(void) {
nop(); // delay slot
}
void AssemblerMIPS32::sc(const Operand *OpRt, const Operand *OpBase,
const uint32_t Offset) {
static constexpr IValueT Opcode = 0xE0000000;
emitRtRsImm16(Opcode, OpRt, OpBase, Offset, "sc");
}
void AssemblerMIPS32::sll(const Operand *OpRd, const Operand *OpRt,
const uint32_t Sa) {
static constexpr IValueT Opcode = 0x00000000;
......@@ -1122,6 +1134,11 @@ void AssemblerMIPS32::swc1(const Operand *OpRt, const Operand *OpBase,
emitInst(Opcode);
}
void AssemblerMIPS32::sync() {
static constexpr IValueT Opcode = 0x0000000f;
emitInst(Opcode);
}
void AssemblerMIPS32::teq(const Operand *OpRs, const Operand *OpRt,
const uint32_t TrapCode) {
IValueT Opcode = 0x00000034;
......
......@@ -195,6 +195,8 @@ public:
void ldc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff,
const RelocOp Reloc);
void ll(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset);
void lw(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset);
void lwc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff,
......@@ -252,6 +254,8 @@ public:
void ret(void);
void sc(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset);
void sll(const Operand *OpRd, const Operand *OpRt, const uint32_t Sa);
void sllv(const Operand *OpRd, const Operand *OpRt, const Operand *OpRs);
......@@ -290,6 +294,8 @@ public:
void swc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff,
const RelocOp Reloc);
void sync();
void teq(const Operand *OpRs, const Operand *OpRt, const uint32_t TrapCode);
void trunc_l_d(const Operand *OpFd, const Operand *OpFs);
......
......@@ -97,6 +97,7 @@ template <> const char *InstMIPS32Div_s::Opcode = "div.s";
template <> const char *InstMIPS32Divu::Opcode = "divu";
template <> const char *InstMIPS32La::Opcode = "la";
template <> const char *InstMIPS32Ldc1::Opcode = "ldc1";
template <> const char *InstMIPS32Ll::Opcode = "ll";
template <> const char *InstMIPS32Lui::Opcode = "lui";
template <> const char *InstMIPS32Lw::Opcode = "lw";
template <> const char *InstMIPS32Lwc1::Opcode = "lwc1";
......@@ -124,6 +125,7 @@ template <> const char *InstMIPS32Multu::Opcode = "multu";
template <> const char *InstMIPS32Nor::Opcode = "nor";
template <> const char *InstMIPS32Or::Opcode = "or";
template <> const char *InstMIPS32Ori::Opcode = "ori";
template <> const char *InstMIPS32Sc::Opcode = "sc";
template <> const char *InstMIPS32Sdc1::Opcode = "sdc1";
template <> const char *InstMIPS32Sll::Opcode = "sll";
template <> const char *InstMIPS32Sllv::Opcode = "sllv";
......@@ -143,6 +145,7 @@ template <> const char *InstMIPS32Sub_s::Opcode = "sub.s";
template <> const char *InstMIPS32Subu::Opcode = "subu";
template <> const char *InstMIPS32Sw::Opcode = "sw";
template <> const char *InstMIPS32Swc1::Opcode = "swc1";
const char *InstMIPS32Sync::Opcode = "sync";
template <> const char *InstMIPS32Teq::Opcode = "teq";
template <> const char *InstMIPS32Trunc_l_d::Opcode = "trunc.l.d";
template <> const char *InstMIPS32Trunc_l_s::Opcode = "trunc.l.s";
......@@ -429,8 +432,12 @@ void InstMIPS32Br::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
if (Label != nullptr) {
// Intra-block branches are of kind bcc
Asm->bcc(Predicate, getSrc(0), getSrc(1),
Asm->getOrCreateLocalLabel(Label->getNumber()));
if (isUnconditionalBranch()) {
Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber()));
} else {
Asm->bcc(Predicate, getSrc(0), getSrc(1),
Asm->getOrCreateLocalLabel(Label->getNumber()));
}
} else if (isUnconditionalBranch()) {
Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()));
} else {
......@@ -465,10 +472,14 @@ void InstMIPS32Br::emit(const Cfg *Func) const {
Str << "\t"
"b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t";
if (Label != nullptr) {
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", " << Label->getLabelName();
if (isUnconditionalBranch()) {
Str << Label->getLabelName();
} else {
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", " << Label->getLabelName();
}
} else {
if (isUnconditionalBranch()) {
Str << getTargetFalse()->getAsmName();
......@@ -513,10 +524,14 @@ void InstMIPS32Br::dump(const Cfg *Func) const {
"b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t";
if (Label != nullptr) {
getSrc(0)->dump(Func);
Str << ", ";
getSrc(1)->dump(Func);
Str << ", " << Label->getLabelName();
if (isUnconditionalBranch()) {
Str << Label->getLabelName();
} else {
getSrc(0)->dump(Func);
Str << ", ";
getSrc(1)->dump(Func);
Str << ", " << Label->getLabelName();
}
} else {
if (isUnconditionalBranch()) {
Str << getTargetFalse()->getAsmName();
......@@ -886,6 +901,14 @@ template <> void InstMIPS32Ldc1::emitIAS(const Cfg *Func) const {
Asm->ldc1(getDest(), Mem->getBase(), Mem->getOffset(), Reloc);
}
template <> void InstMIPS32Ll::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0));
ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
uint32_t Imm = static_cast<uint32_t>(Offset->getValue());
Asm->ll(getDest(), Mem->getBase(), Imm);
}
template <> void InstMIPS32Lw::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(0));
......@@ -1067,6 +1090,14 @@ template <> void InstMIPS32Ori::emitIAS(const Cfg *Func) const {
Asm->ori(getDest(), getSrc(0), Imm);
}
template <> void InstMIPS32Sc::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(1));
ConstantInteger32 *Offset = llvm::cast<ConstantInteger32>(Mem->getOffset());
uint32_t Imm = static_cast<uint32_t>(Offset->getValue());
Asm->sc(getSrc(0), Mem->getBase(), Imm);
}
template <> void InstMIPS32Sll::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->sll(getDest(), getSrc(0), Imm);
......@@ -1162,6 +1193,11 @@ template <> void InstMIPS32Swc1::emitIAS(const Cfg *Func) const {
Asm->swc1(getSrc(0), Mem->getBase(), Mem->getOffset(), Reloc);
}
void InstMIPS32Sync::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->sync();
}
template <> void InstMIPS32Teq::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->teq(getSrc(0), getSrc(1), getTrapCode());
......
......@@ -224,6 +224,7 @@ public:
La,
Label,
Ldc1,
Ll,
Lui,
Lw,
Lwc1,
......@@ -253,6 +254,7 @@ public:
Or,
Ori,
Ret,
Sc,
Sdc1,
Sll,
Sllv,
......@@ -272,6 +274,7 @@ public:
Subu,
Sw,
Swc1,
Sync,
Teq,
Trunc_l_d,
Trunc_l_s,
......@@ -598,35 +601,40 @@ public:
return;
Ostream &Str = Func->getContext()->getStrEmit();
const Type Ty = getDest()->getType();
switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
<< "lb"
<< "\t";
break;
case IceType_i16:
Str << "\t"
<< "lh"
<< "\t";
break;
case IceType_i32:
Str << "\t"
<< "lw"
<< "\t";
break;
case IceType_f32:
Str << "\t"
<< "lwc1"
<< "\t";
break;
case IceType_f64:
Str << "\t"
<< "ldc1"
<< "\t";
break;
default:
llvm_unreachable("InstMIPS32Load unknown type");
if (getKind() == static_cast<InstKind>(Ll)) {
Str << "\t" << Opcode << "\t";
} else {
switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
"lb"
"\t";
break;
case IceType_i16:
Str << "\t"
"lh"
"\t";
break;
case IceType_i32:
Str << "\t"
"lw"
"\t";
break;
case IceType_f32:
Str << "\t"
"lwc1"
"\t";
break;
case IceType_f64:
Str << "\t"
"ldc1"
"\t";
break;
default:
llvm_unreachable("InstMIPS32Load unknown type");
}
}
getDest()->emit(Func);
Str << ", ";
......@@ -683,35 +691,40 @@ public:
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 2);
const Type Ty = getSrc(0)->getType();
switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
<< "sb"
<< "\t";
break;
case IceType_i16:
Str << "\t"
<< "sh"
<< "\t";
break;
case IceType_i32:
Str << "\t"
<< "sw"
<< "\t";
break;
case IceType_f32:
Str << "\t"
<< "swc1"
<< "\t";
break;
case IceType_f64:
Str << "\t"
<< "sdc1"
<< "\t";
break;
default:
llvm_unreachable("InstMIPS32Store unknown type");
if (getKind() == static_cast<InstKind>(Sc)) {
Str << "\t" << Opcode << "\t";
} else {
switch (Ty) {
case IceType_i1:
case IceType_i8:
Str << "\t"
"sb"
"\t";
break;
case IceType_i16:
Str << "\t"
"sh"
"\t";
break;
case IceType_i32:
Str << "\t"
"sw"
"\t";
break;
case IceType_f32:
Str << "\t"
"swc1"
"\t";
break;
case IceType_f64:
Str << "\t"
"sdc1"
"\t";
break;
default:
llvm_unreachable("InstMIPS32Store unknown type");
}
}
getSrc(0)->emit(Func);
Str << ", ";
......@@ -793,6 +806,13 @@ public:
InstMIPS32Br(Func, NoCondTarget, Target, NoLabel, CondMIPS32::AL);
}
static InstMIPS32Br *create(Cfg *Func, CfgNode *Target,
const InstMIPS32Label *Label) {
constexpr CfgNode *NoCondTarget = nullptr;
return new (Func->allocate<InstMIPS32Br>())
InstMIPS32Br(Func, NoCondTarget, Target, Label, CondMIPS32::AL);
}
/// Create a conditional branch to the false node.
static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue,
CfgNode *TargetFalse, Operand *Src0,
......@@ -921,6 +941,40 @@ private:
static const char *Opcode;
};
class InstMIPS32Sync : public InstMIPS32 {
InstMIPS32Sync() = delete;
InstMIPS32Sync(const InstMIPS32Sync &) = delete;
InstMIPS32Sync &operator=(const InstMIPS32Sync &) = delete;
public:
static InstMIPS32Sync *create(Cfg *Func) {
return new (Func->allocate<InstMIPS32Sync>()) InstMIPS32Sync(Func);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << Opcode << "\t";
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Func->getContext()->getStrDump() << Opcode << "\t";
}
static bool classof(const Inst *Inst) {
return isClassof(Inst, InstMIPS32::Sync);
}
void emitIAS(const Cfg *Func) const override;
private:
InstMIPS32Sync(Cfg *Func) : InstMIPS32(Func, InstMIPS32::Sync, 0, nullptr) {}
static const char *Opcode;
};
// Trap
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32Trap : public InstMIPS32 {
......@@ -1175,6 +1229,7 @@ using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>;
using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Ldc1 = InstMIPS32Load<InstMIPS32::Ldc1>;
using InstMIPS32Ll = InstMIPS32Load<InstMIPS32::Ll>;
using InstMIPS32Lui = InstMIPS32UnaryopGPR<InstMIPS32::Lui>;
using InstMIPS32Lw = InstMIPS32Load<InstMIPS32::Lw>;
using InstMIPS32Lwc1 = InstMIPS32Load<InstMIPS32::Lwc1>;
......@@ -1202,6 +1257,7 @@ using InstMIPS32Multu = InstMIPS32ThreeAddrGPR<InstMIPS32::Multu>;
using InstMIPS32Nor = InstMIPS32ThreeAddrGPR<InstMIPS32::Nor>;
using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
using InstMIPS32Sc = InstMIPS32Store<InstMIPS32::Sc>;
using InstMIPS32Sdc1 = InstMIPS32Store<InstMIPS32::Sdc1>;
using InstMIPS32Sll = InstMIPS32Imm16<InstMIPS32::Sll>;
using InstMIPS32Sllv = InstMIPS32ThreeAddrGPR<InstMIPS32::Sllv>;
......
......@@ -175,6 +175,10 @@ public:
void _br(CfgNode *Target) { Context.insert<InstMIPS32Br>(Target); }
void _br(CfgNode *Target, const InstMIPS32Label *Label) {
Context.insert<InstMIPS32Br>(Target, Label);
}
void _br(CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0,
Operand *Src1, CondMIPS32::Cond Condition) {
Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Src1,
......@@ -329,6 +333,10 @@ public:
Context.insert<InstMIPS32Ldc1>(Value, Mem, Reloc);
}
void _ll(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Ll>(Value, Mem);
}
void _lw(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Lw>(Value, Mem);
}
......@@ -474,6 +482,10 @@ public:
Context.insert<InstMIPS32Ori>(Dest, Src, Imm);
}
InstMIPS32Sc *_sc(Variable *Value, OperandMIPS32Mem *Mem) {
return Context.insert<InstMIPS32Sc>(Value, Mem);
}
void _sdc1(Variable *Value, OperandMIPS32Mem *Mem) {
Context.insert<InstMIPS32Sdc1>(Value, Mem);
}
......@@ -550,6 +562,8 @@ public:
Context.insert<InstMIPS32Swc1>(Value, Mem);
}
void _sync() { Context.insert<InstMIPS32Sync>(); }
void _teq(Variable *Src0, Variable *Src1, uint32_t TrapCode) {
Context.insert<InstMIPS32Teq>(Src0, Src1, TrapCode);
}
......@@ -746,6 +760,8 @@ protected:
void lowerFcmp(const InstFcmp *Instr) override;
void lowerIcmp(const InstIcmp *Instr) override;
void lower64Icmp(const InstIcmp *Instr);
void createArithInst(Intrinsics::AtomicRMWOperation Operation, Variable *Dest,
Variable *Src0, Variable *Src1);
void lowerIntrinsicCall(const InstIntrinsicCall *Instr) override;
void lowerInsertElement(const InstInsertElement *Instr) override;
void lowerLoad(const InstLoad *Instr) override;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment