/// emitted.
bool translateBitCast(const CastInst &CI);
+ /// Translate an LLVM load instruction into generic IR.
+ bool translateLoad(const LoadInst &LI);
+
+ /// Translate an LLVM store instruction into generic IR.
+ bool translateStore(const StoreInst &SI);
+
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
/// given generic Opcode.
bool translateCast(unsigned Opcode, const CastInst &CI);
/// If such VReg does not exist, it is created.
unsigned getOrCreateVReg(const Value &Val);
+ /// Get the alignment of the given memory operation instruction. This will
+ /// either be the explicitly specified value or the ABI-required alignment for
+ /// the type being accessed (according to the Module's DataLayout).
+ unsigned getMemOpAlignment(const Instruction &I);
+
/// Get the MachineBasicBlock that represents \p BB.
/// If such basic block does not exist, it is created.
MachineBasicBlock &getOrCreateBB(const BasicBlock &BB);
+
public:
// Ctor, nothing fancy.
IRTranslator();
/// \return The newly created instruction.
MachineInstr *buildCopy(unsigned Res, unsigned Op);
+ /// Build and insert `Res<def> = G_LOAD { VTy, PTy } Addr, MMO`.
+ ///
+ /// Loads the value of (sized) type \p VTy stored at \p Addr (in address space
+ /// given by \p PTy). Puts the result in Res.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ ///
+ /// \return The newly created instruction.
+ MachineInstr *buildLoad(LLT VTy, LLT PTy, unsigned Res, unsigned Addr,
+ MachineMemOperand &MMO);
+
+ /// Build and insert `G_STORE { VTy, PTy } Val, Addr, MMO`.
+ ///
+ /// Stores the value \p Val of (sized) \p VTy to \p Addr (in address space
+ /// given by \p PTy).
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ ///
+ /// \return The newly created instruction.
+ MachineInstr *buildStore(LLT VTy, LLT PTy, unsigned Val, unsigned Addr,
+ MachineMemOperand &MMO);
+
/// Build and insert `Res0<def>, ... = G_EXTRACT Ty Src, Idx0, ...`.
///
/// If \p Ty has size N bits, G_EXTRACT sets \p Res[0] to bits `[Idxs[0],
let hasSideEffects = 0;
}
-
//------------------------------------------------------------------------------
// Binary ops.
//------------------------------------------------------------------------------
+
// Generic addition.
def G_ADD : Instruction {
let OutOperandList = (outs unknown:$dst);
}
//------------------------------------------------------------------------------
+// Memory ops
+//------------------------------------------------------------------------------
+
+// Generic load. Expects a MachineMemOperand in addition to explicit operands.
+def G_LOAD : Instruction {
+ let OutOperandList = (outs unknown:$dst);
+ let InOperandList = (ins unknown:$addr);
+ let hasSideEffects = 0;
+ let mayLoad = 1;
+}
+
+// Generic store. Expects a MachineMemOperand in addition to explicit operands.
+def G_STORE : Instruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins unknown:$src, unknown:$addr);
+ let hasSideEffects = 0;
+ let mayStore = 1;
+}
+
+//------------------------------------------------------------------------------
// Variadic ops
//------------------------------------------------------------------------------
/// COPY is the relevant instruction.
HANDLE_TARGET_OPCODE(G_BITCAST)
+/// Generic load.
+HANDLE_TARGET_OPCODE(G_LOAD)
+
+/// Generic store.
+HANDLE_TARGET_OPCODE(G_STORE)
+
/// Generic BRANCH instruction. This is an unconditional branch.
HANDLE_TARGET_OPCODE(G_BR)
return ValReg;
}
+unsigned IRTranslator::getMemOpAlignment(const Instruction &I) {
+ unsigned Alignment = 0;
+ Type *ValTy = nullptr;
+ if (const StoreInst *SI = dyn_cast<StoreInst>(&I)) {
+ Alignment = SI->getAlignment();
+ ValTy = SI->getValueOperand()->getType();
+ } else if (const LoadInst *LI = dyn_cast<LoadInst>(&I)) {
+ Alignment = LI->getAlignment();
+ ValTy = LI->getType();
+ } else
+ llvm_unreachable("unhandled memory instruction");
+
+ return Alignment ? Alignment : DL->getABITypeAlignment(ValTy);
+}
+
MachineBasicBlock &IRTranslator::getOrCreateBB(const BasicBlock &BB) {
MachineBasicBlock *&MBB = BBToMBB[&BB];
if (!MBB) {
return true;
}
+bool IRTranslator::translateLoad(const LoadInst &LI) {
+ assert(LI.isSimple() && "only simple loads are supported at the moment");
+
+ MachineFunction &MF = MIRBuilder.getMF();
+ unsigned Res = getOrCreateVReg(LI);
+ unsigned Addr = getOrCreateVReg(*LI.getPointerOperand());
+ LLT VTy{*LI.getType()}, PTy{*LI.getPointerOperand()->getType()};
+
+ MIRBuilder.buildLoad(
+ VTy, PTy, Res, Addr,
+ *MF.getMachineMemOperand(MachinePointerInfo(LI.getPointerOperand()),
+ MachineMemOperand::MOLoad,
+ VTy.getSizeInBits() / 8, getMemOpAlignment(LI)));
+ return true;
+}
+
+bool IRTranslator::translateStore(const StoreInst &SI) {
+ assert(SI.isSimple() && "only simple loads are supported at the moment");
+
+ MachineFunction &MF = MIRBuilder.getMF();
+ unsigned Val = getOrCreateVReg(*SI.getValueOperand());
+ unsigned Addr = getOrCreateVReg(*SI.getPointerOperand());
+ LLT VTy{*SI.getValueOperand()->getType()},
+ PTy{*SI.getPointerOperand()->getType()};
+
+ MIRBuilder.buildStore(
+ VTy, PTy, Val, Addr,
+ *MF.getMachineMemOperand(MachinePointerInfo(SI.getPointerOperand()),
+ MachineMemOperand::MOStore,
+ VTy.getSizeInBits() / 8, getMemOpAlignment(SI)));
+ return true;
+}
+
bool IRTranslator::translateBitCast(const CastInst &CI) {
if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) {
MIRBuilder.buildCopy(getOrCreateVReg(CI),
case Instruction::PtrToInt:
return translateCast(TargetOpcode::G_PTRTOINT, cast<CastInst>(Inst));
+ // Memory ops.
+ case Instruction::Load:
+ return translateLoad(cast<LoadInst>(Inst));
+ case Instruction::Store:
+ return translateStore(cast<StoreInst>(Inst));
+
case Instruction::Alloca:
return translateStaticAlloca(cast<AllocaInst>(Inst));
return buildInstr(TargetOpcode::COPY, Res, Op);
}
+MachineInstr *MachineIRBuilder::buildLoad(LLT VTy, LLT PTy, unsigned Res,
+ unsigned Addr,
+ MachineMemOperand &MMO) {
+ MachineInstr *NewMI = buildInstr(TargetOpcode::G_LOAD, {VTy, PTy}, Res, Addr);
+ NewMI->addMemOperand(getMF(), &MMO);
+ return NewMI;
+}
+
+MachineInstr *MachineIRBuilder::buildStore(LLT VTy, LLT PTy, unsigned Val,
+ unsigned Addr,
+ MachineMemOperand &MMO) {
+ MachineInstr *NewMI = buildInstr(TargetOpcode::G_STORE, {VTy, PTy});
+ NewMI->addMemOperand(getMF(), &MMO);
+ MachineInstrBuilder(getMF(), NewMI).addReg(Val).addReg(Addr);
+ return NewMI;
+}
+
MachineInstr *MachineIRBuilder::buildExtract(LLT Ty, ArrayRef<unsigned> Results,
unsigned Src,
ArrayRef<unsigned> Indexes) {
%res2 = bitcast <2 x i32> %res1 to i64
ret i64 %res2
}
+
+; CHECK-LABEL: name: load
+; CHECK: [[ADDR:%[0-9]+]](64) = COPY %x0
+; CHECK: [[ADDR42:%[0-9]+]](64) = COPY %x1
+; CHECK: [[VAL1:%[0-9]+]](64) = G_LOAD { s64, p0 } [[ADDR]] :: (load 8 from %ir.addr, align 16)
+; CHECK: [[VAL2:%[0-9]+]](64) = G_LOAD { s64, p42 } [[ADDR42]] :: (load 8 from %ir.addr42)
+; CHECK: [[SUM:%.*]](64) = G_ADD s64 [[VAL1]], [[VAL2]]
+; CHECK: %x0 = COPY [[SUM]]
+; CHECK: RET_ReallyLR implicit %x0
+define i64 @load(i64* %addr, i64 addrspace(42)* %addr42) {
+ %val1 = load i64, i64* %addr, align 16
+ %val2 = load i64, i64 addrspace(42)* %addr42
+ %sum = add i64 %val1, %val2
+ ret i64 %sum
+}
+
+; CHECK-LABEL: name: store
+; CHECK: [[ADDR:%[0-9]+]](64) = COPY %x0
+; CHECK: [[ADDR42:%[0-9]+]](64) = COPY %x1
+; CHECK: [[VAL1:%[0-9]+]](64) = COPY %x2
+; CHECK: [[VAL2:%[0-9]+]](64) = COPY %x3
+; CHECK: G_STORE { s64, p0 } [[VAL1]], [[ADDR]] :: (store 8 into %ir.addr, align 16)
+; CHECK: G_STORE { s64, p42 } [[VAL2]], [[ADDR42]] :: (store 8 into %ir.addr42)
+; CHECK: RET_ReallyLR
+define void @store(i64* %addr, i64 addrspace(42)* %addr42, i64 %val1, i64 %val2) {
+ store i64 %val1, i64* %addr, align 16
+ store i64 %val2, i64 addrspace(42)* %addr42
+ %sum = add i64 %val1, %val2
+ ret void
+}