Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GCC Compiler Support #1791

Merged
merged 2 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 71 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ COMPARE ?= 1
NON_MATCHING ?= 0
# If ORIG_COMPILER is 1, compile with QEMU_IRIX and the original compiler
ORIG_COMPILER ?= 0
# If COMPILER is "gcc", compile with GCC instead of IDO.
COMPILER ?= ido
# if WERROR is 1, pass -Werror to CC_CHECK, so warnings would be treated as errors
WERROR ?= 0
# Keep .mdebug section in build
Expand Down Expand Up @@ -69,9 +71,18 @@ N64_EMULATOR ?=
# Ensure the map file being created using English localization
export LANG := C

CFLAGS :=
CPPFLAGS :=

ifeq ($(COMPILER),gcc)
CPPFLAGS += -DCOMPILER_GCC
NON_MATCHING := 1
RUN_CC_CHECK := 0
endif

ifneq ($(NON_MATCHING),0)
CFLAGS := -DNON_MATCHING
CPPFLAGS := -DNON_MATCHING
CFLAGS += -DNON_MATCHING -DAVOID_UB
CPPFLAGS += -DNON_MATCHING -DAVOID_UB
COMPARE := 0
endif

Expand All @@ -92,8 +103,15 @@ ifneq ($(shell type $(MIPS_BINUTILS_PREFIX)ld >/dev/null 2>/dev/null; echo $$?),
$(error Unable to find $(MIPS_BINUTILS_PREFIX)ld. Please install or build MIPS binutils, commonly mips-linux-gnu. (or set MIPS_BINUTILS_PREFIX if your MIPS binutils install uses another prefix))
endif

CC := tools/ido_recomp/$(DETECTED_OS)/7.1/cc
CC_OLD := tools/ido_recomp/$(DETECTED_OS)/5.3/cc
# Detect compiler and set variables appropriately.
ifeq ($(COMPILER),gcc)
CC := $(MIPS_BINUTILS_PREFIX)gcc
else ifeq ($(COMPILER),ido)
CC := tools/ido_recomp/$(DETECTED_OS)/7.1/cc
CC_OLD := tools/ido_recomp/$(DETECTED_OS)/5.3/cc
else
$(error Unsupported compiler. Please use either ido or gcc as the COMPILER variable.)
endif

# if ORIG_COMPILER is 1, check that either QEMU_IRIX is set or qemu-irix package installed
ifeq ($(ORIG_COMPILER),1)
Expand Down Expand Up @@ -177,18 +195,36 @@ SFCFLAGS := --matching
# We can't use the C preprocessor for this because it won't substitute inside string literals.
BUILD_DIR_REPLACE := sed -e 's|$$(BUILD_DIR)|$(BUILD_DIR)|g'

CFLAGS += -G 0 -non_shared -Xcpluscomm -nostdinc -Wab,-r4300_mul
GBI_DEFINES := -DF3DEX_GBI_2 -DF3DEX_GBI_PL -DGBI_DOWHILE

WARNINGS := -fullwarn -verbose -woff 624,649,838,712,516,513,596,564,594,807
ASFLAGS := -march=vr4300 -32 -G0
GBI_DEFINES := -DF3DEX_GBI_2 -DF3DEX_GBI_PL -DGBI_DOWHILE
COMMON_DEFINES := -D_MIPS_SZLONG=32 $(GBI_DEFINES)
AS_DEFINES := $(COMMON_DEFINES) -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_ULTRA64
C_DEFINES := $(COMMON_DEFINES) -DLANGUAGE_C -D_LANGUAGE_C
ENDIAN := -EB
ifeq ($(COMPILER),gcc)
# MIPS options
CFLAGS += -G 0 -march=vr4300 -mtune=vr4300 -mfix4300 -mabi=32 -mno-abicalls -mdivide-breaks
hensldm marked this conversation as resolved.
Show resolved Hide resolved
# C dialect options
CFLAGS += -nostdinc -fno-PIC -fno-common -ffreestanding -fbuiltin -fno-builtin-sinf -fno-builtin-cosf -funsigned-char

OPTFLAGS := -O2 -g3
MIPS_VERSION := -mips2
WARNINGS := $(CC_CHECK_WARNINGS)
ASFLAGS := -march=vr4300 -32 -G0
COMMON_DEFINES := $(GBI_DEFINES)
AS_DEFINES := $(COMMON_DEFINES) -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_ULTRA64
C_DEFINES := $(COMMON_DEFINES) -D_LANGUAGE_C
ENDIAN :=
hensldm marked this conversation as resolved.
Show resolved Hide resolved

OPTFLAGS := -Os -ffast-math -ftrapping-math -fno-associative-math
MIPS_VERSION := -mips3
else
CFLAGS += -G 0 -non_shared -Xcpluscomm -nostdinc -Wab,-r4300_mul

WARNINGS := -fullwarn -verbose -woff 624,649,838,712,516,513,596,564,594,807
ASFLAGS := -march=vr4300 -32 -G0
COMMON_DEFINES := -D_MIPS_SZLONG=32 $(GBI_DEFINES)
AS_DEFINES := $(COMMON_DEFINES) -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_ULTRA64
C_DEFINES := $(COMMON_DEFINES) -D_LANGUAGE_C
ENDIAN := -EB

OPTFLAGS := -O2 -g3
MIPS_VERSION := -mips2
endif

# Use relocations and abi fpr names in the dump
OBJDUMP_FLAGS := --disassemble --reloc --disassemble-zeroes -Mreg-names=32
Expand Down Expand Up @@ -221,7 +257,12 @@ SPEC := spec
# create asm directories
$(shell mkdir -p asm data extracted)

ifeq ($(COMPILER),ido)
SRC_DIRS := $(shell find src -type d -not -path src/gcc_fix)
else
SRC_DIRS := $(shell find src -type d)
endif

ASM_DIRS := $(shell find asm -type d -not -path "asm/non_matchings*") $(shell find data -type d)

ifneq ($(wildcard $(EXTRACTED_DIR)/assets/audio),)
Expand Down Expand Up @@ -369,6 +410,7 @@ $(shell mkdir -p $(foreach dir, \
$(dir:$(EXTRACTED_DIR)/%=$(BUILD_DIR)/%)))
endif

ifeq ($(COMPILER),ido)
# directory flags
$(BUILD_DIR)/src/libultra/os/%.o: OPTFLAGS := -O1
$(BUILD_DIR)/src/libultra/voice/%.o: OPTFLAGS := -O2
Expand Down Expand Up @@ -417,7 +459,16 @@ $(BUILD_DIR)/src/audio/%.o: CC := $(ASM_PROC) $(ASM_PROC_FLAGS) $(CC) -- $(AS) $
$(BUILD_DIR)/src/overlays/%.o: CC := $(ASM_PROC) $(ASM_PROC_FLAGS) $(CC) -- $(AS) $(ASFLAGS) --

$(BUILD_DIR)/assets/%.o: CC := $(ASM_PROC) $(ASM_PROC_FLAGS) $(CC) -- $(AS) $(ASFLAGS) --

else
# Note that if adding additional assets directories for modding reasons these flags must also be used there
$(BUILD_DIR)/assets/%.o: CFLAGS += -fno-zero-initialized-in-bss -fno-toplevel-reorder
$(BUILD_DIR)/src/%.o: CFLAGS += -fexec-charset=euc-jp
$(BUILD_DIR)/src/libultra/libc/ll.o: OPTFLAGS := -Ofast
$(BUILD_DIR)/src/overlays/%.o: CFLAGS += -fno-merge-constants -mno-explicit-relocs -mno-split-addresses

# Temporary: Hardcoded pointers in assets (specifically object_dmask and object_osn)
$(BUILD_DIR)/assets/%.o: WARNINGS += -Wno-error=int-conversion
endif

$(SHIFTJIS_O_FILES): CC_CHECK_WARNINGS += -Wno-multichar -Wno-type-limits -Wno-overflow

Expand Down Expand Up @@ -550,9 +601,13 @@ $(BUILD_DIR)/%.o: %.s
$(CPP) $(CPPFLAGS) $(IINC) $< | $(AS) $(ASFLAGS) $(IINC) $(ENDIAN) -o $@

$(BUILD_DIR)/assets/text/%.o: assets/text/%.c
ifneq ($(COMPILER),gcc)
# Preprocess text with modern cpp for varargs macros
$(CPP) -undef -D_LANGUAGE_C -D__sgi $(CPPFLAGS) $(IINC) $< -o $(@:.o=.c)
$(CC) -c $(CFLAGS) $(WARNINGS) $(C_DEFINES) $(MIPS_VERSION) $(ENDIAN) $(OPTFLAGS) -o $@ $(@:.o=.c)
$(CC) -c $(CFLAGS) $(IINC) $(WARNINGS) $(C_DEFINES) $(MIPS_VERSION) $(ENDIAN) $(OPTFLAGS) -o $@ $(@:.o=.c)
else
$(CC) -c $(CFLAGS) $(IINC) $(WARNINGS) $(C_DEFINES) $(MIPS_VERSION) $(ENDIAN) $(OPTFLAGS) -o $@ $<
endif

$(BUILD_DIR)/assets/%.o: assets/%.c
$(CC) -c $(CFLAGS) $(IINC) $(WARNINGS) $(C_DEFINES) $(MIPS_VERSION) $(ENDIAN) $(OPTFLAGS) -o $@ $<
Expand Down
3 changes: 3 additions & 0 deletions spec
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ beginseg
include "$(BUILD_DIR)/src/boot/libc/strcpy.o"
include "$(BUILD_DIR)/src/boot/libc/memmove.o"
include "$(BUILD_DIR)/src/boot/build.o"
#ifdef COMPILER_GCC
include "$(BUILD_DIR)/src/gcc_fix/missing_gcc_functions.o"
#endif
endseg

beginseg
Expand Down
237 changes: 237 additions & 0 deletions src/gcc_fix/missing_gcc_functions.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/* --------------------------------------------------------------------------------*/
/* Depending on the toolchain used, an appropriate precompiled libgcc library */
/* may not exist and cannot be linked against. Until we have a better work around, */
/* necessary gcc functions are hosted here in order to properly compile. */
/* This file is NOT a part of the original game and only exists to help gcc work. */
/* --------------------------------------------------------------------------------*/

#include "global.h"

// Self-hosted libc memory functions, gcc assumes these exist even in a freestanding
// environment and there is no way to tell it otherwise.

int memcmp(const void* s1, const void* s2, size_t n) {
const u8* m1 = s1;
const u8* m2 = s2;
size_t i;

for (i = 0; i < n; i++) {
if (m1[i] < m2[i]) {
return -1;
} else if (m1[i] > m2[i]) {
return 1;
}
}

return 0;
}

// Conversions involving 64-bit integer types required by the O32 MIPS ABI.

// f32 -> u64, negative values become 0
u64 __fixunssfdi(f32 a) {
if (a > 0.0f) {
register union {
f64 f;
u64 i;
} m;

__asm__("cvt.l.s %0, %1" : "=f"(m.f) : "f"(a));
return m.i;
}
return 0;
}

// f64 -> u64, negative values become 0
u64 __fixunsdfdi(f64 a) {
if (a > 0.0) {
register union {
f64 f;
u64 i;
} m;

__asm__("cvt.l.d %0, %1" : "=f"(m.f) : "f"(a));
return m.i;
}
return 0;
}

// f32 -> s64
s64 __fixsfdi(f32 c) {
register union {
f64 f;
s64 i;
} m;

__asm__("cvt.l.s %0, %1" : "=f"(m.f) : "f"(c));
return m.i;
}

// f64 -> s64
s64 __fixdfdi(f64 c) {
register union {
f64 f;
s64 i;
} m;

__asm__("cvt.l.d %0, %1" : "=f"(m.f) : "f"(c));
return m.i;
}

// s64 -> f32
f32 __floatdisf(s64 c) {
register union {
f64 f;
s64 i;
} m;
register f32 v;

m.i = c;
__asm__("cvt.s.l %0, %1" : "=f"(v) : "f"(m.f));
return v;
}

// s64 -> f64
f64 __floatdidf(s64 c) {
register union {
f64 f;
s64 i;
} m;
register f64 v;

m.i = c;
__asm__("cvt.d.l %0, %1" : "=f"(v) : "f"(m.f));
return v;
}

// u64 -> f32
f32 __floatundisf(u64 c) {
register union {
f64 f;
u64 i;
} m;
register f32 v;

m.i = c;
__asm__("cvt.s.l %0, %1" : "=f"(v) : "f"(m.f));
if ((s64)c < 0) {
// cvt.s.l assumes signed input, adjust output
v += 4294967296.0f; // 2^32
}
return v;
}

// u64 -> f64
f64 __floatundidf(u64 c) {
register union {
f64 f;
u64 i;
} m;
register f64 v;

m.i = c;
__asm__("cvt.d.l %0, %1" : "=f"(v) : "f"(m.f));
if ((s64)c < 0) {
// cvt.d.l assumes signed input, adjust output
v += 18446744073709551616.0; // 2^64
}
return v;
}

// Compute x^m by binary exponentiation

f32 __powisf2(f32 x, s32 m) {
u32 n = (m < 0) ? -m : m;
f32 y = (n % 2 != 0) ? x : 1.0f;

while (n >>= 1) {
x = x * x;

if (n % 2 != 0) {
y = y * x;
}
}
return (m < 0) ? (1.0f / y) : y;
}

// Compute division and modulo of 64-bit signed and unsigned integers

__asm__(" \n\
.set push \n\
.set noreorder \n\
.set gp=64 \n\
\n\
.global __umoddi3 \n\
__umoddi3: \n\
.type __umoddi3, @function \n\
.ent __umoddi3 \n\
sw $a0, 0x0($sp) \n\
sw $a1, 0x4($sp) \n\
sw $a2, 0x8($sp) \n\
sw $a3, 0xC($sp) \n\
ld $t6, 0($sp) \n\
ld $t7, 8($sp) \n\
dremu $v0, $t6, $t7 \n\
dsll32 $v1, $v0, 0 \n\
dsra32 $v1, $v1, 0 \n\
jr $ra \n\
dsra32 $v0, $v0, 0 \n\
.end __umoddi3 \n\
.size __umoddi3, . - __umoddi3 \n\
\n\
.global __udivdi3 \n\
__udivdi3: \n\
.type __udivdi3, @function \n\
.ent __udivdi3 \n\
sw $a0, 0x0($sp) \n\
sw $a1, 0x4($sp) \n\
sw $a2, 0x8($sp) \n\
sw $a3, 0xC($sp) \n\
ld $t6, 0($sp) \n\
ld $t7, 8($sp) \n\
ddivu $v0, $t6, $t7 \n\
dsll32 $v1, $v0, 0 \n\
dsra32 $v1, $v1, 0 \n\
jr $ra \n\
dsra32 $v0, $v0, 0 \n\
.end __udivdi3 \n\
.size __udivdi3, . - __udivdi3 \n\
\n\
.global __moddi3 \n\
__moddi3: \n\
.type __moddi3, @function \n\
.ent __moddi3 \n\
sw $a0, 0x0($sp) \n\
sw $a1, 0x4($sp) \n\
sw $a2, 0x8($sp) \n\
sw $a3, 0xC($sp) \n\
ld $t6, 0($sp) \n\
ld $t7, 8($sp) \n\
drem $v0, $t6, $t7 \n\
dsll32 $v1, $v0, 0 \n\
dsra32 $v1, $v1, 0 \n\
jr $ra \n\
dsra32 $v0, $v0, 0 \n\
.end __moddi3 \n\
.size __moddi3, . - __moddi3 \n\
\n\
.global __divdi3 \n\
__divdi3: \n\
.type __divdi3, @function \n\
.ent __divdi3 \n\
sw $a0, 0x0($sp) \n\
sw $a1, 0x4($sp) \n\
sw $a2, 0x8($sp) \n\
sw $a3, 0xC($sp) \n\
ld $t6, 0($sp) \n\
ld $t7, 8($sp) \n\
ddiv $v0, $t6, $t7 \n\
dsll32 $v1, $v0, 0 \n\
dsra32 $v1, $v1, 0 \n\
jr $ra \n\
dsra32 $v0, $v0, 0 \n\
.end __divdi3 \n\
.size __divdi3, . - __divdi3 \n\
\n\
.set pop \n\
\n");
Loading