diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp --- a/llvm/lib/Target/DirectX/DXILPrepare.cpp +++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "DirectX.h" +#include "PointerTypeAnalysis.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/Passes.h" @@ -25,6 +26,7 @@ #define DEBUG_TYPE "dxil-prepare" using namespace llvm; +using namespace llvm::dxil; namespace { @@ -80,6 +82,7 @@ class DXILPrepareModule : public ModulePass { 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)) { @@ -101,6 +104,63 @@ 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().hasSetOpaquePointersValue()) + continue; + + // Emtting NoOp bitcast instructions allows the ValueEnumerator to be + // unmodified as it reserves instruction IDs during contruction. + if (auto Inst = dyn_cast_or_null(&I)) { + // Omit bitcasts if the incoming value matches the instruction type + auto It = PointerTypes.find(Inst->getPointerOperand()); + if (It != PointerTypes.end()) { + if (cast(It->second)->getElementType() == + Inst->getType()) + continue; + } + // Insert bitcasts where we are removing the instruction. + Builder.SetInsertPoint(Inst); + Value *NoOpBitcast = Builder.Insert(CastInst::Create( + Instruction::BitCast, Inst->getPointerOperand(), + Inst->getPointerOperandType())); + Inst->replaceAllUsesWith( + Builder.CreateLoad(Inst->getType(), NoOpBitcast)); + Inst->eraseFromParent(); + continue; + } + if (auto Inst = dyn_cast_or_null(&I)) { + // Omit bitcasts if the incoming value matches the instruction type + auto It = PointerTypes.find(Inst->getPointerOperand()); + if (It != PointerTypes.end()) { + if (cast(It->second)->getElementType() == + Inst->getValueOperand()->getType()) + continue; + } + Builder.SetInsertPoint(Inst); + Value *NoOpBitcast = Builder.Insert(CastInst::Create( + Instruction::BitCast, Inst->getPointerOperand(), + Inst->getPointerOperandType())); + Inst->replaceAllUsesWith( + Builder.CreateStore(Inst->getValueOperand(), NoOpBitcast)); + Inst->eraseFromParent(); + continue; + } + if (auto Inst = dyn_cast_or_null(&I)) { + // Omit bitcasts if the incoming value matches the instruction type + auto It = PointerTypes.find(Inst->getPointerOperand()); + if (It != PointerTypes.end()) { + if (cast(It->second)->getElementType() == + Inst->getResultElementType()) + continue; + } + Builder.SetInsertPoint(Inst); + Value *NoOpBitcast = Builder.Insert(CastInst::Create( + Instruction::BitCast, Inst->getPointerOperand(), + Inst->getPointerOperandType())); + Inst->setOperand(0, NoOpBitcast); + continue; } } } diff --git a/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll b/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/conflicting-bitcast-insert.ll @@ -0,0 +1,14 @@ +; RUN: llc --filetype=asm %s -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +define i64 @test(ptr %p) { + store i32 0, ptr %p + %v = load i64, ptr %p + ret i64 %v +} + +; CHECK: define i64 @test(ptr %p) { +; CHECK-NEXT: %1 = bitcast ptr %p to ptr +; CHECK-NEXT: store i32 0, ptr %1, align 4 +; CHECK-NEXT: %2 = bitcast ptr %p to ptr +; CHECK-NEXT: %3 = load i64, ptr %2, align 8 diff --git a/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll b/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/omit-bitcast-insert.ll @@ -0,0 +1,32 @@ +; RUN: llc --filetype=asm %s -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +define i64 @test(ptr %p) { + %v = load i64, ptr %p + ret i64 %v +} + +; CHECK: define i64 @test(ptr %p) { +; CHECK-NEXT: %v = load i64, ptr %p, align 8 +; CHECK-NEXT: ret i64 %v + +define i64 @test2(ptr %p) { + store i64 0, ptr %p + %v = load i64, ptr %p + ret i64 %v +} + +; CHECK: define i64 @test2(ptr %p) { +; CHECK-NEXT: store i64 0, ptr %p +; CHECK-NEXT: %v = load i64, ptr %p, align 8 +; CHECK-NEXT: ret i64 %v + +define i32 @test3(ptr %0) { + %2 = getelementptr i32, ptr %0, i32 4 + %3 = load i32, ptr %2 + ret i32 %3 +} + +; CHECK: define i32 @test3(ptr %0) { +; CHECK-NEXT: %2 = getelementptr i32, ptr %0, i32 4 +; CHECK-NEXT: %3 = load i32, ptr %2