|
1 | 1 | // This file is a part of Julia. License is MIT: https://julialang.org/license
|
2 | 2 |
|
3 | 3 | #include "llvm-gc-interface-passes.h"
|
| 4 | +#include "llvm/IR/Intrinsics.h" |
| 5 | +#include "llvm/Support/Casting.h" |
4 | 6 |
|
5 | 7 | #define DEBUG_TYPE "late_lower_gcroot"
|
6 | 8 |
|
@@ -171,39 +173,54 @@ static std::pair<Value*,int> FindBaseValue(const State &S, Value *V, bool UseCac
|
171 | 173 | (void)LI;
|
172 | 174 | break;
|
173 | 175 | }
|
174 |
| - else if (auto II = dyn_cast<IntrinsicInst>(CurrentV)) { |
| 176 | + else if (dyn_cast<IntrinsicInst>(CurrentV) != nullptr && |
| 177 | + (cast<IntrinsicInst>(CurrentV)->getIntrinsicID() == Intrinsic::masked_load || |
| 178 | + cast<IntrinsicInst>(CurrentV)->getIntrinsicID() == Intrinsic::masked_gather)) { |
175 | 179 | // Some intrinsics behave like LoadInst followed by a SelectInst
|
176 | 180 | // This should never happen in a derived addrspace (since those cannot be stored to memory)
|
177 | 181 | // so we don't need to lift these operations, but we do need to check if it's loaded and continue walking the base pointer
|
178 |
| - if (II->getIntrinsicID() == Intrinsic::masked_load || |
179 |
| - II->getIntrinsicID() == Intrinsic::masked_gather) { |
180 |
| - if (auto VTy = dyn_cast<VectorType>(II->getType())) { |
181 |
| - if (hasLoadedTy(VTy->getElementType())) { |
182 |
| - Value *Mask = II->getOperand(2); |
183 |
| - Value *Passthrough = II->getOperand(3); |
184 |
| - if (!isa<Constant>(Mask) || !cast<Constant>(Mask)->isAllOnesValue()) { |
185 |
| - assert(isa<UndefValue>(Passthrough) && "unimplemented"); |
186 |
| - (void)Passthrough; |
| 182 | + auto II = dyn_cast<IntrinsicInst>(CurrentV); |
| 183 | + if (auto VTy = dyn_cast<VectorType>(II->getType())) { |
| 184 | + if (hasLoadedTy(VTy->getElementType())) { |
| 185 | + Value *Mask = II->getOperand(2); |
| 186 | + Value *Passthrough = II->getOperand(3); |
| 187 | + if (!isa<Constant>(Mask) || !cast<Constant>(Mask)->isAllOnesValue()) { |
| 188 | + assert(isa<UndefValue>(Passthrough) && "unimplemented"); |
| 189 | + (void)Passthrough; |
| 190 | + } |
| 191 | + CurrentV = II->getOperand(0); |
| 192 | + if (II->getIntrinsicID() == Intrinsic::masked_load) { |
| 193 | + fld_idx = -1; |
| 194 | + if (!isSpecialPtr(CurrentV->getType())) { |
| 195 | + CurrentV = ConstantPointerNull::get(PointerType::get(V->getContext(), 0)); |
187 | 196 | }
|
188 |
| - CurrentV = II->getOperand(0); |
189 |
| - if (II->getIntrinsicID() == Intrinsic::masked_load) { |
190 |
| - fld_idx = -1; |
191 |
| - if (!isSpecialPtr(CurrentV->getType())) { |
| 197 | + } else { |
| 198 | + if (auto VTy2 = dyn_cast<VectorType>(CurrentV->getType())) { |
| 199 | + if (!isSpecialPtr(VTy2->getElementType())) { |
192 | 200 | CurrentV = ConstantPointerNull::get(PointerType::get(V->getContext(), 0));
|
193 |
| - } |
194 |
| - } else { |
195 |
| - if (auto VTy2 = dyn_cast<VectorType>(CurrentV->getType())) { |
196 |
| - if (!isSpecialPtr(VTy2->getElementType())) { |
197 |
| - CurrentV = ConstantPointerNull::get(PointerType::get(V->getContext(), 0)); |
198 |
| - fld_idx = -1; |
199 |
| - } |
| 201 | + fld_idx = -1; |
200 | 202 | }
|
201 | 203 | }
|
202 |
| - continue; |
203 | 204 | }
|
| 205 | + continue; |
| 206 | + } |
| 207 | + } |
| 208 | + // In general a load terminates a walk |
| 209 | + break; |
| 210 | + } |
| 211 | + else if (dyn_cast<IntrinsicInst>(CurrentV) != nullptr && cast<IntrinsicInst>(CurrentV)->getIntrinsicID() == Intrinsic::vector_extract) { |
| 212 | + auto II = dyn_cast<IntrinsicInst>(CurrentV); |
| 213 | + if (auto VTy = dyn_cast<VectorType>(II->getType())) { |
| 214 | + if (hasLoadedTy(VTy->getElementType())) { |
| 215 | + Value *Idx = II->getOperand(1); |
| 216 | + if (!isa<ConstantInt>(Idx)) { |
| 217 | + assert(isa<UndefValue>(Idx) && "unimplemented"); |
| 218 | + (void)Idx; |
| 219 | + } |
| 220 | + CurrentV = II->getOperand(0); |
| 221 | + fld_idx = -1; |
| 222 | + continue; |
204 | 223 | }
|
205 |
| - // In general a load terminates a walk |
206 |
| - break; |
207 | 224 | }
|
208 | 225 | }
|
209 | 226 | else if (auto CI = dyn_cast<CallInst>(CurrentV)) {
|
@@ -530,6 +547,20 @@ SmallVector<int, 0> LateLowerGCFrame::NumberAllBase(State &S, Value *CurrentV) {
|
530 | 547 | Numbers = NumberAll(S, IEI->getOperand(0));
|
531 | 548 | int ElNumber = Number(S, IEI->getOperand(1));
|
532 | 549 | Numbers[idx] = ElNumber;
|
| 550 | + } else if (dyn_cast<IntrinsicInst>(CurrentV) != nullptr && dyn_cast<IntrinsicInst>(CurrentV)->getIntrinsicID() == Intrinsic::vector_insert) { |
| 551 | + auto *VII = cast<IntrinsicInst>(CurrentV); |
| 552 | + // Vector insert is a bit like a shuffle so use the same approach |
| 553 | + SmallVector<int, 0> Numbers1 = NumberAll(S, VII->getOperand(0)); |
| 554 | + SmallVector<int, 0> Numbers2 = NumberAll(S, VII->getOperand(1)); |
| 555 | + unsigned first_idx = cast<ConstantInt>(VII->getOperand(2))->getZExtValue(); |
| 556 | + for (unsigned i = 0; i < Numbers1.size(); ++i) { |
| 557 | + if (i < first_idx) |
| 558 | + Numbers.push_back(Numbers1[i]); |
| 559 | + else if (i - first_idx < Numbers2.size()) |
| 560 | + Numbers.push_back(Numbers2[i - first_idx]); |
| 561 | + else |
| 562 | + Numbers.push_back(Numbers1[i]); |
| 563 | + } |
533 | 564 | } else if (auto *IVI = dyn_cast<InsertValueInst>(CurrentV)) {
|
534 | 565 | Numbers = NumberAll(S, IVI->getAggregateOperand());
|
535 | 566 | auto Tracked = TrackCompositeType(IVI->getType());
|
@@ -1206,6 +1237,10 @@ State LateLowerGCFrame::LocalScan(Function &F) {
|
1206 | 1237 | }
|
1207 | 1238 | }
|
1208 | 1239 | }
|
| 1240 | + if (II->getIntrinsicID() == Intrinsic::vector_extract || II->getIntrinsicID() == Intrinsic::vector_insert) { |
| 1241 | + // These are not real defs |
| 1242 | + continue; |
| 1243 | + } |
1209 | 1244 | }
|
1210 | 1245 | auto callee = CI->getCalledFunction();
|
1211 | 1246 | if (callee && callee == typeof_func) {
|
|
0 commit comments