LANGOPT(ArmSveVectorBits, 32, 0, "SVE vector size in bits")
+ENUM_LANGOPT(ExtendIntArgs, ExtendArgsKind, 1, ExtendArgsKind::ExtendTo32,
+ "Controls how scalar integer arguments are extended in calls "
+ "to unprototyped and varargs functions")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
Single
};
+ enum class ExtendArgsKind {
+ /// Integer arguments are sign or zero extended to 32/64 bits
+ /// during default argument promotions.
+ ExtendTo32,
+ ExtendTo64
+ };
+
public:
/// The used language standard.
LangStandard::Kind LangStd;
bool isBigEndian() const { return BigEndian; }
bool isLittleEndian() const { return !BigEndian; }
+ /// Whether the option -fextend-arguments={32,64} is supported on the target.
+ virtual bool supportsExtendIntArgs() const { return false; }
+
/// Gets the default calling convention for the given target and
/// declaration context.
virtual CallingConv getDefaultCallingConv() const {
PosFlag<SetTrue, [CC1Option], "Require math functions to indicate errors by setting errno">,
NegFlag<SetFalse>>,
ShouldParseIf<!strconcat("!", open_cl.KeyPath)>;
+def fextend_args_EQ : Joined<["-"], "fextend-arguments=">, Group<f_Group>,
+ Flags<[CC1Option, NoArgumentUnused]>,
+ HelpText<"Controls how scalar integer arguments are extended in calls "
+ "to unprototyped and varargs functions">,
+ Values<"32,64">,
+ NormalizedValues<["ExtendTo32", "ExtendTo64"]>,
+ NormalizedValuesScope<"LangOptions::ExtendArgsKind">,
+ MarshallingInfoEnum<LangOpts<"ExtendIntArgs">,"ExtendTo32">;
def fbracket_depth_EQ : Joined<["-"], "fbracket-depth=">, Group<f_Group>, Flags<[CoreOption]>;
def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>;
def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
bool setFPMath(StringRef Name) override;
+ bool supportsExtendIntArgs() const override {
+ return getTriple().getArch() != llvm::Triple::x86;
+ }
+
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
// Most of the non-ARM calling conventions are i386 conventions.
switch (CC) {
RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs, JA);
+ if (Arg *A = Args.getLastArg(options::OPT_fextend_args_EQ)) {
+ const llvm::Triple::ArchType Arch = TC.getArch();
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ StringRef V = A->getValue();
+ if (V == "64")
+ CmdArgs.push_back("-fextend-arguments=64");
+ else if (V != "32")
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << A->getValue() << A->getOption().getName();
+ } else
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getOption().getName() << TripleStr;
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_mdouble_EQ)) {
if (TC.getArch() == llvm::Triple::avr)
A->render(Args, CmdArgs);
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get();
}
}
+ if (BTy &&
+ getLangOpts().getExtendIntArgs() ==
+ LangOptions::ExtendArgsKind::ExtendTo64 &&
+ Context.getTargetInfo().supportsExtendIntArgs() && Ty->isIntegerType() &&
+ Context.getTypeSizeInChars(BTy) <
+ Context.getTypeSizeInChars(Context.LongLongTy)) {
+ E = (Ty->isUnsignedIntegerType())
+ ? ImpCastExprToType(E, Context.UnsignedLongLongTy, CK_IntegralCast)
+ .get()
+ : ImpCastExprToType(E, Context.LongLongTy, CK_IntegralCast).get();
+ assert(8 == Context.getTypeSizeInChars(Context.LongLongTy).getQuantity() &&
+ "Unexpected typesize for LongLongTy");
+ }
// C++ performs lvalue-to-rvalue conversion as a default argument
// promotion, even on class types, but note:
--- /dev/null
+// RUN: %clang_cc1 -DD128 -triple x86_64-apple-darwin -fextend-arguments=64 \
+// RUN: %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECKEXT
+
+// When the option isn't selected, no effect
+// RUN: %clang_cc1 -DD128 -triple x86_64-apple-darwin \
+// RUN: %s -emit-llvm -o - | FileCheck %s \
+// RUN: --implicit-check-not "ext {{.*}}to i64"
+
+// The option isn't supported on x86, no effect
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fextend-arguments=64 \
+// RUN: %s -emit-llvm -o - | FileCheck %s \
+// RUN: --implicit-check-not "ext {{.*}}to i64"
+
+// The option isn't supported on ppc, no effect
+// RUN: %clang_cc1 -triple ppc64le -fextend-arguments=64 \
+// RUN: %s -emit-llvm -o - | FileCheck %s \
+// RUN: --implicit-check-not "ext {{.*}}to i64"
+
+int vararg(int, ...);
+void knr();
+
+unsigned int u32;
+int s32;
+unsigned short u16;
+short s16;
+unsigned char u8;
+signed char s8;
+long long ll;
+_ExtInt(23) ei23;
+float ff;
+double dd;
+#ifdef D128
+__int128 i128;
+#endif
+
+int test() {
+ // CHECK: define{{.*}} i32 @test{{.*}}
+
+ // CHECKEXT: [[TAG_u32:%.*]] = load i32, i32* @u32{{.*}}
+ // CHECKEXT: [[CONV_u32:%.*]] = zext i32 [[TAG_u32]] to i64
+
+ // CHECKEXT: [[TAG_s32:%.*]] = load i32, i32* @s32
+ // CHECKEXT: [[CONV_s32:%.*]] = sext i32 [[TAG_s32]] to i64
+
+ // CHECKEXT: [[TAG_u16:%.*]] = load i16, i16* @u16
+ // CHECKEXT: [[CONV_u16:%.*]] = zext i16 [[TAG_u16]] to i64
+
+ // CHECKEXT: [[TAG_s16:%.*]] = load i16, i16* @s16
+ // CHECKEXT: [[CONV_s16:%.*]] = sext i16 [[TAG_s16]] to i64
+
+ // CHECKEXT: [[TAG_u8:%.*]] = load i8, i8* @u8
+ // CHECKEXT: [[CONV_u8:%.*]] = zext i8 [[TAG_u8]] to i64
+
+ // CHECKEXT: [[TAG_s8:%.*]] = load i8, i8* @s8
+ // CHECKEXT: [[CONV_s8:%.*]] = sext i8 [[TAG_s8]] to i64
+ // CHECKEXT: call{{.*}} @vararg(i32 %0, i64 [[CONV_u32]], i64 [[CONV_s32]], i64 [[CONV_u16]], i64 [[CONV_s16]], i64 [[CONV_u8]], i64 [[CONV_s8]]
+
+ int sum = 0;
+ sum = vararg(sum, u32, s32, u16, s16, u8, s8);
+ knr(ll);
+ // CHECKEXT: load i64, i64* @ll
+ // CHECKEXT-NEXT: call void (i64, ...) bitcast {{.*}} @knr
+
+ knr(ei23);
+ // CHECKEXT: load i23, i23* @ei23
+ // CHECKEXT-NEXT: call void (i23, ...) bitcast{{.*}} @knr
+
+ knr(ff);
+ // CHECKEXT: load float
+ // CHECKEXT-NEXT: fpext float {{.*}} to double
+ // CHECKEXT-NEXT: call{{.*}} void (double, ...) bitcast{{.*}} @knr
+
+ knr(dd);
+ // CHECKEXT: load double
+ // CHECKEXT-NEXT: call{{.*}} void (double, ...) bitcast{{.*}} @knr
+
+#ifdef D128
+ knr(i128);
+ // CHECKEXT: load i128
+ // CHECKEXT: call{{.*}} void (i64, i64, ...) bitcast{{.*}} @knr
+#endif
+
+ knr(u32, s32, u16, s16, u8, s8);
+ // CHECKEXT: [[TAg_u32:%.*]] = load i32, i32* @u32{{.*}}
+ // CHECKEXT: [[CONv_u32:%.*]] = zext i32 [[TAg_u32]] to i64
+
+ // CHECKEXT: [[TAg_s32:%.*]] = load i32, i32* @s32
+ // CHECKEXT: [[CONv_s32:%.*]] = sext i32 [[TAg_s32]] to i64
+
+ // CHECKEXT: [[TAg_u16:%.*]] = load i16, i16* @u16
+ // CHECKEXT: [[CONv_u16:%.*]] = zext i16 [[TAg_u16]] to i64
+
+ // CHECKEXT: [[TAg_s16:%.*]] = load i16, i16* @s16
+ // CHECKEXT: [[CONv_s16:%.*]] = sext i16 [[TAg_s16]] to i64
+
+ // CHECKEXT: [[TAg_u8:%.*]] = load i8, i8* @u8
+ // CHECKEXT: [[CONv_u8:%.*]] = zext i8 [[TAg_u8]] to i64
+
+ // CHECKEXT: [[TAg_s8:%.*]] = load i8, i8* @s8
+ // CHECKEXT: [[CONv_s8:%.*]] = sext i8 [[TAg_s8]] to i64
+ // CHECKEXT: call{{.*}} void (i64, i64, i64, i64, i64, i64, ...) bitcast{{.*}} @knr
+ return sum;
+}
--- /dev/null
+// Options for intel arch
+// RUN: %clang -### -target x86_64-apple-darwin -fextend-arguments=32 %s 2>&1 \
+// RUN: | FileCheck --implicit-check-not "-fextend-arguments=32" %s
+// RUN: %clang -### -target x86_64-apple-darwin -fextend-arguments=64 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-64 %s
+
+// Unsupported target
+// RUN: not %clang -target aarch64-unknown-windows-msvc -fextend-arguments=32 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=UNSUPPORTED-TARGET %s
+
+// Invalid option value
+// RUN: not %clang -target x86_64-apple-darwin -fextend-arguments=0 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=INVALID-VALUE %s
+
+// CHECK-64: "-cc1" {{.*}}"-fextend-arguments=64"
+// UNSUPPORTED-TARGET: error: unsupported option
+// INVALID-VALUE: error: invalid argument '0' to -fextend-arguments