Skip to content

Commit

Permalink
Support mingw compiler (#3869)
Browse files Browse the repository at this point in the history
* Add OS compat targeting windows gnu
In contrast to UnixCompat, this generates code with dso_local.

Depending on whether the target OS is 32 bit or 64 bit, the `__gxx_personality_v0` and
`__gxx_personality_seh0` personality is used, respectively.

* Make registry functions available when using mingw
Currently, mingw is only missing the `SE_REGISTRY_WOW64_64KEY`.

* Use standard complex types with mingw
* Use `%S` instead of `%ws` format specifier

The `w` argument size modifier prefix is a Microsoft extension and does not work
with mingw-msvcrt (but when using ucrt).

However, `%S` is equivalent to `%ws` for (sn)printf.
  • Loading branch information
avdv committed Apr 14, 2024
1 parent 9d924ab commit cb745e4
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 5 deletions.
2 changes: 1 addition & 1 deletion clib/src/main/resources/scala-native/complex.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#if defined(SCALANATIVE_COMPILE_ALWAYS) || defined(__SCALANATIVE_C_COMPLEX)
#include <complex.h>

#if defined(_WIN32)
#if defined(_WIN32) && !defined(__MINGW32__)
typedef _Fcomplex FloatComplex;
typedef _Dcomplex DoubleComplex;
#else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ int scalanative_unwind_get_proc_name(void *cursor, char *buffer, size_t length,
void *address = ucontext->stack[ucontext->cursor];
PSYMBOL_INFOW symbol = &ucontext->symbol.info;
SymFromAddrW(ucontext->process, (DWORD64)address, 0, symbol);
snprintf(buffer, length, "%ws", symbol->Name);
snprintf(buffer, length, "%S", symbol->Name);
memcpy(offset, &(symbol->Address), sizeof(void *));
if (SymGetLineFromAddr(ucontext->process, (DWORD64)address,
&displacement, &line)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,18 @@ private[codegen] abstract class AbstractCodeGen(
private val generated = mutable.Set.empty[String]
private val externSigMembers = mutable.Map.empty[nir.Sig, nir.Global.Member]

private def isGnu: Boolean = {
meta.buildConfig.compilerConfig.configuredOrDetectedTriple.env
.startsWith("gnu")
}

final val os: OsCompat = {
import scala.scalanative.codegen.llvm.compat.os._
if (meta.platform.targetsWindows) new WindowsCompat(this)
if (meta.platform.targetsWindows)
if (isGnu)
new WindowsGnuCompat(this)
else
new WindowsCompat(this)
else new UnixCompat(this)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package scala.scalanative
package codegen.llvm
package compat.os

import scala.scalanative.codegen.llvm.AbstractCodeGen
import scala.scalanative.nir.Defn.Define.DebugInfo
import scala.scalanative.util.ShowBuilder

private[codegen] class WindowsGnuCompat(codegen: AbstractCodeGen)
extends OsCompat(codegen) {

import codegen.{pointerType => ptrT}

val ehWrapperTy = "@_ZTIN11scalanative16ExceptionWrapperE"
val excRecTy = s"{ $ptrT, i32 }"
val beginCatch = "@__cxa_begin_catch"
val endCatch = "@__cxa_end_catch"
val catchSig =
if (useOpaquePointers) s"$ptrT $ehWrapperTy"
else s"i8* bitcast ({ i8*, i8*, i8* }* $ehWrapperTy to i8*)"
val landingpad =
s"landingpad $excRecTy catch $catchSig"
val typeid =
s"call i32 @llvm.eh.typeid.for($catchSig)"

protected val osPersonalityType: String =
if (codegen.meta.buildConfig.compilerConfig.is32BitPlatform)
"@__gxx_personality_v0"
else
"@__gxx_personality_seh0"

override def genBlockAlloca(block: nir.ControlFlow.Block)(implicit
sb: ShowBuilder
): Unit =
()

def genLandingPad(
unwind: nir.Next.Unwind
)(implicit
fresh: nir.Fresh,
pos: nir.SourcePosition,
sb: ShowBuilder
): Unit = {
import sb._
val nir.Next.Unwind(nir.Val.Local(excname, _), next) = unwind

val excpad = "_" + excname.id + ".landingpad"
val excsucc = excpad + ".succ"
val excfail = excpad + ".fail"

val exc = "%_" + excname.id
val rec, r0, r1, id, cmp = "%_" + fresh().id
val w0, w1, w2 = "%_" + fresh().id

def line(s: String) = { newline(); str(s) }

line(s"$excpad:")
indent()
line(s"$rec = $landingpad")
line(s"$r0 = extractvalue $excRecTy $rec, 0")
line(s"$r1 = extractvalue $excRecTy $rec, 1")
line(s"$id = $typeid")
line(s"$cmp = icmp eq i32 $r1, $id")
line(s"br i1 $cmp, label %$excsucc, label %$excfail")
unindent()

line(s"$excsucc:")
indent()
line(s"$w0 = call $ptrT $beginCatch($ptrT $r0)")
if (useOpaquePointers) {
line(s"$w2 = getelementptr ptr, ptr $w0, i32 1")
line(s"$exc = load ptr, ptr $w2")
} else {
line(s"$w1 = bitcast i8* $w0 to i8**")
line(s"$w2 = getelementptr i8*, i8** $w1, i32 1")
line(s"$exc = load i8*, i8** $w2")
}
line(s"call void $endCatch()")
str("br ")
codegen.genNext(next)
unindent()

line(s"$excfail:")
indent()
line(s"resume $excRecTy $rec")
unindent()
}

def genPrelude()(implicit builder: ShowBuilder): Unit = {
import builder._
line(s"declare i32 @llvm.eh.typeid.for($ptrT)")
line(s"declare dso_local i32 $osPersonalityType(...)")
line(s"declare dso_local $ptrT $beginCatch($ptrT)")
line(s"declare dso_local void $endCatch()")
line(s"$ehWrapperTy = external constant { $ptrT, $ptrT, $ptrT }")
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if (defined(_WIN32) || defined(WIN32)) && !defined(__MINGW64__)
#if (defined(_WIN32) || defined(WIN32))
#define WIN32_LEAN_AND_MEAN
#include <accctrl.h>

Expand All @@ -17,6 +17,8 @@ int scalanative_se_provider_defined_object() {
}
int scalanative_se_wmiguid_object() { return SE_WMIGUID_OBJECT; }
int scalanative_se_registry_wow64_32key() { return SE_REGISTRY_WOW64_32KEY; }
#ifndef __MINGW32__
// missing in mingw 3.11 / mingw-64 12.0.0
int scalanative_se_registry_wow64_64key() { return SE_REGISTRY_WOW64_64KEY; }

#endif
#endif // defined(_WIN32)

0 comments on commit cb745e4

Please sign in to comment.