From a83a393964736f5e73e0aff1eef446e52d4fc033 Mon Sep 17 00:00:00 2001
From: Niyas Sait <niyas.sait@linaro.org>
Date: Tue, 22 Feb 2022 13:07:24 +0000
Subject: [PATCH] Enable postgres native build for windows-arm64 platform

Following changes are included

- Extend MSVC scripts to handle ARM64 platform
- Add arm64 definition of spin_delay function
- Exclude arm_acle.h import for MSVC
---
 src/include/storage/s_lock.h     | 10 +++++++++-
 src/port/pg_crc32c_armv8.c       |  2 ++
 src/tools/msvc/MSBuildProject.pm | 15 +++++++++++----
 src/tools/msvc/Mkvcbuild.pm      |  9 +++++++--
 src/tools/msvc/Solution.pm       |  9 +++++++--
 src/tools/msvc/gendef.pl         |  8 ++++----
 6 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 8a5a905e38..dfbbb5f10a 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -912,13 +912,21 @@ typedef LONG slock_t;
 #define SPIN_DELAY() spin_delay()
 
 /* If using Visual C++ on Win64, inline assembly is unavailable.
- * Use a _mm_pause intrinsic instead of rep nop.
+ * Use _mm_pause (x64) or __isb(arm64) intrinsic instead of rep nop.
  */
 #if defined(_WIN64)
 static __forceinline void
 spin_delay(void)
 {
+#ifdef _M_ARM64
+	/*
+	 * arm64 way of hinting processor for spin loops optimisations
+	 * ref: https://community.arm.com/support-forums/f/infrastructure-solutions-forum/48654/ssetoneon-faq
+	*/
+	__isb(_ARM64_BARRIER_SY);
+#else
 	_mm_pause();
+#endif
 }
 #else
 static __forceinline void
diff --git a/src/port/pg_crc32c_armv8.c b/src/port/pg_crc32c_armv8.c
index 9e301f96f6..981718752f 100644
--- a/src/port/pg_crc32c_armv8.c
+++ b/src/port/pg_crc32c_armv8.c
@@ -14,7 +14,9 @@
  */
 #include "c.h"
 
+#ifndef _MSC_VER
 #include <arm_acle.h>
+#endif
 
 #include "port/pg_crc32c.h"
 
diff --git a/src/tools/msvc/MSBuildProject.pm b/src/tools/msvc/MSBuildProject.pm
index 5e312d232e..044907ef99 100644
--- a/src/tools/msvc/MSBuildProject.pm
+++ b/src/tools/msvc/MSBuildProject.pm
@@ -310,11 +310,18 @@ sub WriteItemDefinitionGroup
 	  : ($self->{type} eq "dll" ? 'DynamicLibrary' : 'StaticLibrary');
 	my $libs = $self->GetAdditionalLinkerDependencies($cfgname, ';');
 
-	my $targetmachine =
-	  $self->{platform} eq 'Win32' ? 'MachineX86' : 'MachineX64';
+	my $targetmachine;
+	if ($self->{platform} eq 'Win32') {
+		$targetmachine = 'MachineX86';
+	} elsif ($self->{platform} eq 'ARM64'){
+		$targetmachine = 'MachineARM64';
+	} else {
+		$targetmachine = 'MachineX64';
+	}
 
 	my $includes = join ';', @{$self->{includes}}, "";
-
+	# arm64 linker only supports dynamic base address
+	my $cfgrandbaseaddress = $self->{platform} eq 'ARM64' ? 'true' : 'false';
 	print $f <<EOF;
   <ItemDefinitionGroup Condition="'\$(Configuration)|\$(Platform)'=='$cfgname|$self->{platform}'">
     <ClCompile>
@@ -347,7 +354,7 @@ sub WriteItemDefinitionGroup
       <ProgramDatabaseFile>.\\$cfgname\\$self->{name}\\$self->{name}.pdb</ProgramDatabaseFile>
       <GenerateMapFile>false</GenerateMapFile>
       <MapFileName>.\\$cfgname\\$self->{name}\\$self->{name}.map</MapFileName>
-      <RandomizedBaseAddress>false</RandomizedBaseAddress>
+      <RandomizedBaseAddress>$cfgrandbaseaddress</RandomizedBaseAddress>
       <!-- Permit links to MinGW-built, 32-bit DLLs (default before VS2012). -->
       <ImageHasSafeExceptionHandlers/>
       <SubSystem>Console</SubSystem>
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 105f5c72a2..2ebc71b621 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -114,8 +114,13 @@ sub mkvcbuild
 
 	if ($vsVersion >= '9.00')
 	{
-		push(@pgportfiles, 'pg_crc32c_sse42_choose.c');
-		push(@pgportfiles, 'pg_crc32c_sse42.c');
+		if ($solution->{platform} eq 'ARM64') {
+			push(@pgportfiles, 'pg_crc32c_armv8_choose.c');
+			push(@pgportfiles, 'pg_crc32c_armv8.c');
+		} else {
+			push(@pgportfiles, 'pg_crc32c_sse42_choose.c');
+			push(@pgportfiles, 'pg_crc32c_sse42.c');
+		}
 		push(@pgportfiles, 'pg_crc32c_sb8.c');
 	}
 	else
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index a21ea9bef9..106c0916ed 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -67,8 +67,13 @@ sub DeterminePlatform
 		# Examine CL help output to determine if we are in 32 or 64-bit mode.
 		my $output = `cl /help 2>&1`;
 		$? >> 8 == 0 or die "cl command not found";
-		$self->{platform} =
-		  ($output =~ /^\/favor:<.+AMD64/m) ? 'x64' : 'Win32';
+		if ($output =~ /^\/favor:<.+AMD64/m) {
+			$self->{platform} = 'x64';
+		} elsif($output =~ /for ARM64$/m) {
+			$self->{platform} = 'ARM64';
+		} else {
+			$self->{platform} = 'Win32';
+		}
 	}
 	else
 	{
diff --git a/src/tools/msvc/gendef.pl b/src/tools/msvc/gendef.pl
index b8c514a831..2068484b14 100644
--- a/src/tools/msvc/gendef.pl
+++ b/src/tools/msvc/gendef.pl
@@ -120,9 +120,9 @@ sub writedef
 	{
 		my $isdata = $def->{$f} eq 'data';
 
-		# Strip the leading underscore for win32, but not x64
+		# Strip the leading underscore for win32, but not x64 and arm64
 		$f =~ s/^_//
-		  unless ($platform eq "x64");
+		  unless ($platform ne "Win32");
 
 		# Emit just the name if it's a function symbol, or emit the name
 		# decorated with the DATA option for variables.
@@ -144,13 +144,13 @@ sub usage
 {
 	die(    "Usage: gendef.pl <modulepath> <platform>\n"
 		  . "    modulepath: path to dir with obj files, no trailing slash"
-		  . "    platform: Win32 | x64");
+		  . "    platform: Win32 | x64 | ARM64");
 }
 
 usage()
   unless scalar(@ARGV) == 2
   && ( ($ARGV[0] =~ /\\([^\\]+$)/)
-	&& ($ARGV[1] eq 'Win32' || $ARGV[1] eq 'x64'));
+	&& ($ARGV[1] eq 'Win32' || $ARGV[1] eq 'x64' || $ARGV[1] eq 'ARM64'));
 my $defname  = uc $1;
 my $deffile  = "$ARGV[0]/$defname.def";
 my $platform = $ARGV[1];
-- 
2.35.0.windows.1

