Index: lib/Basic/CMakeLists.txt =================================================================== --- lib/Basic/CMakeLists.txt +++ lib/Basic/CMakeLists.txt @@ -71,6 +71,7 @@ Targets.cpp Targets/AArch64.cpp Targets/AMDGPU.cpp + Targets/ARC.cpp Targets/ARM.cpp Targets/AVR.cpp Targets/BPF.cpp Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -16,6 +16,7 @@ #include "Targets/AArch64.h" #include "Targets/AMDGPU.h" +#include "Targets/ARC.h" #include "Targets/ARM.h" #include "Targets/AVR.h" #include "Targets/BPF.h" @@ -124,6 +125,9 @@ default: return nullptr; + case llvm::Triple::arc: + return new ARCTargetInfo(Triple, Opts); + case llvm::Triple::xcore: return new XCoreTargetInfo(Triple, Opts); Index: lib/Basic/Targets/ARC.h =================================================================== --- lib/Basic/Targets/ARC.h +++ lib/Basic/Targets/ARC.h @@ -0,0 +1,74 @@ +//===--- ARC.h - Declare ARC target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { +public: + ARCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-" + "i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef getGCCRegNames() const override { + static const char *const 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", "gp", "sp", "fp", "ilink1", "r30", "blink"}; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H Index: lib/Basic/Targets/ARC.cpp =================================================================== --- lib/Basic/Targets/ARC.cpp +++ lib/Basic/Targets/ARC.cpp @@ -0,0 +1,25 @@ +//===--- ARC.cpp - Implement ARC target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +void ARCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__arc__"); +} Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -8249,6 +8249,137 @@ return false; } +// ARC ABI implementation. +namespace { + +class ARCABIInfo : public DefaultABIInfo { +public: + using DefaultABIInfo::DefaultABIInfo; + +private: + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; + + void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { + if (!State.FreeRegs) + return; + if (Info.isIndirect() && Info.getInReg()) + State.FreeRegs--; + else if (Info.isDirect() && Info.getInReg()) { + unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; + if (sz < State.FreeRegs) + State.FreeRegs -= sz; + else + State.FreeRegs = 0; + } + } + + void computeInfo(CGFunctionInfo &FI) const override { + CCState State(FI.getCallingConvention()); + // ARC uses 8 registers to pass arguments. + State.FreeRegs = 8; + + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + updateState(FI.getReturnInfo(), FI.getReturnType(), State); + for (auto &I : FI.arguments()) { + I.info = classifyArgumentType(I.type, State.FreeRegs); + updateState(I.info, I.type, State); + } + } + + ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; + ABIArgInfo getIndirectByValue(QualType Ty) const; + ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; +}; + +class ARCTargetCodeGenInfo : public TargetCodeGenInfo { +public: + ARCTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new ARCABIInfo(CGT)) {} +}; + + +ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { + return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : + getNaturalAlignIndirect(Ty, false); +} + +ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { + // Compute the byval alignment. + const unsigned MinABIStackAlignInBytes = 4; + unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; + return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, + TypeAlign > MinABIStackAlignInBytes); +} + +Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, + getContext().getTypeInfoInChars(Ty), + CharUnits::fromQuantity(4), true); +} + +ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, + uint8_t FreeRegs) const { + // Handle the generic C++ ABI. + const RecordType *RT = Ty->getAs(); + if (RT) { + CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); + if (RAA == CGCXXABI::RAA_Indirect) + return getIndirectByRef(Ty, FreeRegs > 0); + + if (RAA == CGCXXABI::RAA_DirectInMemory) + return getIndirectByValue(Ty); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; + + if (isAggregateTypeForABI(Ty)) { + // Structures with flexible arrays are always indirect. + if (RT && RT->getDecl()->hasFlexibleArrayMember()) + return getIndirectByValue(Ty); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + llvm::LLVMContext &LLVMContext = getVMContext(); + + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + SmallVector Elements(SizeInRegs, Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + + return FreeRegs >= SizeInRegs ? + ABIArgInfo::getDirectInReg(Result) : + ABIArgInfo::getDirect(Result, 0, nullptr, false); + } + + return Ty->isPromotableIntegerType() ? + (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) : + ABIArgInfo::getExtend(Ty)) : + (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() : + ABIArgInfo::getDirect()); +} + +ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getDirectInReg(); + + // Arguments of size > 4 registers are indirect. + auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; + if (RetSize > 4) + return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); + + return DefaultABIInfo::classifyReturnType(RetTy); +} + +} // End anonymous namespace. //===----------------------------------------------------------------------===// // XCore ABI Implementation @@ -9270,6 +9401,8 @@ return SetCGInfo(new SparcV9TargetCodeGenInfo(Types)); case llvm::Triple::xcore: return SetCGInfo(new XCoreTargetCodeGenInfo(Types)); + case llvm::Triple::arc: + return SetCGInfo(new ARCTargetCodeGenInfo(Types)); case llvm::Triple::spir: case llvm::Triple::spir64: return SetCGInfo(new SPIRTargetCodeGenInfo(Types)); Index: test/CodeGen/arc/arguments.c =================================================================== --- test/CodeGen/arc/arguments.c +++ test/CodeGen/arc/arguments.c @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -triple arc-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s + +// Basic argument tests for ARC. + +// 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(i32 inreg %i.coerce0, i32 inreg %i.coerce1) +void f1(s1 i) {} + +typedef struct { + char aa; char bb; char cc; char dd; +} cs1; +// CHECK: define void @cf1(i32 inreg %i.coerce) +void cf1(cs1 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 signext %a, i16 inreg signext %b) +void f5(signed char a, short b) {} + +// CHECK: define void @f6(i8 inreg zeroext %a, i16 inreg zeroext %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 inreg. +// CHECK: define void @f9(i32 inreg %s.coerce) +void f9(union simple_union s) {} + +typedef struct { + int b4 : 4; + int b3 : 3; + int b8 : 8; +} bitfield1; +// Bitfields should be passed inreg. +// CHECK: define void @f10(i32 inreg %bf1.coerce) +void f10(bitfield1 bf1) {} + +// CHECK: define inreg { float, float } @cplx1(float inreg %r) +_Complex float cplx1(float r) { + return r + 2.0fi; +} + +// CHECK: define inreg { double, double } @cplx2(double inreg %r) +_Complex double cplx2(double r) { + return r + 2.0i; +} + +// CHECK: define inreg { i32, i32 } @cplx3(i32 inreg %r) +_Complex int cplx3(int r) { + return r + 2i; +} + +// CHECK: define inreg { i64, i64 } @cplx4(i64 inreg %r) +_Complex long long cplx4(long long r) { + return r + 2i; +} + +// CHECK: define inreg { i8, i8 } @cplx6(i8 inreg signext %r) +_Complex signed char cplx6(signed char r) { + return r + 2i; +} + +// CHECK: define inreg { i16, i16 } @cplx7(i16 inreg signext %r) +_Complex short cplx7(short r) { + return r + 2i; +} + +typedef struct { + int aa; int bb; +} s8; + +typedef struct { + int aa; int bb; int cc; int dd; +} s16; + +// Use 16-byte struct 2 times, gets 8 registers. +void st2(s16 a, s16 b) {} +// CHECK: define void @st2(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3) + +// Use 8-byte struct 3 times, gets 8 registers, 1 byval struct argument. +void st3(s16 a, s16 b, s16 c) {} +// CHECK: define void @st3(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) + +// 1 sret + 1 i32 + 2*(i32 coerce) + 4*(i32 coerce) + 1 byval +s16 st4(int x, s8 a, s16 b, s16 c) { return b; } +// CHECK: define void @st4(%struct.s16* noalias sret %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) + +// 1 sret + 2*(i32 coerce) + 4*(i32 coerce) + 4*(i32 coerce) +s16 st5(s8 a, s16 b, s16 c) { return b; } +// CHECK: define void @st5(%struct.s16* noalias sret %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) Index: test/CodeGen/arc/struct-align.c =================================================================== --- test/CodeGen/arc/struct-align.c +++ test/CodeGen/arc/struct-align.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple arc-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s + +// 64-bit fields need only be 32-bit aligned for arc. + +typedef struct { + int aa; + double bb; +} s1; + +// CHECK: define i32 @f1 +// CHECK: ret i32 12 +int f1() { + return sizeof(s1); +} + +typedef struct { + int aa; + long long bb; +} s2; +// CHECK: define i32 @f2 +// CHECK: ret i32 12 +int f2() { + return sizeof(s2); +} + Index: test/CodeGen/target-data.c =================================================================== --- test/CodeGen/target-data.c +++ test/CodeGen/target-data.c @@ -179,6 +179,10 @@ // RUN: %s | FileCheck %s -check-prefix=ARM-GNU // ARM-GNU: target datalayout = "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" +// RUN: %clang_cc1 -triple arc-unknown-unknown -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=ARC +// ARC: target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32" + // RUN: %clang_cc1 -triple hexagon-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=HEXAGON // HEXAGON: target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"