diff options
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp')
-rw-r--r-- | llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 6650a1e2073..c891502112f 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -287,6 +288,77 @@ bool IRTranslator::translateCast(unsigned Opcode, const User &U) { return true; } +bool IRTranslator::translateGetElementPtr(const User &U) { + // FIXME: support vector GEPs. + if (U.getType()->isVectorTy()) + return false; + + Value &Op0 = *U.getOperand(0); + unsigned BaseReg = getOrCreateVReg(Op0); + LLT PtrTy(*Op0.getType()); + unsigned PtrSize = DL->getPointerSizeInBits(PtrTy.getAddressSpace()); + LLT OffsetTy = LLT::scalar(PtrSize); + + int64_t Offset = 0; + for (gep_type_iterator GTI = gep_type_begin(&U), E = gep_type_end(&U); + GTI != E; ++GTI) { + const Value *Idx = GTI.getOperand(); + if (StructType *StTy = dyn_cast<StructType>(*GTI)) { + unsigned Field = cast<Constant>(Idx)->getUniqueInteger().getZExtValue(); + Offset += DL->getStructLayout(StTy)->getElementOffset(Field); + continue; + } else { + uint64_t ElementSize = DL->getTypeAllocSize(GTI.getIndexedType()); + + // If this is a scalar constant or a splat vector of constants, + // handle it quickly. + if (const auto *CI = dyn_cast<ConstantInt>(Idx)) { + Offset += ElementSize * CI->getSExtValue(); + continue; + } + + if (Offset != 0) { + unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy); + unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy); + MIRBuilder.buildConstant(OffsetReg, Offset); + MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg); + + BaseReg = NewBaseReg; + Offset = 0; + } + + // N = N + Idx * ElementSize; + unsigned ElementSizeReg = MRI->createGenericVirtualRegister(OffsetTy); + MIRBuilder.buildConstant(ElementSizeReg, ElementSize); + + unsigned IdxReg = getOrCreateVReg(*Idx); + if (MRI->getType(IdxReg) != OffsetTy) { + unsigned NewIdxReg = MRI->createGenericVirtualRegister(OffsetTy); + MIRBuilder.buildSExtOrTrunc(NewIdxReg, IdxReg); + IdxReg = NewIdxReg; + } + + unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy); + MIRBuilder.buildMul(OffsetReg, ElementSizeReg, IdxReg); + + unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy); + MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg); + BaseReg = NewBaseReg; + } + } + + if (Offset != 0) { + unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy); + MIRBuilder.buildConstant(OffsetReg, Offset); + MIRBuilder.buildGEP(getOrCreateVReg(U), BaseReg, OffsetReg); + return true; + } + + MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg); + return true; +} + + bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID) { unsigned Op = 0; |