diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -9,6 +9,7 @@ add_llvm_target(DirectXCodeGen DirectXSubtarget.cpp DirectXTargetMachine.cpp + DXILPrepare.cpp LINK_COMPONENTS Bitwriter diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp @@ -0,0 +1,102 @@ +//===- 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 "llvm/ADT/EnumMatcher.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; + +namespace { + +LLVM_ATTRIBUTE_ALWAYS_INLINE bool isValidForDXIL(Attribute::AttrKind Attr) { + return isInEnumSet< + Attribute::AttrKind, 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::NoRedZone, + Attribute::NoReturn, Attribute::NoUnwind, Attribute::OptimizeForSize, + Attribute::OptimizeNone, Attribute::ReadNone, Attribute::ReadOnly, + Attribute::ArgMemOnly, 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 { +public: + bool runOnModule(Module &M) override { + 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; Idx < F.arg_size(); ++Idx) + F.removeParamAttrs(Idx, AttrMask); + + for (auto &BB : F) { + IRBuilder<> Builder(&BB); + SmallVector FNegs; + for (auto &I : BB) { + if (I.getOpcode() == Instruction::FNeg) + FNegs.push_back(&I); + } + for (auto I : FNegs) { + Builder.SetInsertPoint(I); + Value *In = I->getOperand(0); + Value *Zero = ConstantFP::get(In->getType(), -0.0); + I->replaceAllUsesWith(Builder.CreateFSub(Zero, In)); + } + for (auto I : FNegs) + I->eraseFromParent(); + } + } + 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(); +} diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DirectX.h @@ -0,0 +1,26 @@ +//===- DirectXTargetMachine.h - DirectX Target Implementation ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_DIRECTX_DIRECTX_H +#define LLVM_LIB_TARGET_DIRECTX_DIRECTX_H + +#include "llvm/PassRegistry.h" +namespace llvm { +class ModulePass; +class PassRegistry; + +/// Initializer for DXIL-prepare +void initializeDXILPrepareModulePass(PassRegistry &); + +/// Pass to convert modules into DXIL-compatable modules +ModulePass *createDXILPrepareModulePass(); +} // namespace llvm + +#endif // LLVM_LIB_TARGET_DIRECTX_DIRECTX_H diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp --- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "DirectXTargetMachine.h" +#include "DirectX.h" #include "DirectXSubtarget.h" #include "DirectXTargetTransformInfo.h" #include "TargetInfo/DirectXTargetInfo.h" @@ -31,6 +32,8 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() { RegisterTargetMachine X(getTheDirectXTarget()); + auto *PR = PassRegistry::getPassRegistry(); + initializeDXILPrepareModulePass(*PR); } class DXILTargetObjectFile : public TargetLoweringObjectFile { @@ -83,6 +86,7 @@ PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, CodeGenFileType FileType, bool DisableVerify, MachineModuleInfoWrapperPass *MMIWP) { + PM.add(createDXILPrepareModulePass()); switch (FileType) { case CGFT_AssemblyFile: PM.add(createPrintModulePass(Out, "", true)); diff --git a/llvm/test/CodeGen/DirectX/fneg-conversion.ll b/llvm/test/CodeGen/DirectX/fneg-conversion.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/fneg-conversion.ll @@ -0,0 +1,14 @@ +; RUN: llc %s --filetype=asm -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +define float @negateF(float %0) { +; CHECK: %2 = fsub float -0.000000e+00, %0 + %2 = fneg float %0 + ret float %2 +} + +define double @negateD(double %0) { +; CHECK: %2 = fsub double -0.000000e+00, %0 + %2 = fneg double %0 + ret double %2 +} diff --git a/llvm/test/CodeGen/DirectX/lit.local.cfg b/llvm/test/CodeGen/DirectX/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'DirectX' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll b/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/strip-fn-attrs.ll @@ -0,0 +1,20 @@ +; RUN: llc %s --filetype=asm -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +; CHECK: Function Attrs: nounwind readnone +; Function Attrs: norecurse nounwind readnone willreturn +define dso_local float @fma(float %0, float %1, float %2) local_unnamed_addr #0 { + %4 = fmul float %0, %1 + %5 = fadd float %4, %2 + ret float %5 +} + +; CHECK: Function Attrs: nounwind readnone +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +; CHECK: attributes #0 = { nounwind readnone } +; CHECK-NOT attributes # + +attributes #0 = { norecurse nounwind readnone willreturn } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }