forked from OSchip/llvm-project
[lanai] Add Lanai backend to clang driver.
Changes to clang to add Lanai backend. Adds a new target, ABI and toolchain. General Lanai backend discussion on llvm-dev thread "[RFC] Lanai backend" (http://lists.llvm.org/pipermail/llvm-dev/2016-February/095118.html). Differential Revision: http://reviews.llvm.org/D17002 llvm-svn: 264655
This commit is contained in:
parent
83c3bd3e59
commit
d964cc22d1
|
@ -5950,6 +5950,111 @@ const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
|
|||
#include "clang/Basic/BuiltinsHexagon.def"
|
||||
};
|
||||
|
||||
class LanaiTargetInfo : public TargetInfo {
|
||||
// Class for Lanai (32-bit).
|
||||
// The CPU profiles supported by the Lanai backend
|
||||
enum CPUKind {
|
||||
CK_NONE,
|
||||
CK_V11,
|
||||
} CPU;
|
||||
|
||||
static const TargetInfo::GCCRegAlias GCCRegAliases[];
|
||||
static const char *const GCCRegNames[];
|
||||
|
||||
public:
|
||||
LanaiTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
|
||||
// Description string has to be kept in sync with backend.
|
||||
resetDataLayout("E" // Big endian
|
||||
"-m:e" // ELF name manging
|
||||
"-p:32:32" // 32 bit pointers, 32 bit aligned
|
||||
"-i64:64" // 64 bit integers, 64 bit aligned
|
||||
"-a:0:32" // 32 bit alignment of objects of aggregate type
|
||||
"-n32" // 32 bit native integer width
|
||||
"-S64" // 64 bit natural stack alignment
|
||||
);
|
||||
|
||||
// Setting RegParmMax equal to what mregparm was set to in the old
|
||||
// toolchain
|
||||
RegParmMax = 4;
|
||||
|
||||
// Set the default CPU to V11
|
||||
CPU = CK_V11;
|
||||
|
||||
// Temporary approach to make everything at least word-aligned and allow for
|
||||
// safely casting between pointers with different alignment requirements.
|
||||
// TODO: Remove this when there are no more cast align warnings on the
|
||||
// firmware.
|
||||
MinGlobalAlign = 32;
|
||||
}
|
||||
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const override {
|
||||
// Define __lanai__ when building for target lanai.
|
||||
Builder.defineMacro("__lanai__");
|
||||
|
||||
// Set define for the CPU specified.
|
||||
switch (CPU) {
|
||||
case CK_V11:
|
||||
Builder.defineMacro("__LANAI_V11__");
|
||||
break;
|
||||
case CK_NONE:
|
||||
llvm_unreachable("Unhandled target CPU");
|
||||
}
|
||||
}
|
||||
|
||||
bool setCPU(const std::string &Name) override {
|
||||
CPU = llvm::StringSwitch<CPUKind>(Name)
|
||||
.Case("v11", CK_V11)
|
||||
.Default(CK_NONE);
|
||||
|
||||
return CPU != CK_NONE;
|
||||
}
|
||||
|
||||
bool hasFeature(StringRef Feature) const override {
|
||||
return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false);
|
||||
}
|
||||
|
||||
ArrayRef<const char *> getGCCRegNames() const override;
|
||||
|
||||
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
|
||||
|
||||
BuiltinVaListKind getBuiltinVaListKind() const override {
|
||||
return TargetInfo::VoidPtrBuiltinVaList;
|
||||
}
|
||||
|
||||
ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
|
||||
|
||||
bool validateAsmConstraint(const char *&Name,
|
||||
TargetInfo::ConstraintInfo &info) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *getClobbers() const override { return ""; }
|
||||
};
|
||||
|
||||
const char *const LanaiTargetInfo::GCCRegNames[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
|
||||
"r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
|
||||
"r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"};
|
||||
|
||||
ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const {
|
||||
return llvm::makeArrayRef(GCCRegNames);
|
||||
}
|
||||
|
||||
const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = {
|
||||
{{"pc"}, "r2"},
|
||||
{{"sp"}, "r4"},
|
||||
{{"fp"}, "r5"},
|
||||
{{"rv"}, "r8"},
|
||||
{{"rr1"}, "r10"},
|
||||
{{"rr2"}, "r11"},
|
||||
{{"rca"}, "r15"},
|
||||
};
|
||||
|
||||
ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const {
|
||||
return llvm::makeArrayRef(GCCRegAliases);
|
||||
}
|
||||
|
||||
// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit).
|
||||
class SparcTargetInfo : public TargetInfo {
|
||||
static const TargetInfo::GCCRegAlias GCCRegAliases[];
|
||||
|
@ -7672,6 +7777,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
|
|||
case llvm::Triple::hexagon:
|
||||
return new HexagonTargetInfo(Triple);
|
||||
|
||||
case llvm::Triple::lanai:
|
||||
return new LanaiTargetInfo(Triple);
|
||||
|
||||
case llvm::Triple::aarch64:
|
||||
if (Triple.isOSDarwin())
|
||||
return new DarwinAArch64TargetInfo(Triple);
|
||||
|
|
|
@ -6582,6 +6582,78 @@ Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|||
/*AllowHigherAlign*/ true);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Lanai ABI Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class LanaiABIInfo : public DefaultABIInfo {
|
||||
public:
|
||||
LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
|
||||
|
||||
bool shouldUseInReg(QualType Ty, CCState &State) const;
|
||||
|
||||
void computeInfo(CGFunctionInfo &FI) const override {
|
||||
CCState State(FI.getCallingConvention());
|
||||
// Lanai uses 4 registers to pass arguments unless the function has the
|
||||
// regparm attribute set.
|
||||
if (FI.getHasRegParm()) {
|
||||
State.FreeRegs = FI.getRegParm();
|
||||
} else {
|
||||
State.FreeRegs = 4;
|
||||
}
|
||||
|
||||
if (!getCXXABI().classifyReturnType(FI))
|
||||
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
|
||||
for (auto &I : FI.arguments())
|
||||
I.info = classifyArgumentType(I.type, State);
|
||||
}
|
||||
|
||||
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
|
||||
};
|
||||
|
||||
bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const {
|
||||
unsigned Size = getContext().getTypeSize(Ty);
|
||||
unsigned SizeInRegs = llvm::alignTo(Size, 32U) / 32U;
|
||||
|
||||
if (SizeInRegs == 0)
|
||||
return false;
|
||||
|
||||
if (SizeInRegs > State.FreeRegs) {
|
||||
State.FreeRegs = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
State.FreeRegs -= SizeInRegs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty,
|
||||
CCState &State) const {
|
||||
if (isAggregateTypeForABI(Ty))
|
||||
return getNaturalAlignIndirect(Ty);
|
||||
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const auto *EnumTy = Ty->getAs<EnumType>())
|
||||
Ty = EnumTy->getDecl()->getIntegerType();
|
||||
|
||||
if (shouldUseInReg(Ty, State))
|
||||
return ABIArgInfo::getDirectInReg();
|
||||
|
||||
if (Ty->isPromotableIntegerType())
|
||||
return ABIArgInfo::getExtend();
|
||||
|
||||
return ABIArgInfo::getDirect();
|
||||
}
|
||||
|
||||
namespace {
|
||||
class LanaiTargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
public:
|
||||
LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
|
||||
: TargetCodeGenInfo(new LanaiABIInfo(CGT)) {}
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AMDGPU ABI Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -7740,6 +7812,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
|
|||
}
|
||||
case llvm::Triple::hexagon:
|
||||
return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
|
||||
case llvm::Triple::lanai:
|
||||
return *(TheTargetCodeGenInfo = new LanaiTargetCodeGenInfo(Types));
|
||||
case llvm::Triple::r600:
|
||||
return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types));
|
||||
case llvm::Triple::amdgcn:
|
||||
|
|
|
@ -2459,6 +2459,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
|
|||
case llvm::Triple::hexagon:
|
||||
TC = new toolchains::HexagonToolChain(*this, Target, Args);
|
||||
break;
|
||||
case llvm::Triple::lanai:
|
||||
TC = new toolchains::LanaiToolChain(*this, Target, Args);
|
||||
break;
|
||||
case llvm::Triple::xcore:
|
||||
TC = new toolchains::XCoreToolChain(*this, Target, Args);
|
||||
break;
|
||||
|
|
|
@ -874,6 +874,14 @@ private:
|
|||
std::string LibSuffix;
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF {
|
||||
public:
|
||||
LanaiToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||
const llvm::opt::ArgList &Args)
|
||||
: Generic_ELF(D, Triple, Args) {}
|
||||
bool IsIntegratedAssemblerDefault() const override { return true; }
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
|
||||
protected:
|
||||
GCCVersion GCCLibAndIncVersion;
|
||||
|
|
|
@ -1619,6 +1619,13 @@ static std::string getR600TargetGPU(const ArgList &Args) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static std::string getLanaiTargetCPU(const ArgList &Args) {
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
|
||||
return A->getValue();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void Clang::AddSparcTargetArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
const Driver &D = getToolChain().getDriver();
|
||||
|
@ -1836,6 +1843,9 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
|
|||
return "hexagon" +
|
||||
toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
|
||||
|
||||
case llvm::Triple::lanai:
|
||||
return getLanaiTargetCPU(Args);
|
||||
|
||||
case llvm::Triple::systemz:
|
||||
return getSystemZTargetCPU(Args);
|
||||
|
||||
|
@ -2145,6 +2155,29 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
|
|||
CmdArgs.push_back("-machine-sink-split=0");
|
||||
}
|
||||
|
||||
void Clang::AddLanaiTargetArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
|
||||
StringRef CPUName = A->getValue();
|
||||
|
||||
CmdArgs.push_back("-target-cpu");
|
||||
CmdArgs.push_back(Args.MakeArgString(CPUName));
|
||||
}
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
|
||||
StringRef Value = A->getValue();
|
||||
// Only support mregparm=4 to support old usage. Report error for all other
|
||||
// cases.
|
||||
int Mregparm;
|
||||
if (Value.getAsInteger(10, Mregparm)) {
|
||||
if (Mregparm != 4) {
|
||||
getToolChain().getDriver().Diag(
|
||||
diag::err_drv_unsupported_option_argument)
|
||||
<< A->getOption().getName() << Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
// Default to "hidden" visibility.
|
||||
|
@ -4176,6 +4209,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
AddX86TargetArgs(Args, CmdArgs);
|
||||
break;
|
||||
|
||||
case llvm::Triple::lanai:
|
||||
AddLanaiTargetArgs(Args, CmdArgs);
|
||||
break;
|
||||
|
||||
case llvm::Triple::hexagon:
|
||||
AddHexagonTargetArgs(Args, CmdArgs);
|
||||
break;
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
void AddLanaiTargetArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const;
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// RUN: %clang_cc1 -triple lanai-unknown-unknown %s -emit-llvm -o - \
|
||||
// RUN: | FileCheck %s
|
||||
|
||||
// Basic argument/attribute tests for Lanai.
|
||||
|
||||
// CHECK: define void @f0(i32 inreg %i, i32 inreg %j, i64 inreg %k)
|
||||
void f0(int i, long j, long long k) {}
|
||||
|
||||
typedef struct {
|
||||
int aa;
|
||||
int bb;
|
||||
} s1;
|
||||
// CHECK: define void @f1(%struct.s1* byval align 4 %i)
|
||||
void f1(s1 i) {}
|
||||
|
||||
typedef struct {
|
||||
int cc;
|
||||
} s2;
|
||||
// CHECK: define void @f2(%struct.s2* noalias sret %agg.result)
|
||||
s2 f2() {
|
||||
s2 foo;
|
||||
return foo;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int cc;
|
||||
int dd;
|
||||
} s3;
|
||||
// CHECK: define void @f3(%struct.s3* noalias sret %agg.result)
|
||||
s3 f3() {
|
||||
s3 foo;
|
||||
return foo;
|
||||
}
|
||||
|
||||
// CHECK: define void @f4(i64 inreg %i)
|
||||
void f4(long long i) {}
|
||||
|
||||
// CHECK: define void @f5(i8 inreg %a, i16 inreg %b)
|
||||
void f5(char a, short b) {}
|
||||
|
||||
// CHECK: define void @f6(i8 inreg %a, i16 inreg %b)
|
||||
void f6(unsigned char a, unsigned short b) {}
|
||||
|
||||
enum my_enum {
|
||||
ENUM1,
|
||||
ENUM2,
|
||||
ENUM3,
|
||||
};
|
||||
// Enums should be treated as the underlying i32.
|
||||
// CHECK: define void @f7(i32 inreg %a)
|
||||
void f7(enum my_enum a) {}
|
||||
|
||||
enum my_big_enum {
|
||||
ENUM4 = 0xFFFFFFFFFFFFFFFF,
|
||||
};
|
||||
// Big enums should be treated as the underlying i64.
|
||||
// CHECK: define void @f8(i64 inreg %a)
|
||||
void f8(enum my_big_enum a) {}
|
||||
|
||||
union simple_union {
|
||||
int a;
|
||||
char b;
|
||||
};
|
||||
// Unions should be passed as byval structs.
|
||||
// CHECK: define void @f9(%union.simple_union* byval align 4 %s)
|
||||
void f9(union simple_union s) {}
|
||||
|
||||
typedef struct {
|
||||
int b4 : 4;
|
||||
int b3 : 3;
|
||||
int b8 : 8;
|
||||
} bitfield1;
|
||||
// Bitfields should be passed as byval structs.
|
||||
// CHECK: define void @f10(%struct.bitfield1* byval align 4 %bf1)
|
||||
void f10(bitfield1 bf1) {}
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -triple lanai-unknown-unknown -mregparm 4 %s -emit-llvm -o - | FileCheck %s
|
||||
|
||||
void f1(int a, int b, int c, int d,
|
||||
int e, int f, int g, int h);
|
||||
|
||||
void f2(int a, int b) __attribute((regparm(0)));
|
||||
|
||||
void f0() {
|
||||
// CHECK: call void @f1(i32 inreg 1, i32 inreg 2, i32 inreg 3, i32 inreg 4,
|
||||
// CHECK: i32 5, i32 6, i32 7, i32 8)
|
||||
f1(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
// CHECK: call void @f2(i32 1, i32 2)
|
||||
f2(1, 2);
|
||||
}
|
||||
|
||||
// CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32 inreg,
|
||||
// CHECK: i32, i32, i32, i32)
|
||||
// CHECK: declare void @f2(i32, i32)
|
|
@ -86,6 +86,10 @@
|
|||
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY64
|
||||
// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
|
||||
|
||||
// RUN: %clang_cc1 -triple lanai-unknown-unknown -o - -emit-llvm %s | \
|
||||
// RUN: FileCheck %s -check-prefix=LANAI
|
||||
// LANAI: target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64"
|
||||
|
||||
// RUN: %clang_cc1 -triple powerpc-unknown -o - -emit-llvm %s | \
|
||||
// RUN: FileCheck %s -check-prefix=PPC
|
||||
// PPC: target datalayout = "E-m:e-p:32:32-i64:64-n32"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// RUN: %clang -target lanai-unknown-unknown -v 2> %t
|
||||
// RUN: grep 'Target: lanai-unknown-unknown' %t
|
|
@ -0,0 +1,86 @@
|
|||
// RUN: %clang -target lanai-unknown-unknown -### %s -emit-llvm-only -c 2>&1 \
|
||||
// RUN: | FileCheck %s -check-prefix=ECHO
|
||||
// RUN: %clang -target lanai-unknown-unknown %s -emit-llvm -S -o - \
|
||||
// RUN: | FileCheck %s
|
||||
|
||||
// ECHO: {{.*}} "-cc1" {{.*}}lanai-unknown-unknown.c
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
|
||||
extern "C" {
|
||||
|
||||
// CHECK: @align_c = global i32 1
|
||||
int align_c = __alignof(char);
|
||||
|
||||
// CHECK: @align_s = global i32 2
|
||||
int align_s = __alignof(short);
|
||||
|
||||
// CHECK: @align_i = global i32 4
|
||||
int align_i = __alignof(int);
|
||||
|
||||
// CHECK: @align_l = global i32 4
|
||||
int align_l = __alignof(long);
|
||||
|
||||
// CHECK: @align_ll = global i32 8
|
||||
int align_ll = __alignof(long long);
|
||||
|
||||
// CHECK: @align_p = global i32 4
|
||||
int align_p = __alignof(void*);
|
||||
|
||||
// CHECK: @align_vl = global i32 4
|
||||
int align_vl = __alignof(va_list);
|
||||
|
||||
// Check types
|
||||
|
||||
// CHECK: signext i8 @check_char()
|
||||
char check_char() { return 0; }
|
||||
|
||||
// CHECK: signext i16 @check_short()
|
||||
short check_short() { return 0; }
|
||||
|
||||
// CHECK: i32 @check_int()
|
||||
int check_int() { return 0; }
|
||||
|
||||
// CHECK: i32 @check_long()
|
||||
long check_long() { return 0; }
|
||||
|
||||
// CHECK: i64 @check_longlong()
|
||||
long long check_longlong() { return 0; }
|
||||
|
||||
// CHECK: zeroext i8 @check_uchar()
|
||||
unsigned char check_uchar() { return 0; }
|
||||
|
||||
// CHECK: zeroext i16 @check_ushort()
|
||||
unsigned short check_ushort() { return 0; }
|
||||
|
||||
// CHECK: i32 @check_uint()
|
||||
unsigned int check_uint() { return 0; }
|
||||
|
||||
// CHECK: i32 @check_ulong()
|
||||
unsigned long check_ulong() { return 0; }
|
||||
|
||||
// CHECK: i64 @check_ulonglong()
|
||||
unsigned long long check_ulonglong() { return 0; }
|
||||
|
||||
// CHECK: i32 @check_size_t()
|
||||
size_t check_size_t() { return 0; }
|
||||
|
||||
}
|
||||
|
||||
template<int> void Switch();
|
||||
template<> void Switch<4>();
|
||||
template<> void Switch<8>();
|
||||
template<> void Switch<16>();
|
||||
|
||||
void check_pointer_size() {
|
||||
// CHECK: SwitchILi4
|
||||
Switch<sizeof(void*)>();
|
||||
|
||||
// CHECK: SwitchILi8
|
||||
Switch<sizeof(long long)>();
|
||||
|
||||
// CHECK: SwitchILi4
|
||||
Switch<sizeof(va_list)>();
|
||||
}
|
|
@ -8414,6 +8414,9 @@
|
|||
// RUN: %clang_cc1 -triple arm-linux-androideabi -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix ANDROID %s
|
||||
// ANDROID:#define __ANDROID__ 1
|
||||
//
|
||||
// RUN: %clang_cc1 -triple lanai-unknown-unknown -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix LANAI %s
|
||||
// LANAI: #define __lanai__ 1
|
||||
//
|
||||
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-freebsd < /dev/null | FileCheck -match-full-lines -check-prefix PPC64-FREEBSD %s
|
||||
// PPC64-FREEBSD-NOT: #define __LONG_DOUBLE_128__ 1
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue