50 Function *oldFunc, Function *newFunc,
unsigned width,
51 ValueMap<
const Value *, std::vector<Value *>> &vectorizedValues,
52 ValueToValueMapTy &originalToNewFn, SmallPtrSetImpl<Value *> &toVectorize,
54 : hasError(false), vectorizedValues(vectorizedValues),
55 originalToNewFn(originalToNewFn), toVectorize(toVectorize), width(width),
87 auto found = vectorizedValues.find(&inst);
88 assert(found != vectorizedValues.end());
89 auto placeholders = found->second;
90 Instruction *placeholder = cast<Instruction>(placeholders[0]);
92 for (
unsigned i = 1; i < width; ++i) {
93 ValueToValueMapTy vmap;
94 Instruction *new_inst = placeholder->clone();
95 vmap[placeholder] = new_inst;
97 for (
unsigned j = 0; j < inst.getNumOperands(); ++j) {
98 Value *op = inst.getOperand(j);
102 if (isa<GlobalValue>(op) && !isa<ConstantData>(op) &&
103 inst.mayWriteToMemory() && toVectorize.count(op) != 0) {
106 EmitFailure(
"GlobalValueCannotBeVectorized", inst.getDebugLoc(), &inst,
107 "global variables have to be scalar values", inst);
111 if (
auto meta = dyn_cast<MetadataAsValue>(op))
112 if (!isa<ValueAsMetadata>(meta->getMetadata()))
115 Value *new_op = getNewOperand(i, op);
116 vmap[placeholder->getOperand(j)] = new_op;
119 if (placeholders.size() == width) {
121 Instruction *placeholder = cast<Instruction>(placeholders[i]);
122 assert(!placeholder->getType()->isVoidTy());
124 ReplaceInstWithInst(placeholder, new_inst);
125 vectorizedValues[&inst][i] = new_inst;
126 }
else if (placeholders.size() == 1) {
128 assert(placeholder->getType()->isVoidTy());
130 Instruction *insertionPoint =
131 placeholder->getNextNode() ? placeholder->getNextNode() : placeholder;
132 IRBuilder<> Builder2(insertionPoint);
133 Builder2.SetCurrentDebugLocation(DebugLoc());
134 Builder2.Insert(new_inst);
135 vectorizedValues[&inst].push_back(new_inst);
137 llvm_unreachable(
"Unexpected number of values in mapping");
140 RemapInstruction(new_inst, vmap, RF_NoModuleLevelChanges);
142 if (!inst.getType()->isVoidTy() && inst.hasName())
143 new_inst->setName(inst.getName() + Twine(i));
148 PHINode *placeholder = cast<PHINode>(vectorizedValues[&phi][0]);
150 for (
unsigned i = 1; i < width; ++i) {
151 ValueToValueMapTy vmap;
152 Instruction *new_phi = placeholder->clone();
153 vmap[placeholder] = new_phi;
155 for (
unsigned j = 0; j < phi.getNumIncomingValues(); ++j) {
156 Value *orig_block = phi.getIncomingBlock(j);
157 BasicBlock *new_block = cast<BasicBlock>(originalToNewFn[orig_block]);
158 Value *orig_val = phi.getIncomingValue(j);
159 Value *new_val = getNewOperand(i, orig_val);
161 vmap[placeholder->getIncomingValue(j)] = new_val;
162 vmap[new_block] = new_block;
165 RemapInstruction(new_phi, vmap, RF_NoModuleLevelChanges);
166 Instruction *placeholder = cast<Instruction>(vectorizedValues[&phi][i]);
167 ReplaceInstWithInst(placeholder, new_phi);
168 new_phi->setName(phi.getName());
169 vectorizedValues[&phi][i] = new_phi;
200 auto found = originalToNewFn.find(ret.getParent());
201 assert(found != originalToNewFn.end());
202 BasicBlock *nBB = dyn_cast<BasicBlock>(&*found->second);
203 IRBuilder<> Builder2 = IRBuilder<>(nBB);
204 Builder2.SetCurrentDebugLocation(DebugLoc());
205 ReturnInst *placeholder = cast<ReturnInst>(nBB->getTerminator());
206 SmallVector<Value *, 4> rets;
208 for (
unsigned j = 0; j < ret.getNumOperands(); ++j) {
209 Value *op = ret.getOperand(j);
210 for (
unsigned i = 0; i < width; ++i) {
211 Value *new_op = getNewOperand(i, op);
212 rets.push_back(new_op);
216 if (ret.getNumOperands() != 0) {
217#if LLVM_VERSION_MAJOR > 22
218 auto ret = Builder2.CreateAggregateRet(rets);
220 auto ret = Builder2.CreateAggregateRet(rets.data(), width);
222 ret->setDebugLoc(placeholder->getDebugLoc());
223 placeholder->eraseFromParent();
228 auto found = vectorizedValues.find(&call);
229 assert(found != vectorizedValues.end());
230 auto placeholders = found->second;
231 Instruction *placeholder = cast<Instruction>(placeholders[0]);
232 IRBuilder<> Builder2(placeholder);
233 Builder2.SetCurrentDebugLocation(DebugLoc());
236 bool isDefined = !orig_func->isDeclaration();
241 SmallVector<Value *, 4> args;
242 SmallVector<BATCH_TYPE, 4> arg_types;
243#if LLVM_VERSION_MAJOR >= 14
244 for (
unsigned j = 0; j < call.arg_size(); ++j) {
246 for (
unsigned j = 0; j < call.getNumArgOperands(); ++j) {
248 Value *op = call.getArgOperand(j);
250 if (toVectorize.count(op) != 0) {
252 Value *agg = UndefValue::get(aggTy);
253 for (
unsigned i = 0; i < width; i++) {
254 auto found = vectorizedValues.find(op);
255 assert(found != vectorizedValues.end());
256 Value *new_op = found->second[i];
257 Builder2.CreateInsertValue(agg, new_op, {i});
261 }
else if (isa<ConstantData>(op)) {
265 auto found = originalToNewFn.find(op);
266 assert(found != originalToNewFn.end());
267 Value *arg = found->second;
273 BATCH_TYPE ret_type = orig_func->getReturnType()->isVoidTy()
278 orig_func, width, arg_types, ret_type);
279 CallInst *new_call = Builder2.CreateCall(new_func->getFunctionType(),
280 new_func, args, call.getName());
282 new_call->setDebugLoc(placeholder->getDebugLoc());
284 if (!call.getType()->isVoidTy()) {
285 for (
unsigned i = 0; i < width; ++i) {
286 Instruction *placeholder = dyn_cast<Instruction>(placeholders[i]);
287 ExtractValueInst *ret = ExtractValueInst::Create(
289 "unwrap" + (call.hasName() ?
"." + call.getName() + Twine(i) :
""));
290 ReplaceInstWithInst(placeholder, ret);
291 vectorizedValues[&call][i] = ret;
294 placeholder->replaceAllUsesWith(new_call);
295 placeholder->eraseFromParent();
llvm::Function * CreateBatch(RequestContext context, llvm::Function *tobatch, unsigned width, llvm::ArrayRef< BATCH_TYPE > arg_types, BATCH_TYPE ret_type)
Create a function batched in its inputs.
InstructionBatcher(llvm::Function *oldFunc, llvm::Function *newFunc, unsigned width, llvm::ValueMap< const llvm::Value *, std::vector< llvm::Value * > > &vectorizedValues, llvm::ValueMap< const llvm::Value *, llvm::WeakTrackingVH > &originalToNewFn, llvm::SmallPtrSetImpl< llvm::Value * > &toVectorize, EnzymeLogic &Logic)