bool selectBitCast(const Instruction *I);
bool selectFRem(const Instruction *I);
bool selectSDiv(const Instruction *I);
- bool selectGetElementPtr(const Instruction *I);
// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
return true;
}
-bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
- unsigned N = getRegForValue(I->getOperand(0));
- if (!N)
- return false;
- bool NIsKill = hasTrivialKill(I->getOperand(0));
-
- // Keep a running tab of the total offset to coalesce multiple N = N + Offset
- // into a single N = N + TotalOffset.
- uint64_t TotalOffs = 0;
- Type *Ty = I->getOperand(0)->getType();
- MVT VT = TLI.getPointerTy();
- for (auto OI = std::next(I->op_begin()), E = I->op_end(); OI != E; ++OI) {
- const Value *Idx = *OI;
- if (auto *StTy = dyn_cast<StructType>(Ty)) {
- unsigned Field = cast<ConstantInt>(Idx)->getZExtValue();
- // N = N + Offset
- if (Field)
- TotalOffs += DL.getStructLayout(StTy)->getElementOffset(Field);
- Ty = StTy->getElementType(Field);
- } else {
- Ty = cast<SequentialType>(Ty)->getElementType();
- // If this is a constant subscript, handle it quickly.
- if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
- if (CI->isZero())
- continue;
- // N = N + Offset
- TotalOffs +=
- DL.getTypeAllocSize(Ty) * cast<ConstantInt>(CI)->getSExtValue();
- continue;
- }
- if (TotalOffs) {
- N = emitAddSub_ri(/*UseAdd=*/true, VT, N, NIsKill, TotalOffs);
- if (!N) {
- unsigned C = fastEmit_i(VT, VT, ISD::Constant, TotalOffs);
- if (!C)
- return false;
- N = emitAddSub_rr(/*UseAdd=*/true, VT, N, NIsKill, C, true);
- if (!N)
- return false;
- }
- NIsKill = true;
- TotalOffs = 0;
- }
-
- // N = N + Idx * ElementSize;
- uint64_t ElementSize = DL.getTypeAllocSize(Ty);
- std::pair<unsigned, bool> Pair = getRegForGEPIndex(Idx);
- unsigned IdxN = Pair.first;
- bool IdxNIsKill = Pair.second;
- if (!IdxN)
- return false;
-
- if (ElementSize != 1) {
- unsigned C = fastEmit_i(VT, VT, ISD::Constant, ElementSize);
- if (!C)
- return false;
- IdxN = emitMul_rr(VT, IdxN, IdxNIsKill, C, true);
- if (!IdxN)
- return false;
- IdxNIsKill = true;
- }
- N = fastEmit_rr(VT, VT, ISD::ADD, N, NIsKill, IdxN, IdxNIsKill);
- if (!N)
- return false;
- }
- }
- if (TotalOffs) {
- N = emitAddSub_ri(/*UseAdd=*/true, VT, N, NIsKill, TotalOffs);
- if (!N) {
- unsigned C = fastEmit_i(VT, VT, ISD::Constant, TotalOffs);
- if (!C)
- return false;
- N = emitAddSub_rr(/*UseAdd=*/true, VT, N, NIsKill, C, true);
- if (!N)
- return false;
- }
- }
-
- updateValueMap(I, N);
- return true;
-}
-
bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default:
return selectRet(I);
case Instruction::FRem:
return selectFRem(I);
- case Instruction::GetElementPtr:
- return selectGetElementPtr(I);
}
// fall-back to target-independent instruction selection.
+++ /dev/null
-; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort -verify-machineinstrs < %s | FileCheck %s
-
-%struct.foo = type { i32, i64, float, double }
-
-define double* @test_struct(%struct.foo* %f) {
-; CHECK-LABEL: test_struct
-; CHECK: add x0, x0, #24
- %1 = getelementptr inbounds %struct.foo* %f, i64 0, i32 3
- ret double* %1
-}
-
-define i32* @test_array(i32* %a, i64 %i) {
-; CHECK-LABEL: test_array
-; CHECK: orr [[REG:x[0-9]+]], xzr, #0x4
-; CHECK-NEXT: madd x0, x1, [[REG]], x0
- %1 = getelementptr inbounds i32* %a, i64 %i
- ret i32* %1
-}