blob: 316c93806d86944887accaa29fb25d5a8f1241c2 [file] [log] [blame]
//===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file This file contains pases and utilities to convert a modern LLVM
/// module into a module compatible with the LLVM 3.7-based DirectX Intermediate
/// Language (DXIL).
//===----------------------------------------------------------------------===//
#include "DirectX.h"
#include "DirectXIRPasses/PointerTypeAnalysis.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Compiler.h"
#define DEBUG_TYPE "dxil-prepare"
using namespace llvm;
using namespace llvm::dxil;
namespace {
constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
return is_contained({Attribute::Alignment,
Attribute::AlwaysInline,
Attribute::Builtin,
Attribute::ByVal,
Attribute::InAlloca,
Attribute::Cold,
Attribute::Convergent,
Attribute::InlineHint,
Attribute::InReg,
Attribute::JumpTable,
Attribute::MinSize,
Attribute::Naked,
Attribute::Nest,
Attribute::NoAlias,
Attribute::NoBuiltin,
Attribute::NoCapture,
Attribute::NoDuplicate,
Attribute::NoImplicitFloat,
Attribute::NoInline,
Attribute::NonLazyBind,
Attribute::NonNull,
Attribute::Dereferenceable,
Attribute::DereferenceableOrNull,
Attribute::Memory,
Attribute::NoRedZone,
Attribute::NoReturn,
Attribute::NoUnwind,
Attribute::OptimizeForSize,
Attribute::OptimizeNone,
Attribute::ReadNone,
Attribute::ReadOnly,
Attribute::Returned,
Attribute::ReturnsTwice,
Attribute::SExt,
Attribute::StackAlignment,
Attribute::StackProtect,
Attribute::StackProtectReq,
Attribute::StackProtectStrong,
Attribute::SafeStack,
Attribute::StructRet,
Attribute::SanitizeAddress,
Attribute::SanitizeThread,
Attribute::SanitizeMemory,
Attribute::UWTable,
Attribute::ZExt},
Attr);
}
class DXILPrepareModule : public ModulePass {
static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
PointerTypeMap &PointerTypes,
Instruction &Inst, Value *Operand,
Type *Ty) {
// Omit bitcasts if the incoming value matches the instruction type.
auto It = PointerTypes.find(Operand);
if (It != PointerTypes.end())
if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
return nullptr;
// Insert bitcasts where we are removing the instruction.
Builder.SetInsertPoint(&Inst);
// This code only gets hit in opaque-pointer mode, so the type of the
// pointer doesn't matter.
PointerType *PtrTy = cast<PointerType>(Operand->getType());
return Builder.Insert(
CastInst::Create(Instruction::BitCast, Operand,
Builder.getInt8PtrTy(PtrTy->getAddressSpace())));
}
public:
bool runOnModule(Module &M) override {
PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);
AttributeMask AttrMask;
for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
I = Attribute::AttrKind(I + 1)) {
if (!isValidForDXIL(I))
AttrMask.addAttribute(I);
}
for (auto &F : M.functions()) {
F.removeFnAttrs(AttrMask);
F.removeRetAttrs(AttrMask);
for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
F.removeParamAttrs(Idx, AttrMask);
for (auto &BB : F) {
IRBuilder<> Builder(&BB);
for (auto &I : make_early_inc_range(BB)) {
if (I.getOpcode() == Instruction::FNeg) {
Builder.SetInsertPoint(&I);
Value *In = I.getOperand(0);
Value *Zero = ConstantFP::get(In->getType(), -0.0);
I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
I.eraseFromParent();
continue;
}
// Only insert bitcasts if the IR is using opaque pointers.
if (M.getContext().supportsTypedPointers())
continue;
// Emtting NoOp bitcast instructions allows the ValueEnumerator to be
// unmodified as it reserves instruction IDs during contruction.
if (auto LI = dyn_cast<LoadInst>(&I)) {
if (Value *NoOpBitcast = maybeGenerateBitcast(
Builder, PointerTypes, I, LI->getPointerOperand(),
LI->getType())) {
LI->replaceAllUsesWith(
Builder.CreateLoad(LI->getType(), NoOpBitcast));
LI->eraseFromParent();
}
continue;
}
if (auto SI = dyn_cast<StoreInst>(&I)) {
if (Value *NoOpBitcast = maybeGenerateBitcast(
Builder, PointerTypes, I, SI->getPointerOperand(),
SI->getValueOperand()->getType())) {
SI->replaceAllUsesWith(
Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
SI->eraseFromParent();
}
continue;
}
if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
if (Value *NoOpBitcast = maybeGenerateBitcast(
Builder, PointerTypes, I, GEP->getPointerOperand(),
GEP->getResultElementType()))
GEP->setOperand(0, NoOpBitcast);
continue;
}
if (auto *CB = dyn_cast<CallBase>(&I)) {
CB->removeFnAttrs(AttrMask);
CB->removeRetAttrs(AttrMask);
for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
CB->removeParamAttrs(Idx, AttrMask);
continue;
}
}
}
}
return true;
}
DXILPrepareModule() : ModulePass(ID) {}
static char ID; // Pass identification.
};
char DXILPrepareModule::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
false, false)
INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
false)
ModulePass *llvm::createDXILPrepareModulePass() {
return new DXILPrepareModule();
}