Index: clang/lib/Basic/CMakeLists.txt =================================================================== --- clang/lib/Basic/CMakeLists.txt +++ clang/lib/Basic/CMakeLists.txt @@ -70,6 +70,7 @@ Targets.cpp Targets/AArch64.cpp Targets/AMDGPU.cpp + Targets/ARC.cpp Targets/ARM.cpp Targets/AVR.cpp Targets/BPF.cpp Index: clang/lib/Basic/Targets.cpp =================================================================== --- clang/lib/Basic/Targets.cpp +++ clang/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" @@ -123,6 +124,9 @@ default: return nullptr; + case llvm::Triple::arc: + return new ARCTargetInfo(Triple, Opts); + case llvm::Triple::xcore: return new XCoreTargetInfo(Triple, Opts); Index: clang/lib/Basic/Targets/ARC.h =================================================================== --- /dev/null +++ clang/lib/Basic/Targets/ARC.h @@ -0,0 +1,76 @@ +//===--- 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 { + static const Builtin::Info BuiltinInfo[]; + +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: clang/lib/Basic/Targets/ARC.cpp =================================================================== --- /dev/null +++ clang/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: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -8115,6 +8115,109 @@ return false; } +// ARC ABI implementation. +namespace { + +class ARCABIInfo : public DefaultABIInfo { +public: + ARCABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + +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()) + State.FreeRegs--; + else { + 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 getIndirect(QualType Ty) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; +}; + +class ARCTargetCodeGenInfo : public TargetCodeGenInfo { +public: + ARCTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new ARCABIInfo(CGT)) {} +}; + +ABIArgInfo ARCABIInfo::getIndirect(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, + unsigned FreeRegs) const { + // TODO: C++ ABI? + unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + if (isAggregateTypeForABI(Ty)) { + const RecordType *RT = Ty->getAs(); + // Structures with flexible arrays are always indirect. + if (RT && RT->getDecl()->hasFlexibleArrayMember()) + return getIndirect(Ty); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + llvm::LLVMContext &LLVMContext = getVMContext(); + if (FreeRegs > 0) { + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + SmallVector Elements(SizeInRegs, Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + return ABIArgInfo::getDirect(Result); + } + return getIndirect(Ty); + } + + return DefaultABIInfo::classifyArgumentType(Ty); +} + +ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getDirect(); + // Arguments of size > 4 registers are indirect. + unsigned RetSize = (getContext().getTypeSize(RetTy) + 31) / 32; + if (RetSize > 4) + return getIndirect(RetTy); + return DefaultABIInfo::classifyReturnType(RetTy); +} + +} // namespace //===----------------------------------------------------------------------===// // XCore ABI Implementation @@ -9115,6 +9218,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: clang/test/CodeGen/arc-arguments.c =================================================================== --- /dev/null +++ clang/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 %i, i32 %j, i64 %k) +void f0(int i, long j, long long k) {} + +typedef struct { + int aa; + int bb; +} s1; +// CHECK: define void @f1(i32 %i.coerce0, i32 %i.coerce1) +void f1(s1 i) {} + +typedef struct { + char aa; char bb; char cc; char dd; +} cs1; +// CHECK: define void @cf1(i32 %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 %i) +void f4(long long i) {} + +// CHECK: define void @f5(i8 signext %a, i16 signext %b) +void f5(signed char a, short b) {} + +// CHECK: define void @f6(i8 zeroext %a, i16 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 %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 %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 %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 %bf1.coerce) +void f10(bitfield1 bf1) {} + +// CHECK: define { float, float } @cplx1(float %r) +_Complex float cplx1(float r) { + return r + 2.0fi; +} + +// CHECK: define { double, double } @cplx2(double %r) +_Complex double cplx2(double r) { + return r + 2.0i; +} + +// CHECK: define { i32, i32 } @cplx3(i32 %r) +_Complex int cplx3(int r) { + return r + 2i; +} + +// CHECK: define { i64, i64 } @cplx4(i64 %r) +_Complex long long cplx4(long long r) { + return r + 2i; +} + +// CHECK: define { i8, i8 } @cplx6(i8 signext %r) +_Complex signed char cplx6(signed char r) { + return r + 2i; +} + +// CHECK: define { i16, i16 } @cplx7(i16 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 %a.coerce0, i32 %a.coerce1, i32 %a.coerce2, i32 %a.coerce3, i32 %b.coerce0, i32 %b.coerce1, i32 %b.coerce2, i32 %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 %a.coerce0, i32 %a.coerce1, i32 %a.coerce2, i32 %a.coerce3, i32 %b.coerce0, i32 %b.coerce1, i32 %b.coerce2, i32 %b.coerce3, %struct.s16* byval align 4 %c) + +// 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 %x, i32 %a.coerce0, i32 %a.coerce1, i32 %b.coerce0, i32 %b.coerce1, i32 %b.coerce2, i32 %b.coerce3, %struct.s16* byval align 4 %c) + +// 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 %a.coerce0, i32 %a.coerce1, i32 %b.coerce0, i32 %b.coerce1, i32 %b.coerce2, i32 %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) Index: clang/test/CodeGen/arc-struct-align.c =================================================================== --- /dev/null +++ clang/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: clang/test/CodeGen/target-data.c =================================================================== --- clang/test/CodeGen/target-data.c +++ clang/test/CodeGen/target-data.c @@ -159,6 +159,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"