Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/lib/Target/DirectX/DXILShaderFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
if (!CSF.Int64Ops)
CSF.Int64Ops = I.getType()->isIntegerTy(64);

if (!CSF.Int64Ops) {
if (!CSF.Int64Ops && !isa<LifetimeIntrinsic>(&I)) {
for (const Value *Op : I.operands()) {
if (Op->getType()->isIntegerTy(64)) {
CSF.Int64Ops = true;
Expand Down
55 changes: 55 additions & 0 deletions llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
Expand Down Expand Up @@ -52,6 +53,51 @@ class WriteDXILPass : public llvm::ModulePass {
}
};

static void legalizeLifetimeIntrinsics(Module &M) {
for (Function &F : M) {
Intrinsic::ID IID = F.getIntrinsicID();
if (IID != Intrinsic::lifetime_start && IID != Intrinsic::lifetime_end)
continue;

// Lifetime intrinsics in LLVM 3.7 do not have the memory FnAttr
F.removeFnAttr(Attribute::Memory);

// Lifetime intrinsics in LLVM 3.7 do not have mangled names
F.setName(Intrinsic::getBaseName(IID));

// LLVM 3.7 Lifetime intrinics require an i8* operand, so we insert bitcasts
// to ensure that is the case
for (auto *User : make_early_inc_range(F.users())) {
CallInst *CI = dyn_cast<CallInst>(User);
assert(CI && "Expected user of a lifetime intrinsic function to be a "
"lifetime intrinsic call");
Value *PtrOperand = CI->getArgOperand(1);
PointerType *PtrTy = cast<PointerType>(PtrOperand->getType());
Value *NoOpBitCast = CastInst::Create(Instruction::BitCast, PtrOperand,
PtrTy, "", CI->getIterator());
CI->setArgOperand(1, NoOpBitCast);
}
}
}

static void removeLifetimeIntrinsics(Module &M) {
for (Function &F : make_early_inc_range(M))
if (Intrinsic::ID IID = F.getIntrinsicID();
IID == Intrinsic::lifetime_start || IID == Intrinsic::lifetime_end) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd usually recommend inverting the condition and having a continue here instead of nesting further. That matches what you did above and aligns with the coding standards.

https://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code

for (User *U : make_early_inc_range(F.users())) {
LifetimeIntrinsic *LI = dyn_cast<LifetimeIntrinsic>(U);
assert(LI && "Expected user of lifetime intrinsic function to be "
"a LifetimeIntrinsic instruction");
BitCastInst *BCI = dyn_cast<BitCastInst>(LI->getArgOperand(1));
assert(BCI && "Expected pointer operand of LifetimeIntrinsic to be a "
"BitCastInst");
LI->eraseFromParent();
BCI->eraseFromParent();
}
F.eraseFromParent();
}
}

class EmbedDXILPass : public llvm::ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
Expand All @@ -70,8 +116,17 @@ class EmbedDXILPass : public llvm::ModulePass {
// Only the output bitcode need to be DXIL triple.
M.setTargetTriple(Triple("dxil-ms-dx"));

// Perform late legalization of lifetime intrinsics that would otherwise
// fail the Module Verifier if performed in an earlier pass
legalizeLifetimeIntrinsics(M);

WriteDXILToFile(M, OS);

// We no longer need lifetime intrinsics after bitcode serialization, so we
// simply remove them to keep the Module Verifier happy after our
// not-so-legal legalizations
removeLifetimeIntrinsics(M);

// Recover triple.
M.setTargetTriple(OriginalTriple);

Expand Down
36 changes: 36 additions & 0 deletions llvm/test/CodeGen/DirectX/ShaderFlags/lifetimes-noint64op.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC

target triple = "dxil-pc-shadermodel6.7-library"

; CHECK: ; Combined Shader Flags for Module
; CHECK-NEXT: ; Shader Flags Value: 0x00000000
; CHECK-NEXT: ;
; CHECK-NOT: ; Note: shader requires additional functionality:
; CHECK-NOT: ; 64-Bit integer
; CHECK-NOT: ; Note: extra DXIL module flags:
; CHECK-NOT: ;
; CHECK-NEXT: ; Shader Flags for Module Functions
; CHECK-NEXT: ; Function lifetimes : 0x00000000

define void @lifetimes() #0 {
%a = alloca [4 x i32], align 8
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %a)
call void @llvm.lifetime.end.p0(i64 16, ptr nonnull %a)
ret void
}

; Function Attrs: nounwind memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64, ptr) #1

; Function Attrs: nounwind memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64, ptr) #1

attributes #0 = { convergent norecurse nounwind "hlsl.export"}
attributes #1 = { nounwind memory(argmem: readwrite) }

; DXC: - Name: SFI0
; DXC-NEXT: Size: 8
; DXC-NOT: Flags:
; DXC-NOT: Int64Ops: true
; DXC: ...
38 changes: 38 additions & 0 deletions llvm/test/tools/dxil-dis/lifetimes.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s
target triple = "dxil-unknown-shadermodel6.7-library"

define void @test_lifetimes() {
; CHECK-LABEL: test_lifetimes
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [2 x i32], align 4
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [2 x i32], [2 x i32]* [[ALLOCA]], i32 0, i32 0
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast [2 x i32]* [[ALLOCA]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* nonnull [[BITCAST]])
; CHECK-NEXT: store i32 0, i32* [[GEP]], align 4
; CHECK-NEXT: [[BITCAST:%.*]] = bitcast [2 x i32]* [[ALLOCA]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* nonnull [[BITCAST]])
; CHECK-NEXT: ret void
;
%a = alloca [2 x i32], align 4
%gep = getelementptr [2 x i32], ptr %a, i32 0, i32 0
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a)
store i32 0, ptr %gep, align 4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a)
ret void
}

; CHECK-DAG: attributes [[LIFETIME_ATTRS:#.*]] = { nounwind }

; CHECK-DAG: ; Function Attrs: nounwind
; CHECK-DAG: declare void @llvm.lifetime.start(i64, i8* nocapture) [[LIFETIME_ATTRS]]

; CHECK-DAG: ; Function Attrs: nounwind
; CHECK-DAG: declare void @llvm.lifetime.end(i64, i8* nocapture) [[LIFETIME_ATTRS]]

; Function Attrs: nounwind memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64, ptr) #0

; Function Attrs: nounwind memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64, ptr) #0

attributes #0 = { nounwind memory(argmem: readwrite) }

Loading