Add support for 32b MIPS architecture

* LLVM reactor backend: requires LLVM 7.0
* Subzero reactor backend: unittests hit unimplemented
  TargetMIPS32::lowerShuffleVector()

Bug: b/117854176
Change-Id: Ie58e3e438db6f1b442b05efecf9b645aff82321a
Reviewed-on: https://swiftshader-review.googlesource.com/c/21748
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Milko Leporis <milko.leporis@mips.com>
diff --git a/BUILD.gn b/BUILD.gn
index b36d9f9..672e51e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -96,16 +96,30 @@
         "-march=pentium4",
         "-mtune=generic",
       ]
+    } else if (target_cpu == "mipsel" && current_cpu == target_cpu) {
+      cflags += [
+        "-march=mipsel",
+        "-mcpu=mips32r2",
+        "-fPIC",
+        "-mhard-float",
+        "-mfp32",
+      ]
     }
 
     if (is_linux) {
-      ldflags = [
-        "-Wl,--hash-style=both",
-        "-Wl,--gc-sections",
-      ]
+      ldflags = [ "-Wl,--gc-sections" ]
+
+      if (target_cpu == "mipsel") {
+        ldflags += [
+          "-Wl,--hash-style=sysv",
+          "-mips32r2",
+        ]
+      } else {
+        ldflags += [ "-Wl,--hash-style=both" ]
+      }
 
       # A bug in the gold linker prevents using ICF on 32-bit (crbug.com/729532)
-      if (use_gold && target_cpu == "x86") {
+      if (use_gold && (target_cpu == "x86" || target_cpu == "mipsel")) {
         ldflags += [ "-Wl,--icf=none" ]
       }
     }
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90a62fa..8023fd4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,12 @@
     else()
         set(ARCH "arm")
     endif()
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "mips*")
+    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+        set(ARCH "mips64el")
+    else()
+        set(ARCH "mipsel")
+    endif()
 else()
     if(CMAKE_SIZEOF_VOID_P EQUAL 8)
         set(ARCH "x86_64")
@@ -133,9 +139,14 @@
         # Don't allow symbols to be overridden by another module.
         set_property(TARGET ${TARGET} APPEND_STRING PROPERTY COMPILE_FLAGS " -fvisibility=protected")
 
-        # Both hash-style are needed, because we want both gold and
-        # GNU ld to be able to read our libraries.
-        set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--hash-style=both")
+        if(ARCH STREQUAL "mipsel")
+          # MIPS supports sysv hash-style only.
+          set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--hash-style=sysv")
+        else()
+          # Both hash-style are needed, because we want both gold and
+          # GNU ld to be able to read our libraries.
+          set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--hash-style=both")
+        endif()
 
         # Gc sections is used in combination with each functions being
         # in its own section, to reduce the binary size.
@@ -214,6 +225,12 @@
         set_cpp_flag("-march=x86-64")
         set_cpp_flag("-mtune=generic")
     endif()
+    if(ARCH STREQUAL "mipsel")
+        set_cpp_flag("-march=mips32r2")
+        set_cpp_flag("-fPIC")
+        set_cpp_flag("-mhard-float")
+        set_cpp_flag("-mfp32")
+    endif()
 
     if(LINUX)
         set_cpp_flag("-DUSE_X11=1")
@@ -1408,6 +1425,59 @@
     ${LLVM_DIR}/lib/Target/ARM/Thumb1InstrInfo.cpp
     ${LLVM_DIR}/lib/Target/ARM/ARMLegalizerInfo.cpp
     ${LLVM_DIR}/lib/Target/ARM/ARMOptimizeBarriersPass.cpp
+    ${LLVM_DIR}/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+    ${LLVM_DIR}/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16FrameLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16HardFloat.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16HardFloatInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16InstrInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16ISelLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/Mips16RegisterInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsAnalyzeImmediate.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsAsmPrinter.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsCallLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsCCState.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsConstantIslandPass.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsDelaySlotFiller.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsExpandPseudo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsFastISel.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsInstrInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsInstructionSelector.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsISelDAGToDAG.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsISelLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsFrameLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsLegalizerInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsBranchExpansion.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsMCInstLower.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsMachineFunction.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsOptimizePICCall.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsOs16.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsRegisterBankInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsRegisterInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSEFrameLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSEInstrInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSEISelLowering.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSERegisterInfo.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsSubtarget.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsTargetMachine.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MipsTargetObjectFile.cpp
+    ${LLVM_DIR}/lib/Target/Mips/MicroMipsSizeReduction.cpp
+    ${LLVM_DIR}/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
     ${LLVM_DIR}/lib/Target/X86/AsmParser/X86AsmInstrumentation.cpp
     ${LLVM_DIR}/lib/Target/X86/AsmParser/X86AsmParser.cpp
     ${LLVM_DIR}/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
@@ -1625,11 +1695,13 @@
     ${LLVM_DIR}/include
     ${LLVM_DIR}/lib/Target/AArch64
     ${LLVM_DIR}/lib/Target/ARM
+    ${LLVM_DIR}/lib/Target/Mips
     ${LLVM_DIR}/lib/Target/X86
     ${LLVM_CONFIG_DIR}/common/include
     ${LLVM_CONFIG_DIR}/common/lib/IR
     ${LLVM_CONFIG_DIR}/common/lib/Target/AArch64
     ${LLVM_CONFIG_DIR}/common/lib/Target/ARM
+    ${LLVM_CONFIG_DIR}/common/lib/Target/Mips
     ${LLVM_CONFIG_DIR}/common/lib/Target/X86
     ${LLVM_CONFIG_DIR}/common/lib/Transforms/InstCombine
 )
@@ -1705,6 +1777,13 @@
             ${SUBZERO_DIR}/src/IceTargetLoweringARM32.cpp
         )
         set(SUBZERO_TARGET ARM32)
+    elseif(ARCH STREQUAL "mipsel")
+        list(APPEND SUBZERO_LIST
+            ${SUBZERO_DIR}/src/IceAssemblerMIPS32.cpp
+            ${SUBZERO_DIR}/src/IceInstMIPS32.cpp
+            ${SUBZERO_DIR}/src/IceTargetLoweringMIPS32.cpp
+        )
+        set(SUBZERO_TARGET MIPS32)
     else()
         message(FATAL_ERROR "Architecture '${ARCH}' not supported by Subzero")
     endif()
diff --git a/src/Reactor/BUILD.gn b/src/Reactor/BUILD.gn
index 9cf8e13..1ad06e4 100644
--- a/src/Reactor/BUILD.gn
+++ b/src/Reactor/BUILD.gn
@@ -41,11 +41,16 @@
       "SZTARGET=X8664",
       "SUBZERO_TARGET=X8664",
     ]
-  } else {
+  } else if (target_cpu == "x86") {
     defines += [
       "SZTARGET=X8632",
       "SUBZERO_TARGET=X8632",
     ]
+  } else if (target_cpu == "mipsel") {
+    defines += [
+      "SZTARGET=MIPS32",
+      "SUBZERO_TARGET=MIPS32",
+    ]
   }
 
   include_dirs = [
@@ -153,16 +158,16 @@
       "/wd4201",  # nameless struct/union
       "/wd4245",  # conversion from int to unsigned int (llvm)
     ]
-  } else if (target_cpu == "x86" || target_cpu == "x64") {
-    cflags = [
-      "-Wno-unused-local-typedef",
-      "-msse2",
-    ]
-
+  } else {
+    cflags = [ "-Wno-unused-local-typedef" ]
     defines = [
       "__STDC_CONSTANT_MACROS",
       "__STDC_LIMIT_MACROS",
     ]
+
+    if (target_cpu == "x86" || target_cpu == "x64") {
+        cflags += [ "-msse2" ]
+    }
   }
 }
 
@@ -247,11 +252,17 @@
         "$subzero_dir/src/IceInstX8664.cpp",
         "$subzero_dir/src/IceTargetLoweringX8664.cpp",
       ]
-    } else {
+    } else if (target_cpu == "x86") {
       sources += [
         "$subzero_dir/src/IceInstX8632.cpp",
         "$subzero_dir/src/IceTargetLoweringX8632.cpp",
       ]
+    } else if (target_cpu == "mipsel") {
+      sources += [
+        "$subzero_dir/src/IceAssemblerMIPS32.cpp",
+        "$subzero_dir/src/IceInstMIPS32.cpp",
+        "$subzero_dir/src/IceTargetLoweringMIPS32.cpp",
+      ]
     }
 
     configs = [
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index ca0c0ae..c08572c 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -822,6 +822,8 @@
 			static const char arch[] = "arm64";
 		#elif defined(__arm__)
 			static const char arch[] = "arm";
+		#elif defined(__mips__)
+			static const char arch[] = "mipsel";
 		#else
 		#error "unknown architecture"
 		#endif
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 2126afb..76f5a72 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -106,6 +106,8 @@
 				return true;
 			#elif defined(__i386__) || defined(__x86_64__)
 				return false;
+			#elif defined(__mips__)
+				return false;
 			#else
 				#error "Unknown architecture"
 			#endif
@@ -373,6 +375,8 @@
 			assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_ARM);
 		#elif defined(__aarch64__)
 			assert(sizeof(void*) == 8 && elfHeader->e_machine == EM_AARCH64);
+		#elif defined(__mips__)
+			assert(sizeof(void*) == 4 && elfHeader->e_machine == EM_MIPS);
 		#else
 			#error "Unsupported platform"
 		#endif
@@ -526,6 +530,9 @@
 		#if defined(__arm__)
 			Flags.setTargetArch(Ice::Target_ARM32);
 			Flags.setTargetInstructionSet(Ice::ARM32InstructionSet_HWDivArm);
+		#elif defined(__mips__)
+			Flags.setTargetArch(Ice::Target_MIPS32);
+			Flags.setTargetInstructionSet(Ice::BaseInstructionSet);
 		#else   // x86
 			Flags.setTargetArch(sizeof(void*) == 8 ? Ice::Target_X8664 : Ice::Target_X8632);
 			Flags.setTargetInstructionSet(CPUID::SSE4_1 ? Ice::X86InstructionSet_SSE4_1 : Ice::X86InstructionSet_SSE2);
diff --git a/third_party/llvm-7.0/scripts/update.py b/third_party/llvm-7.0/scripts/update.py
index badabe2..fe30730 100755
--- a/third_party/llvm-7.0/scripts/update.py
+++ b/third_party/llvm-7.0/scripts/update.py
@@ -33,6 +33,7 @@
     ('AArch64', ('__aarch64__',)),
     ('ARM', ('__arm__',)),
     ('X86', ('__i386__', '__x86_64__')),
+    ('Mips', ('__mips__',)),
 ]
 
 LLVM_TRIPLES = {
@@ -47,6 +48,7 @@
         ('__i386__', 'i686-pc-linux-gnu'),
         ('__arm__', 'armv7-linux-gnueabihf'),
         ('__aarch64__', 'aarch64-linux-gnu'),
+        ('__mips__', 'mipsel-linux-gnu'),
     ],
 }
 
@@ -102,6 +104,7 @@
         os.path.join('lib', 'Target', 'AArch64'),
         os.path.join('lib', 'Target', 'ARM'),
         os.path.join('lib', 'Target', 'X86'),
+        os.path.join('lib', 'Target', 'Mips'),
         os.path.join('lib', 'Transforms', 'InstCombine'),
     ]
     for subdir in subdirs: