blob: fb2c6ffd7237c5e1ca23e8bb8f1a7e69264b96c7 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// HLExpandStoreIntrinsics.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DXIL/DxilTypeSystem.h"
#include "dxc/HLSL/HLMatrixType.h"
#include "dxc/HLSL/HLModule.h"
#include "dxc/HLSL/HLOperations.h"
#include "dxc/HlslIntrinsicOp.h"
#include "dxc/Support/Global.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Scalar.h"
using namespace hlsl;
using namespace llvm;
namespace {
// Expands buffer stores of aggregate value types
// into stores of its individual elements,
// before SROA happens and we lose the layout information.
class HLExpandStoreIntrinsics : public FunctionPass {
public:
static char ID;
explicit HLExpandStoreIntrinsics() : FunctionPass(ID) {}
StringRef getPassName() const override {
return "Expand HLSL store intrinsics";
}
bool runOnFunction(Function &Func) override;
private:
DxilTypeSystem *m_typeSys;
bool expand(CallInst *StoreCall);
void emitElementStores(CallInst &OriginalCall,
SmallVectorImpl<Value *> &GEPIndicesStack,
Type *StackTopTy, unsigned OffsetFromBase,
DxilFieldAnnotation *fieldAnnotation);
};
char HLExpandStoreIntrinsics::ID = 0;
bool HLExpandStoreIntrinsics::runOnFunction(Function &Func) {
bool changed = false;
m_typeSys = &(Func.getParent()->GetHLModule().GetTypeSystem());
for (auto InstIt = inst_begin(Func), InstEnd = inst_end(Func);
InstIt != InstEnd;) {
CallInst *Call = dyn_cast<CallInst>(&*(InstIt++));
if (Call == nullptr ||
GetHLOpcodeGroup(Call->getCalledFunction()) !=
HLOpcodeGroup::HLIntrinsic ||
static_cast<IntrinsicOp>(GetHLOpcode(Call)) != IntrinsicOp::MOP_Store) {
continue;
}
changed |= expand(Call);
}
return changed;
}
bool HLExpandStoreIntrinsics::expand(CallInst *StoreCall) {
Value *OldStoreValueArg =
StoreCall->getArgOperand(HLOperandIndex::kStoreValOpIdx);
Type *OldStoreValueArgTy = OldStoreValueArg->getType();
// Only expand if the value argument is by pointer, which means it's an
// aggregate.
if (!OldStoreValueArgTy->isPointerTy())
return false;
IRBuilder<> Builder(StoreCall);
SmallVector<Value *, 4> GEPIndicesStack;
GEPIndicesStack.emplace_back(Builder.getInt32(0));
emitElementStores(*StoreCall, GEPIndicesStack,
OldStoreValueArgTy->getPointerElementType(),
/* OffsetFromBase */ 0, nullptr);
DXASSERT(StoreCall->getType()->isVoidTy() && StoreCall->use_empty(),
"Buffer store intrinsic is expected to return void and hence not "
"have uses.");
StoreCall->eraseFromParent();
return true;
}
void HLExpandStoreIntrinsics::emitElementStores(
CallInst &OriginalCall, SmallVectorImpl<Value *> &GEPIndicesStack,
Type *StackTopTy, unsigned OffsetFromBase,
DxilFieldAnnotation *fieldAnnotation) {
llvm::Module &Module = *OriginalCall.getModule();
IRBuilder<> Builder(&OriginalCall);
StructType *StructTy = dyn_cast<StructType>(StackTopTy);
if (StructTy != nullptr && !HLMatrixType::isa(StructTy)) {
const StructLayout *Layout =
Module.getDataLayout().getStructLayout(StructTy);
DxilStructAnnotation *SA = m_typeSys->GetStructAnnotation(StructTy);
for (unsigned i = 0; i < StructTy->getNumElements(); ++i) {
Type *ElemTy = StructTy->getElementType(i);
unsigned ElemOffsetFromBase =
OffsetFromBase + Layout->getElementOffset(i);
GEPIndicesStack.emplace_back(Builder.getInt32(i));
DxilFieldAnnotation *FA =
SA != nullptr ? &(SA->GetFieldAnnotation(i)) : nullptr;
emitElementStores(OriginalCall, GEPIndicesStack, ElemTy,
ElemOffsetFromBase, FA);
GEPIndicesStack.pop_back();
}
} else if (ArrayType *ArrayTy = dyn_cast<ArrayType>(StackTopTy)) {
unsigned ElemSize = (unsigned)Module.getDataLayout().getTypeAllocSize(
ArrayTy->getElementType());
for (int i = 0; i < (int)ArrayTy->getNumElements(); ++i) {
unsigned ElemOffsetFromBase = OffsetFromBase + ElemSize * i;
GEPIndicesStack.emplace_back(Builder.getInt32(i));
emitElementStores(OriginalCall, GEPIndicesStack,
ArrayTy->getElementType(), ElemOffsetFromBase,
fieldAnnotation);
GEPIndicesStack.pop_back();
}
} else {
// Scalar or vector
Value *OpcodeVal = OriginalCall.getArgOperand(HLOperandIndex::kOpcodeIdx);
Value *BufHandle = OriginalCall.getArgOperand(HLOperandIndex::kHandleOpIdx);
Value *OffsetVal =
OriginalCall.getArgOperand(HLOperandIndex::kStoreOffsetOpIdx);
if (OffsetFromBase > 0)
OffsetVal =
Builder.CreateAdd(OffsetVal, Builder.getInt32(OffsetFromBase));
Value *AggPtr = OriginalCall.getArgOperand(HLOperandIndex::kStoreValOpIdx);
Value *ElemPtr = Builder.CreateGEP(AggPtr, GEPIndicesStack);
Value *ElemVal = nullptr;
if (HLMatrixType::isa(StackTopTy) && fieldAnnotation &&
fieldAnnotation->HasMatrixAnnotation()) {
// For matrix load, we generate HL intrinsic
// matldst.colLoad/matldst.rowLoad instead of LLVM LoadInst to ensure that
// it gets lowered properly later in HLMatrixLowerPass
bool isRowMajor = fieldAnnotation->GetMatrixAnnotation().Orientation ==
hlsl::MatrixOrientation::RowMajor;
unsigned matLdOpcode =
isRowMajor ? static_cast<unsigned>(HLMatLoadStoreOpcode::RowMatLoad)
: static_cast<unsigned>(HLMatLoadStoreOpcode::ColMatLoad);
// Generate matrix load
FunctionType *MatLdFnType = FunctionType::get(
StackTopTy, {Builder.getInt32Ty(), ElemPtr->getType()},
/* isVarArg */ false);
Function *MatLdFn = GetOrCreateHLFunction(
Module, MatLdFnType, HLOpcodeGroup::HLMatLoadStore, matLdOpcode);
Value *MatLdOpCode = ConstantInt::get(Builder.getInt32Ty(), matLdOpcode);
ElemVal = Builder.CreateCall(MatLdFn, {MatLdOpCode, ElemPtr});
} else {
ElemVal = Builder.CreateLoad(ElemPtr); // We go from memory to memory so
// no special bool handling needed
}
FunctionType *NewCalleeType =
FunctionType::get(Builder.getVoidTy(),
{OpcodeVal->getType(), BufHandle->getType(),
OffsetVal->getType(), ElemVal->getType()},
/* isVarArg */ false);
Function *NewCallee =
GetOrCreateHLFunction(Module, NewCalleeType, HLOpcodeGroup::HLIntrinsic,
(unsigned)IntrinsicOp::MOP_Store);
Builder.CreateCall(NewCallee, {OpcodeVal, BufHandle, OffsetVal, ElemVal});
}
}
} // namespace
FunctionPass *llvm::createHLExpandStoreIntrinsicsPass() {
return new HLExpandStoreIntrinsics();
}
INITIALIZE_PASS(HLExpandStoreIntrinsics, "hl-expand-store-intrinsics",
"Expand HLSL store intrinsics", false, false)