Prechádzať zdrojové kódy

[linux-port] Complete the Windows adapter code. (#1358)

This change completes the necessary adapter code needed to enable
cross-platform compilation.

Discussion on the design/implementation of these are in issue #1341 and
isuee #1342.

In addition to the adapter classes/structs, there exists usages of
Windows-specific functions in the codebase. In some cases, we won't need
to compile/run some of those methods on non-Windows platforms. For the
few cases where we do, we have implemented equivalent functionality in
WindowsFunctions.cpp.
Ehsan 7 rokov pred
rodič
commit
285490211f

+ 442 - 1
include/dxc/Support/WinAdapter.h

@@ -141,6 +141,21 @@
 
 #define MB_ERR_INVALID_CHARS 0x00000008 // error for invalid chars
 
+// File IO
+
+#define CREATE_ALWAYS 2
+#define CREATE_NEW 1
+#define OPEN_ALWAYS 4
+#define OPEN_EXISTING 3
+#define TRUNCATE_EXISTING 5
+
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+
+#define GENERIC_READ 0x80000000
+#define GENERIC_WRITE 0x40000000
+
 #define _atoi64 atoll
 #define sprintf_s snprintf
 #define _strdup strdup
@@ -370,6 +385,22 @@ typedef void *HMODULE;
 #define STD_OUTPUT_HANDLE ((DWORD)-11)
 #define STD_ERROR_HANDLE ((DWORD)-12)
 
+//===--------------------- ID Types and Macros for COM --------------------===//
+
+struct GUID {
+  uint32_t Data1;
+  uint16_t Data2;
+  uint16_t Data3;
+  uint8_t Data4[8];
+};
+typedef GUID CLSID;
+typedef const GUID &REFGUID;
+typedef const void *REFIID;
+typedef const GUID &REFCLSID;
+
+#define IsEqualIID(a, b) a == b
+#define IsEqualCLSID(a, b) !memcmp(&a, &b, sizeof(GUID))
+
 //===--------------------- Struct Types -----------------------------------===//
 
 typedef struct _FILETIME {
@@ -444,7 +475,417 @@ enum tagSTATFLAG {
   STATFLAG_NOOPEN = 2
 };
 
-// TODO: More definitions will be added here.
+//===--------------------- UUID Related Macros ----------------------------===//
+
+// The following macros are defined to facilitate the lack of 'uuid' on Linux.
+#define DECLARE_CROSS_PLATFORM_UUIDOF(T)                                       \
+public:                                                                        \
+  static REFIID uuidof() { return static_cast<REFIID>(&T##_ID); }              \
+                                                                               \
+private:                                                                       \
+  static const char T##_ID;
+
+#define DEFINE_CROSS_PLATFORM_UUIDOF(T) const char T::T##_ID = '\0';
+#define __uuidof(T) T::uuidof()
+#define IID_PPV_ARGS(ppType)                                                   \
+  (**(ppType)).uuidof(), reinterpret_cast<void **>(ppType)
+
+//===--------------------- COM Interfaces ---------------------------------===//
+
+struct IUnknown {
+  virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
+  virtual ULONG AddRef();
+  virtual ULONG Release();
+  virtual ~IUnknown();
+  template <class Q> HRESULT QueryInterface(Q **pp) {
+    return QueryInterface(__uuidof(Q), (void **)pp);
+  }
+
+private:
+  std::atomic<unsigned long> m_count;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IUnknown)
+};
+
+struct INoMarshal : public IUnknown {
+  DECLARE_CROSS_PLATFORM_UUIDOF(INoMarshal)
+};
+
+struct IMalloc : public IUnknown {
+  virtual void *Alloc(size_t size);
+  virtual void *Realloc(void *ptr, size_t size);
+  virtual void Free(void *ptr);
+  virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
+};
+
+struct ISequentialStream : public IUnknown {
+  virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
+  virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
+};
+
+struct IStream : public ISequentialStream {
+  virtual HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
+                       ULARGE_INTEGER *plibNewPosition) = 0;
+  virtual HRESULT SetSize(ULARGE_INTEGER libNewSize) = 0;
+  virtual HRESULT CopyTo(IStream *pstm, ULARGE_INTEGER cb,
+                         ULARGE_INTEGER *pcbRead,
+                         ULARGE_INTEGER *pcbWritten) = 0;
+
+  virtual HRESULT Commit(DWORD grfCommitFlags) = 0;
+
+  virtual HRESULT Revert(void) = 0;
+
+  virtual HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+                             DWORD dwLockType) = 0;
+
+  virtual HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+                               DWORD dwLockType) = 0;
+
+  virtual HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag) = 0;
+
+  virtual HRESULT Clone(IStream **ppstm) = 0;
+
+  DECLARE_CROSS_PLATFORM_UUIDOF(IStream)
+};
+
+//===--------------------- COM Pointer Types ------------------------------===//
+
+class CAllocator {
+public:
+  static void *Reallocate(void *p, size_t nBytes) throw();
+  static void *Allocate(size_t nBytes) throw();
+  static void Free(void *p) throw();
+};
+
+template <class T> class CComPtrBase {
+protected:
+  CComPtrBase() throw() { p = nullptr; }
+  CComPtrBase(T *lp) throw() {
+    p = lp;
+    if (p != nullptr)
+      p->AddRef();
+  }
+  void Swap(CComPtrBase &other) {
+    T *pTemp = p;
+    p = other.p;
+    other.p = pTemp;
+  }
+
+public:
+  virtual ~CComPtrBase() throw() {
+    if (p) {
+      p->Release();
+      p = nullptr;
+    }
+  }
+  operator T *() const throw() { return p; }
+  T &operator*() const { return *p; }
+  T *operator->() const { return p; }
+  T **operator&() throw() {
+    assert(p == nullptr);
+    return &p;
+  }
+  bool operator!() const throw() { return (p == nullptr); }
+  bool operator<(T *pT) const throw() { return p < pT; }
+  bool operator!=(T *pT) const { return !operator==(pT); }
+  bool operator==(T *pT) const throw() { return p == pT; }
+
+  // Release the interface and set to nullptr
+  void Release() throw() {
+    T *pTemp = p;
+    if (pTemp) {
+      p = nullptr;
+      pTemp->Release();
+    }
+  }
+
+  // Attach to an existing interface (does not AddRef)
+  void Attach(T *p2) throw() {
+    if (p) {
+      ULONG ref = p->Release();
+      (void)(ref);
+      // Attaching to the same object only works if duplicate references are
+      // being coalesced.  Otherwise re-attaching will cause the pointer to be
+      // released and may cause a crash on a subsequent dereference.
+      assert(ref != 0 || p2 != p);
+    }
+    p = p2;
+  }
+
+  // Detach the interface (does not Release)
+  T *Detach() throw() {
+    T *pt = p;
+    p = nullptr;
+    return pt;
+  }
+
+  HRESULT CopyTo(T **ppT) throw() {
+    assert(ppT != nullptr);
+    if (ppT == nullptr)
+      return E_POINTER;
+    *ppT = p;
+    if (p)
+      p->AddRef();
+    return S_OK;
+  }
+
+  template <class Q> HRESULT QueryInterface(Q **pp) const throw() {
+    assert(pp != nullptr);
+    return p->QueryInterface(__uuidof(Q), (void **)pp);
+  }
+
+  T *p;
+};
+
+template <class T> class CComPtr : public CComPtrBase<T> {
+public:
+  CComPtr() throw() {}
+  CComPtr(T *lp) throw() : CComPtrBase<T>(lp) {}
+  CComPtr(const CComPtr<T> &lp) throw() : CComPtrBase<T>(lp.p) {}
+  T *operator=(T *lp) throw() {
+    if (*this != lp) {
+      CComPtr(lp).Swap(*this);
+    }
+    return *this;
+  }
+
+  inline bool IsEqualObject(IUnknown *pOther) throw() {
+    if (this->p == nullptr && pOther == nullptr)
+      return true; // They are both NULL objects
+
+    if (this->p == nullptr || pOther == nullptr)
+      return false; // One is NULL the other is not
+
+    CComPtr<IUnknown> punk1;
+    CComPtr<IUnknown> punk2;
+    this->p->QueryInterface(__uuidof(IUnknown), (void **)&punk1);
+    pOther->QueryInterface(__uuidof(IUnknown), (void **)&punk2);
+    return punk1 == punk2;
+  }
+
+  void ComPtrAssign(IUnknown **pp, IUnknown *lp, REFIID riid) {
+    IUnknown *pTemp = *pp; // takes ownership
+    if (lp == nullptr || FAILED(lp->QueryInterface(riid, (void **)pp)))
+      *pp = nullptr;
+    if (pTemp)
+      pTemp->Release();
+  }
+
+  template <typename Q> T *operator=(const CComPtr<Q> &lp) throw() {
+    if (!this->IsEqualObject(lp)) {
+      ComPtrAssign((IUnknown **)&this->p, lp, __uuidof(T));
+    }
+    return *this;
+  }
+
+  T *operator=(const CComPtr<T> &lp) throw() {
+    if (*this != lp) {
+      CComPtr(lp).Swap(*this);
+    }
+    return *this;
+  }
+
+  CComPtr(CComPtr<T> &&lp) throw() : CComPtrBase<T>() { lp.Swap(*this); }
+
+  T *operator=(CComPtr<T> &&lp) throw() {
+    if (*this != lp) {
+      CComPtr(static_cast<CComPtr &&>(lp)).Swap(*this);
+    }
+    return *this;
+  }
+};
+
+template <class T> class CSimpleArray : public std::vector<T> {
+public:
+  bool Add(const T &t) {
+    this->push_back(t);
+    return true;
+  }
+  int GetSize() { return this->size(); }
+  T *GetData() { return this->data(); }
+};
+
+template <class T, class Allocator = CAllocator> class CHeapPtrBase {
+protected:
+  CHeapPtrBase() throw() : m_pData(NULL) {}
+  CHeapPtrBase(CHeapPtrBase<T, Allocator> &p) throw() {
+    m_pData = p.Detach(); // Transfer ownership
+  }
+  explicit CHeapPtrBase(T *pData) throw() : m_pData(pData) {}
+
+public:
+  ~CHeapPtrBase() throw() { Free(); }
+
+protected:
+  CHeapPtrBase<T, Allocator> &operator=(CHeapPtrBase<T, Allocator> &p) throw() {
+    if (m_pData != p.m_pData)
+      Attach(p.Detach()); // Transfer ownership
+    return *this;
+  }
+
+public:
+  operator T *() const throw() { return m_pData; }
+  T *operator->() const throw() {
+    assert(m_pData != NULL);
+    return m_pData;
+  }
+
+  T **operator&() throw() {
+    assert(m_pData == NULL);
+    return &m_pData;
+  }
+
+  // Allocate a buffer with the given number of bytes
+  bool AllocateBytes(size_t nBytes) throw() {
+    assert(m_pData == NULL);
+    m_pData = static_cast<T *>(Allocator::Allocate(nBytes * sizeof(char)));
+    if (m_pData == NULL)
+      return false;
+
+    return true;
+  }
+
+  // Attach to an existing pointer (takes ownership)
+  void Attach(T *pData) throw() {
+    Allocator::Free(m_pData);
+    m_pData = pData;
+  }
+
+  // Detach the pointer (releases ownership)
+  T *Detach() throw() {
+    T *pTemp = m_pData;
+    m_pData = NULL;
+    return pTemp;
+  }
+
+  // Free the memory pointed to, and set the pointer to NULL
+  void Free() throw() {
+    Allocator::Free(m_pData);
+    m_pData = NULL;
+  }
+
+  // Reallocate the buffer to hold a given number of bytes
+  bool ReallocateBytes(size_t nBytes) throw() {
+    T *pNew;
+    pNew =
+        static_cast<T *>(Allocator::Reallocate(m_pData, nBytes * sizeof(char)));
+    if (pNew == NULL)
+      return false;
+    m_pData = pNew;
+
+    return true;
+  }
+
+public:
+  T *m_pData;
+};
+
+template <typename T, class Allocator = CAllocator>
+class CHeapPtr : public CHeapPtrBase<T, Allocator> {
+public:
+  CHeapPtr() throw() {}
+  CHeapPtr(CHeapPtr<T, Allocator> &p) throw() : CHeapPtrBase<T, Allocator>(p) {}
+  explicit CHeapPtr(T *p) throw() : CHeapPtrBase<T, Allocator>(p) {}
+  CHeapPtr<T> &operator=(CHeapPtr<T, Allocator> &p) throw() {
+    CHeapPtrBase<T, Allocator>::operator=(p);
+    return *this;
+  }
+
+  // Allocate a buffer with the given number of elements
+  bool Allocate(size_t nElements = 1) throw() {
+    size_t nBytes = nElements * sizeof(T);
+    return this->AllocateBytes(nBytes);
+  }
+
+  // Reallocate the buffer to hold a given number of elements
+  bool Reallocate(size_t nElements) throw() {
+    size_t nBytes = nElements * sizeof(T);
+    return this->ReallocateBytes(nBytes);
+  }
+};
+
+#define CComHeapPtr CHeapPtr
+
+//===--------------------- UTF-8 Related Types ----------------------------===//
+
+// Code Page
+#define CP_ACP 0
+#define CP_UTF8 65001 // UTF-8 translation.
+
+// The t_nBufferLength parameter is part of the published interface, but not
+// used here.
+template <int t_nBufferLength = 128> class CW2AEX {
+public:
+  CW2AEX(LPCWSTR psz, UINT nCodePage = CP_UTF8) {
+    if (nCodePage != CP_UTF8) {
+      // Current Implementation only supports CP_UTF8
+      assert(false && "CW2AEX implementation for Linux does not handle "
+                      "non-UTF8 code pages");
+      return;
+    }
+
+    if (!psz) {
+      m_psz = NULL;
+      return;
+    }
+
+    int len = wcslen(psz) * 4;
+    m_psz = new char[len];
+    std::wcstombs(m_psz, psz, len);
+  }
+
+  ~CW2AEX() { delete[] m_psz; }
+
+  operator LPSTR() const { return m_psz; }
+
+  char *m_psz;
+};
+typedef CW2AEX<> CW2A;
+
+// The t_nBufferLength parameter is part of the published interface, but not
+// used here.
+template <int t_nBufferLength = 128> class CA2WEX {
+public:
+  CA2WEX(LPCSTR psz, UINT nCodePage = CP_UTF8) {
+    if (nCodePage != CP_UTF8) {
+      // Current Implementation only supports CP_UTF8
+      assert(false && "CA2WEX implementation for Linux does not handle "
+                      "non-UTF8 code pages");
+      return;
+    }
+
+    if (!psz) {
+      m_psz = NULL;
+      return;
+    }
+
+    int len = strlen(psz) + 1;
+    m_psz = new wchar_t[len];
+    std::mbstowcs(m_psz, psz, len);
+  }
+
+  ~CA2WEX() { delete[] m_psz; }
+
+  operator LPWSTR() const { return m_psz; }
+
+  wchar_t *m_psz;
+};
+
+typedef CA2WEX<> CA2W;
+
+//===--------- File IO Related Types ----------------===//
+
+class CHandle {
+public:
+  CHandle(HANDLE h);
+  ~CHandle();
+  operator HANDLE() const throw();
+
+private:
+  HANDLE m_h;
+};
 
 #endif // __cplusplus
 

+ 54 - 0
include/dxc/Support/WinFunctions.h

@@ -0,0 +1,54 @@
+//===-- WinFunctions.h - Windows Functions for other platforms --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Windows-specific functions used in the codebase for
+// non-Windows platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WINFUNCTIONS_H
+#define LLVM_SUPPORT_WINFUNCTIONS_H
+
+#ifndef _WIN32
+
+#include "dxc/Support/WinAdapter.h"
+
+HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...);
+HRESULT UIntAdd(UINT uAugend, UINT uAddend, UINT *puResult);
+HRESULT IntToUInt(int in, UINT *out);
+HRESULT UInt32Mult(UINT a, UINT b, UINT *out);
+int _stricmp(const char *str1, const char *str2);
+HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc);
+
+HANDLE CreateFile2(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition,
+                   _In_opt_ void *pCreateExParams);
+
+HANDLE CreateFileW(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_opt_ void *lpSecurityAttributes,
+                   _In_ DWORD dwCreationDisposition,
+                   _In_ DWORD dwFlagsAndAttributes,
+                   _In_opt_ HANDLE hTemplateFile);
+
+BOOL GetFileSizeEx(_In_ HANDLE hFile, _Out_ PLARGE_INTEGER lpFileSize);
+
+BOOL ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer,
+              _In_ DWORD nNumberOfBytesToRead,
+              _Out_opt_ LPDWORD lpNumberOfBytesRead,
+              _Inout_opt_ void *lpOverlapped);
+BOOL WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer,
+               _In_ DWORD nNumberOfBytesToWrite,
+               _Out_opt_ LPDWORD lpNumberOfBytesWritten,
+               _Inout_opt_ void *lpOverlapped);
+
+BOOL CloseHandle(_In_ HANDLE hObject);
+
+#endif // _WIN32
+
+#endif // LLVM_SUPPORT_WINFUNCTIONS_H

+ 56 - 0
include/dxc/Support/WinIncludes.h

@@ -10,6 +10,8 @@
 
 #pragma once
 
+#ifdef _MSC_VER
+
 #define NOATOM 1
 #define NOGDICAPMASKS 1
 #define NOMETAFILE 1
@@ -46,3 +48,57 @@ template <class T> void swap(CComHeapPtr<T> &a, CComHeapPtr<T> &b) {
   a.m_pData = b.m_pData;
   b.m_pData = c;
 }
+
+#else // _MSC_VER
+
+#include "dxc/Support/WinAdapter.h"
+
+#ifdef __cplusplus
+// Define operator overloads to enable bit operations on enum values that are
+// used to define flags. Use DEFINE_ENUM_FLAG_OPERATORS(YOUR_TYPE) to enable these
+// operators on YOUR_TYPE.
+extern "C++" {
+    template <size_t S>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE;
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<1>
+    {
+        typedef int8_t type;
+    };
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<2>
+    {
+        typedef int16_t type;
+    };
+
+    template <>
+    struct _ENUM_FLAG_INTEGER_FOR_SIZE<4>
+    {
+        typedef int32_t type;
+    };
+
+    // used as an approximation of std::underlying_type<T>
+    template <class T>
+    struct _ENUM_FLAG_SIZED_INTEGER
+    {
+        typedef typename _ENUM_FLAG_INTEGER_FOR_SIZE<sizeof(T)>::type type;
+    };
+
+}
+#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
+extern "C++" { \
+inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) | ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) |= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) & ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) &= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE operator ~ (ENUMTYPE a) { return ENUMTYPE(~((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a)); } \
+inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) ^ ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) ^= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
+}
+#else
+#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) // NOP, C allows these operators.
+#endif
+
+#endif // _MSC_VER

+ 2 - 0
lib/DxcSupport/CMakeLists.txt

@@ -7,6 +7,8 @@ add_llvm_library(LLVMDxcSupport
   Global.cpp
   HLSLOptions.cpp
   Unicode.cpp
+  WinAdapter.cpp
+  WinFunctions.cpp
   )
 
 add_dependencies(LLVMDxcSupport TablegenHLSLOptions)

+ 59 - 0
lib/DxcSupport/WinAdapter.cpp

@@ -0,0 +1,59 @@
+//===-- WinAdapter.cpp - Windows Adapter for other platforms ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _WIN32
+
+#include "dxc/Support/WinAdapter.h"
+#include "dxc/Support/WinFunctions.h"
+
+DEFINE_CROSS_PLATFORM_UUIDOF(IUnknown)
+DEFINE_CROSS_PLATFORM_UUIDOF(INoMarshal)
+DEFINE_CROSS_PLATFORM_UUIDOF(IStream)
+DEFINE_CROSS_PLATFORM_UUIDOF(ISequentialStream)
+
+//===--------------------------- IUnknown ---------------------------------===//
+
+ULONG IUnknown::AddRef() {
+  ++m_count;
+  return m_count;
+}
+ULONG IUnknown::Release() {
+  ULONG result = --m_count;
+  if (m_count == 0) {
+    delete this;
+  }
+  return result;
+}
+IUnknown::~IUnknown() {}
+
+//===--------------------------- IMalloc ----------------------------------===//
+
+void *IMalloc::Alloc(size_t size) { return malloc(size); }
+void *IMalloc::Realloc(void *ptr, size_t size) { return realloc(ptr, size); }
+void IMalloc::Free(void *ptr) { free(ptr); }
+HRESULT IMalloc::QueryInterface(REFIID riid, void **ppvObject) {
+  assert(false && "QueryInterface not implemented for IMalloc.");
+  return E_NOINTERFACE;
+}
+
+//===--------------------------- CAllocator -------------------------------===//
+
+void *CAllocator::Reallocate(void *p, size_t nBytes) throw() {
+  return realloc(p, nBytes);
+}
+void *CAllocator::Allocate(size_t nBytes) throw() { return malloc(nBytes); }
+void CAllocator::Free(void *p) throw() { free(p); }
+
+//===--------------------------- CHandle -------------------------------===//
+
+CHandle::CHandle(HANDLE h) { m_h = h; }
+CHandle::~CHandle() { CloseHandle(m_h); }
+CHandle::operator HANDLE() const throw() { return m_h; }
+
+#endif

+ 178 - 0
lib/DxcSupport/WinFunctions.cpp

@@ -0,0 +1,178 @@
+//===-- WinFunctions.cpp - Windows Functions for other platforms --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines Windows-specific functions used in the codebase for
+// non-Windows platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "dxc/Support/WinFunctions.h"
+
+HRESULT StringCchPrintfA(char *dst, size_t dstSize, const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  // C++11 snprintf can return the size of the resulting string if it was to be
+  // constructed.
+  size_t size = snprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'
+  if (size > dstSize) {
+    *dst = '\0';
+  } else {
+    snprintf(dst, size, format, args);
+  }
+  va_end(args);
+  return S_OK;
+}
+HRESULT UIntAdd(UINT uAugend, UINT uAddend, UINT *puResult) {
+  HRESULT hr;
+  if ((uAugend + uAddend) >= uAugend) {
+    *puResult = (uAugend + uAddend);
+    hr = S_OK;
+  } else {
+    *puResult = 0xffffffff;
+    hr = (HRESULT)1L;
+  }
+  return hr;
+}
+HRESULT IntToUInt(int in, UINT *out) {
+  HRESULT hr;
+  if (in >= 0) {
+    *out = (UINT)in;
+    hr = S_OK;
+  } else {
+    *out = 0xffffffff;
+    hr = (HRESULT)1L;
+  }
+  return hr;
+}
+HRESULT UInt32Mult(UINT a, UINT b, UINT *out) {
+  uint64_t result = (uint64_t)a * (uint64_t)b;
+  if (result > uint64_t(UINT_MAX))
+    return (HRESULT)1L;
+
+  *out = (uint32_t)result;
+  return S_OK;
+}
+
+int _stricmp(const char *str1, const char *str2) {
+  size_t i = 0;
+  for (; str1[i] && str2[i]; ++i) {
+    int d = std::tolower(str1[i]) - std::tolower(str2[i]);
+    if (d != 0)
+      return d;
+  }
+  return str1[i] - str2[i];
+}
+
+HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc) {
+  *ppMalloc = new IMalloc;
+  (*ppMalloc)->AddRef();
+  return S_OK;
+}
+
+HANDLE CreateFile2(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition,
+                   _In_opt_ void *pCreateExParams) {
+  return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, pCreateExParams,
+                     dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
+}
+
+HANDLE CreateFileW(_In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess,
+                   _In_ DWORD dwShareMode, _In_opt_ void *lpSecurityAttributes,
+                   _In_ DWORD dwCreationDisposition,
+                   _In_ DWORD dwFlagsAndAttributes,
+                   _In_opt_ HANDLE hTemplateFile) {
+  CW2A pUtf8FileName(lpFileName);
+  size_t fd = -1;
+  int flags = 0;
+
+  if (dwDesiredAccess & GENERIC_WRITE)
+    if (dwDesiredAccess & GENERIC_READ)
+      flags |= O_RDWR;
+    else
+      flags |= O_WRONLY;
+  else // dwDesiredAccess may be 0, but open() demands something here. This is mostly harmless
+    flags |= O_RDONLY;
+
+  if (dwCreationDisposition == CREATE_ALWAYS)
+    flags |= (O_CREAT | O_TRUNC);
+  if (dwCreationDisposition == OPEN_ALWAYS)
+    flags |= O_CREAT;
+  else if (dwCreationDisposition == CREATE_NEW)
+    flags |= (O_CREAT | O_EXCL);
+  else if (dwCreationDisposition == TRUNCATE_EXISTING)
+    flags |= O_TRUNC;
+  // OPEN_EXISTING represents default open() behavior
+
+  // Catch Implementation limitations.
+  assert(!lpSecurityAttributes && "security attributes not supported in CreateFileW yet");
+  assert(!hTemplateFile && "template file not supported in CreateFileW yet");
+  assert(dwFlagsAndAttributes == FILE_ATTRIBUTE_NORMAL &&
+         "Attributes other than NORMAL not supported in CreateFileW yet");
+
+  fd = open(pUtf8FileName, flags);
+
+  return (HANDLE)fd;
+}
+
+BOOL GetFileSizeEx(_In_ HANDLE hFile, _Out_ PLARGE_INTEGER lpFileSize) {
+  int fd = (size_t)hFile;
+  struct stat fdstat;
+  int rv = fstat(fd, &fdstat);
+  if (!rv) {
+    lpFileSize->QuadPart = (LONGLONG)fdstat.st_size;
+    return true;
+  }
+  return false;
+}
+
+BOOL ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer,
+              _In_ DWORD nNumberOfBytesToRead,
+              _Out_opt_ LPDWORD lpNumberOfBytesRead,
+              _Inout_opt_ void *lpOverlapped) {
+  size_t fd = (size_t)hFile;
+  ssize_t rv = -1;
+
+  // Implementation limitation
+  assert(!lpOverlapped && "Overlapping not supported in ReadFile yet.");
+
+  rv = read(fd, lpBuffer, nNumberOfBytesToRead);
+  if (rv < 0)
+    return false;
+  *lpNumberOfBytesRead = rv;
+  return true;
+}
+
+BOOL WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer,
+               _In_ DWORD nNumberOfBytesToWrite,
+               _Out_opt_ LPDWORD lpNumberOfBytesWritten,
+               _Inout_opt_ void *lpOverlapped) {
+  size_t fd = (size_t)hFile;
+  ssize_t rv = -1;
+
+  // Implementation limitation
+  assert(!lpOverlapped && "Overlapping not supported in WriteFile yet.");
+
+  rv = write(fd, lpBuffer, nNumberOfBytesToWrite);
+  if (rv < 0)
+    return false;
+  *lpNumberOfBytesWritten = rv;
+  return true;
+}
+
+BOOL CloseHandle(_In_ HANDLE hObject) {
+  int fd = (size_t)hObject;
+  return !close(fd);
+}
+
+#endif // _WIN32