golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.12k stars 17.45k forks source link

gollvm: supporting i386/i686 builds (Intel) #42440

Open advancedwebdeveloper opened 3 years ago

advancedwebdeveloper commented 3 years ago

I am creating this issue for a future patch (and others should be expected, for the same purpose), observable on/threw Gerrit. It would be referenced (a bit) later.

This is about compiling & running 32bit userspace Go applications on (under?) 32bit CPU/hardware/OS kernel (system-on-board). Something for 32bit AMD's CPUs would be a good cause for a separate Github issue.

This is not covering the following (corresponding options/use cases should be covered within separate Github issues):

This issue covers few OS-compiler combinations (at once). I will update this summary once there would be a demand to extend the scope. GCC, Clang compilers on Linux. MSVC compiler on Windows. Not sure what to assume on MacOS (I heard that they have a hybrid 32bit/64bit kernel - but I am not an expert). GCC, Clang on FreeBSD.

advancedwebdeveloper commented 3 years ago

I am attaching the specification, System V Application Binary Interface

intel386-psABI-1.1.pdf

advancedwebdeveloper commented 3 years ago

My first patch, submitted for a review is https://go-review.googlesource.com/c/gollvm/+/270219 . This one is related to CMake's configuration files:

advancedwebdeveloper commented 3 years ago

My next patch would cover driver/ArchCpusAttrs.h

https://go-review.googlesource.com/c/gollvm/+/271457

Since it is required to perform pre-checks of supported CPU features (in my case - I have a relic Intel Celeron M440), which is resolved by Clang (common code for any LLVM related projects, for these checks - so both llvm-goc and pre-installed Clang would both act similar, on a specific hardware) - I used the following tool:

include "llvm/ADT/StringRef.h"

include "llvm/ADT/StringMap.h"

include "llvm/MC/SubtargetFeature.h"

include "llvm/Support/Host.h"

using namespace llvm; SubtargetFeatures Features1;

int main (int argc, char **argv) { sys::getHostCPUName(); StringMap HostFeatures; if (sys::getHostCPUFeatures(HostFeatures)) for (auto &F : HostFeatures) Features1.AddFeature(F.first(), F.second);

printf("test %s", Features1.getString().c_str()); printf("\nsomething else\n"); return 0; }

. Many thanks to @topperc for guiding me threw this.

advancedwebdeveloper commented 3 years ago

I see that CPU instructions are defined in the following files: https://github.com/llvm/llvm-project/blob/756f5978410809530150f5e1cd425e85ad94d1cd/llvm/lib/Target/X86/X86InstrFormats.td https://github.com/llvm/llvm-project/blob/756f5978410809530150f5e1cd425e85ad94d1cd/llvm/lib/Target/X86/X86InstrInfo.td https://github.com/llvm/llvm-project/blob/756f5978410809530150f5e1cd425e85ad94d1cd/llvm/lib/Target/X86/X86.td https://llvm.org/doxygen/X86TargetParser_8cpp_source.html . ABI specific stuff could be found here: https://clang.llvm.org/doxygen/CodeGen_2TargetInfo_8cpp_source.html available calling conventions https://github.com/llvm/llvm-project/blob/a022b1ccd8d849dd59a8e7b76c0406cc80dee0f0/llvm/include/llvm/IR/CallingConv.h .

advancedwebdeveloper commented 3 years ago

I missed a file, where library path should be handled: https://go.googlesource.com/gollvm/+/refs/heads/master/driver/Driver.cpp#70 I think I will submit the change within one of my future patches (yet to be submitted, as for now).

advancedwebdeveloper commented 3 years ago

@thanm, @cherrymui: I don't understand why CABIOracle contains "Oracle" in it's naming. What does Oracle corp. has to do with you naming convention?

Attaching some diagrams, as a rude summary:

advancedwebdeveloper commented 3 years ago

go-llvm-cabi-oracle_8cpp__incl

advancedwebdeveloper commented 3 years ago

go-llvm-cabi-oracle_8h__dep__incl

advancedwebdeveloper commented 3 years ago

go-llvm-cabi-oracle_8h__incl

advancedwebdeveloper commented 3 years ago

classCABIOracleArgumentAnalyzer__coll__graph classCABIOracleArgumentAnalyzer__inherit__graph classCABIOracle__coll__graph classCABIOracleX86__64__SysV__coll__graph classCABIOracleX86__64__SysV__inherit__graph

advancedwebdeveloper commented 3 years ago

I see some adoptions of EightByteInfo::determineABITypesFor[LLVM's calling convention]() function.

Looks like EightByteInfo class has a constructor, which initializes private variable typeManager_ with the same of the second passed argument (of type *TypeManager). Correct me/elaborate, if I have an improper understanding/vision of the API. It's not currently cleat whether the switch (cconv) is a good location to define the logic of handling 32bit and 64bit calling conventions (calling conventions for 32bit variation of a specific arch. has pretty diverse ABI handling, compared to how it is done for 64bit variation of that arch.).

ianlancetaylor commented 3 years ago

@advancedwebdeveloper "oracle" happens to be the name of a company but it is also an English word. It also has a well established meaning specific to computer programming: https://en.wikipedia.org/wiki/Oracle_machine .

thanm commented 3 years ago

Ian is correct. "Oracle" is being used in the non-commercial sense (as in "Oracle of Delphi"), e.g. some entity that you ask questions of.

advancedwebdeveloper commented 3 years ago

Referencing http://llvm.org/docs/LangRef.html#parameter-attributes - specific considerations would be added later

advancedwebdeveloper commented 3 years ago

Reminding about unresolved issue https://github.com/golang/go/issues/42975

advancedwebdeveloper commented 3 years ago

You are referencing System V x86_64 ABI spec. , on https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#61 . It looks like that's https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf#page=22 :

The classification of aggregate (structures and arrays) and union types works as follows:

  1. If the size of an object is larger than eight eightbytes, or it contains un-aligned fields, it has class MEMORY12.

In the same time - I am able to extract the following statements, from i386 ABI spec. http://www.sco.com/developers/devspecs/abi386-4.pdf#page=29 :

The Intel386 architecture does not require all data access to be properly aligned. But I suspect that it would be aligned by LLVM/Clang, in some way.

Unsure if the following contains any useful statements, for elaborating this:

For example, double-precision values occupy 1 doubleword (8-bytes), and their natural alignment is a word boundary, meaning their addresses are multiples of 4 .

advancedwebdeveloper commented 3 years ago

I am able to extract the following, from i386 ABI spec., on http://www.sco.com/developers/devspecs/abi386-4.pdf#page=36 :

The stack is word aligned. Although the architecture does not require any alignment of the stack, software convention and the operating system requires that the stack be aligned on a word boundary.

And by taking

the term word refers to a 32-bit object

into an account, on http://www.sco.com/developers/devspecs/abi386-4.pdf#page=27 - that would be 32/8=4 bytes

advancedwebdeveloper commented 3 years ago

So if it differs from what happens on x86_64 - the struct EightByteRegion should not be compiled on i686. And there have to be another structured type, for the similar purpose.

Probably that i686 oriented struct should contain such functions: void determineABITypesForC(); void determineABITypesForC(); It's constructor should contain

case llvm::CallingConv::C: determineABITypesForC(); break;

advancedwebdeveloper commented 3 years ago

Probably related to https://github.com/golang/go/issues/42440#issuecomment-735389706 : we could provide such functions:

CABIOracleC::CABIOracleC(TypeManager typeManager): CABIOracleArgumentAnalyzer(typeManager) ; CABIParamDisp CABIOracleC::classifyArgType(Btype btype); CABIParamInfo CABIOracleC::analyzeABIParam(Btype *paramType, ABIState &state); bool CABIOracleC::canPassDirectly(unsigned regsInt, unsigned regsSSE, ABIState &state);

ianlancetaylor commented 3 years ago

Stack alignment on 32-bit x86 has become quite complex. Search for "stack" in https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/x86-Options.html#x86-Options.

advancedwebdeveloper commented 3 years ago

@marmolejo , please elaborate regarding 32bit soft-CPU implementation and consideration for stack alignments. There where some relic i386/i686 ASIC CPUs produced, in the past - so not all options have sense. I was curious if future re-implementations of i686 compatible soft-CPUs could could assume specific alignments.

advancedwebdeveloper commented 3 years ago

CC @MicroCoreLabs @alfikpl

advancedwebdeveloper commented 3 years ago

@JonChesterfield , could you elaborate regarding relic 32bit AMD's CPUs? Which stack alignments should be considered, for old CPUs? Why?

advancedwebdeveloper commented 3 years ago

@tve , I remember that you tried to build Go applications for a retired/relic VIA's CPU (eons ago). Did you try to perform any specific optimizations, by using stack alignment?

advancedwebdeveloper commented 3 years ago

@kcadieux , @GreatKeeper : could you elaborate about MSVC's stack alignment, when compiling (and linking, by using Microsoft's linker) for 32bit Windows 10 (i686) ?

advancedwebdeveloper commented 3 years ago

Citation from https://reviews.llvm.org/D60748 :

Please also exclude FreeBSD from these changes, since we care a lot about backwards compatibility, and specifically about alignment requirements. (We have run into many issues in our ports collection where upstream assumes everything is 16-byte aligned on i386, which is NOT ABI compliant.)

I didn't new about about that, btw. @emaste , @kostikbel : could you explain more?

@pcordes , found your old post here . Could you explain more about Clang vs GCC behavior?

phoebewang commented 3 years ago

Currently, Clang always aligns to 4 bytes on i386 standard calling conversion. This is not strictly following psABI/gcc. Chen had a new patch https://reviews.llvm.org/D78564 to fix the problem after D60748 abandoned. But it hasn't been accepted.

MoringLiu commented 3 years ago

D78564 is trying to fix the wrong alignment when the parameters are unnamed parameters(Only for m128, m256 and m512). From what I know, When clang uses the stack to pass struct, it will always be aligned to 4 bytes, except m128, m256 and m512, no matter the parameter is named or unnamed. I have described the rule of __m128/256/512 in that D78564 . This is totally different from gcc. For example:

struct __attribute__((aligned(64))) X {
 int x;
};

gcc will align to 64 byte but clang will align to 4 byte.

For D78564, when the parameter is unnamed, the callee will always assume that the alignment of the unnamed parameter is align to 4 byte. For common struct there is no problem. But for __m128/256/512, caller will align these parameters to 16/32/64 bytes, the callee will get wrong result.

advancedwebdeveloper commented 3 years ago

Looks like I missed https://go.googlesource.com/gollvm/+/refs/heads/master/unittests/BackendCore/TestUtils.h#35

advancedwebdeveloper commented 3 years ago

@thanm, could you provide an extended explanation of 16 bytes sizing?

https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#156 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#374 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#447 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#809 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#856 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#996 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#1047 https://go.googlesource.com/gollvm/+/refs/heads/master/bridge/go-llvm-cabi-oracle.cpp#1134

Which of those are ABI specific (System V x86_64, not related to the current i686 issue)? Which are specific to https://tour.golang.org/basics/11 (int16)? Specific to LLVM itself?

thanm commented 3 years ago

could you provide an extended explanation of 16 bytes sizing?

Mailing list is a better place for questions of this sort. Happy to respond on golang-dev.