1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements MemorySlot-related interfaces for CIR dialect |
10 | // operations. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/CIR/Dialect/IR/CIRDialect.h" |
15 | |
16 | using namespace mlir; |
17 | |
18 | /// Conditions the deletion of the operation to the removal of all its uses. |
19 | static bool forwardToUsers(Operation *op, |
20 | SmallVectorImpl<OpOperand *> &newBlockingUses) { |
21 | for (Value result : op->getResults()) |
22 | for (OpOperand &use : result.getUses()) |
23 | newBlockingUses.push_back(&use); |
24 | return true; |
25 | } |
26 | |
27 | //===----------------------------------------------------------------------===// |
28 | // Interfaces for AllocaOp |
29 | //===----------------------------------------------------------------------===// |
30 | |
31 | llvm::SmallVector<MemorySlot> cir::AllocaOp::getPromotableSlots() { |
32 | return {MemorySlot{getResult(), getAllocaType()}}; |
33 | } |
34 | |
35 | Value cir::AllocaOp::getDefaultValue(const MemorySlot &slot, |
36 | OpBuilder &builder) { |
37 | return builder.create<cir::ConstantOp>(getLoc(), |
38 | cir::UndefAttr::get(slot.elemType)); |
39 | } |
40 | |
41 | void cir::AllocaOp::handleBlockArgument(const MemorySlot &slot, |
42 | BlockArgument argument, |
43 | OpBuilder &builder) {} |
44 | |
45 | std::optional<PromotableAllocationOpInterface> |
46 | cir::AllocaOp::handlePromotionComplete(const MemorySlot &slot, |
47 | Value defaultValue, OpBuilder &builder) { |
48 | if (defaultValue && defaultValue.use_empty()) |
49 | defaultValue.getDefiningOp()->erase(); |
50 | this->erase(); |
51 | return std::nullopt; |
52 | } |
53 | |
54 | //===----------------------------------------------------------------------===// |
55 | // Interfaces for LoadOp |
56 | //===----------------------------------------------------------------------===// |
57 | |
58 | bool cir::LoadOp::loadsFrom(const MemorySlot &slot) { |
59 | return getAddr() == slot.ptr; |
60 | } |
61 | |
62 | bool cir::LoadOp::storesTo(const MemorySlot &slot) { return false; } |
63 | |
64 | Value cir::LoadOp::getStored(const MemorySlot &slot, OpBuilder &builder, |
65 | Value reachingDef, const DataLayout &dataLayout) { |
66 | llvm_unreachable("getStored should not be called on LoadOp" ); |
67 | } |
68 | |
69 | bool cir::LoadOp::canUsesBeRemoved( |
70 | const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses, |
71 | SmallVectorImpl<OpOperand *> &newBlockingUses, |
72 | const DataLayout &dataLayout) { |
73 | if (blockingUses.size() != 1) |
74 | return false; |
75 | Value blockingUse = (*blockingUses.begin())->get(); |
76 | return blockingUse == slot.ptr && getAddr() == slot.ptr && |
77 | getType() == slot.elemType; |
78 | } |
79 | |
80 | DeletionKind cir::LoadOp::removeBlockingUses( |
81 | const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses, |
82 | OpBuilder &builder, Value reachingDefinition, |
83 | const DataLayout &dataLayout) { |
84 | getResult().replaceAllUsesWith(reachingDefinition); |
85 | return DeletionKind::Delete; |
86 | } |
87 | |
88 | //===----------------------------------------------------------------------===// |
89 | // Interfaces for StoreOp |
90 | //===----------------------------------------------------------------------===// |
91 | |
92 | bool cir::StoreOp::loadsFrom(const MemorySlot &slot) { return false; } |
93 | |
94 | bool cir::StoreOp::storesTo(const MemorySlot &slot) { |
95 | return getAddr() == slot.ptr; |
96 | } |
97 | |
98 | Value cir::StoreOp::getStored(const MemorySlot &slot, OpBuilder &builder, |
99 | Value reachingDef, const DataLayout &dataLayout) { |
100 | return getValue(); |
101 | } |
102 | |
103 | bool cir::StoreOp::canUsesBeRemoved( |
104 | const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses, |
105 | SmallVectorImpl<OpOperand *> &newBlockingUses, |
106 | const DataLayout &dataLayout) { |
107 | if (blockingUses.size() != 1) |
108 | return false; |
109 | Value blockingUse = (*blockingUses.begin())->get(); |
110 | return blockingUse == slot.ptr && getAddr() == slot.ptr && |
111 | getValue() != slot.ptr && slot.elemType == getValue().getType(); |
112 | } |
113 | |
114 | DeletionKind cir::StoreOp::removeBlockingUses( |
115 | const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses, |
116 | OpBuilder &builder, Value reachingDefinition, |
117 | const DataLayout &dataLayout) { |
118 | return DeletionKind::Delete; |
119 | } |
120 | |
121 | //===----------------------------------------------------------------------===// |
122 | // Interfaces for CastOp |
123 | //===----------------------------------------------------------------------===// |
124 | |
125 | bool cir::CastOp::canUsesBeRemoved( |
126 | const SmallPtrSetImpl<OpOperand *> &blockingUses, |
127 | SmallVectorImpl<OpOperand *> &newBlockingUses, |
128 | const DataLayout &dataLayout) { |
129 | if (getKind() == cir::CastKind::bitcast) |
130 | return forwardToUsers(*this, newBlockingUses); |
131 | return false; |
132 | } |
133 | |
134 | DeletionKind cir::CastOp::removeBlockingUses( |
135 | const SmallPtrSetImpl<OpOperand *> &blockingUses, OpBuilder &builder) { |
136 | return DeletionKind::Delete; |
137 | } |
138 | |