diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2469,20 +2469,32 @@ unsigned Output = Info.getTiedOperand(); QualType OutputType = S.getOutputExpr(Output)->getType(); QualType InputTy = InputExpr->getType(); + uint64_t OutputSize = getContext().getTypeSize(OutputType); + uint64_t InputSize = getContext().getTypeSize(InputTy); - if (getContext().getTypeSize(OutputType) > - getContext().getTypeSize(InputTy)) { + if (OutputSize > InputSize) { // Use ptrtoint as appropriate so that we can do our extension. if (isa(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, IntPtrTy); + if (isa(Arg->getType())) { + llvm::IntegerType *IntTy = + llvm::IntegerType::get(getLLVMContext(), InputSize); + Arg = Builder.CreateBitCast(Arg, IntTy); + } llvm::Type *OutputTy = ConvertType(OutputType); if (isa(OutputTy)) Arg = Builder.CreateZExt(Arg, OutputTy); else if (isa(OutputTy)) Arg = Builder.CreateZExt(Arg, IntPtrTy); - else { - assert(OutputTy->isFloatingPointTy() && "Unexpected output type"); + else if (OutputTy->isFloatingPointTy()) Arg = Builder.CreateFPExt(Arg, OutputTy); + else { + assert(OutputTy->isStructTy() && OutputSize != 128 && + "Unexpected output type"); + llvm::IntegerType *IntTy = + llvm::IntegerType::get(getLLVMContext(), OutputSize); + Arg = Builder.CreateZExt(Arg, IntTy); + Arg = Builder.CreateBitCast(Arg, OutputTy); } } // Deal with the tied operands' constraint code in adjustInlineAsmType. diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -617,14 +617,33 @@ AD_Int, AD_FP, AD_Other } InputDomain, OutputDomain; - if (InTy->isIntegerType() || InTy->isPointerType()) + auto IsPower2Structure = [this](QualType Ty) { + if (!Ty->isStructureType()) + return false; + + switch (Context.getTypeSize(Ty)) { + default: + return false; + case 8: + case 16: + case 32: + case 64: + // TODO: The maximum size GCC supports is 128 bits. + // We may need to extract the first element in this case. + return true; + } + }; + + if (InTy->isIntegerType() || InTy->isPointerType() || + IsPower2Structure(InTy)) InputDomain = AD_Int; else if (InTy->isRealFloatingType()) InputDomain = AD_FP; else InputDomain = AD_Other; - if (OutTy->isIntegerType() || OutTy->isPointerType()) + if (OutTy->isIntegerType() || OutTy->isPointerType() || + IsPower2Structure(OutTy)) OutputDomain = AD_Int; else if (OutTy->isRealFloatingType()) OutputDomain = AD_FP; @@ -666,7 +685,8 @@ // output was a register, just extend the shorter one to the size of the // larger one. if (!SmallerValueMentioned && InputDomain != AD_Other && - OutputConstraintInfos[TiedTo].allowsRegister()) + OutputConstraintInfos[TiedTo].allowsRegister() && + OutputDomain != AD_Other) continue; // Either both of the operands were mentioned or the smaller one was diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -313,3 +313,51 @@ asm ("jne %l0":::); asm goto ("jne %l0"::::lab); } + +typedef struct test19_a { + int a; + char b; +} test19_a; + +typedef struct test19_b { + int a; + int b; + int c; +} test19_b; + +typedef struct test19_c { + char a; + char b; +} test19_c; + +typedef struct test19_d { + char a; + char b; + char c; + char d; +} test19_d; + +typedef struct test19_e { + int a; + int b; + int c; + int d; +} test19_e; + +void test19(long long x) +{ + test19_a a; + test19_b b; + test19_c c; + test19_d d; + test19_e e; + asm ("" : "=rm" (a): "0" (1)); // no-error + asm ("" : "=rm" (d): "0" (1)); // no-error + asm ("" : "=rm" (c): "0" (x)); // no-error + asm ("" : "=rm" (x): "0" (a)); // no-error + asm ("" : "=rm" (a): "0" (d)); // no-error + asm ("" : "=rm" (b): "0" (1)); // expected-error {{unsupported inline asm: input with type 'int' matching output with type 'test19_b' (aka 'struct test19_b')}} + // FIXME: The below 2 cases should be no error. + asm ("" : "=rm" (e): "0" (1)); // expected-error {{unsupported inline asm: input with type 'int' matching output with type 'test19_e' (aka 'struct test19_e')}} + asm ("" : "=rm" (x): "0" (e)); // expected-error {{unsupported inline asm: input with type 'test19_e' (aka 'struct test19_e') matching output with type 'long long'}} +}