Hi Reid, The test is triggering errors on our build, can you restrict it somewhere?
error: MS-style inline assembly is not available: No available targets are compatible with this triple, see -version for the available targets. http://lab.llvm.org:8011/builders/clang-native-arm-cortex-a15/builds/2461/steps/check-all/logs/Clang%3A%3Ams-inline-asm-return.cpp cheers, --renato On 4 September 2014 21:04, Reid Kleckner <[email protected]> wrote: > Author: rnk > Date: Thu Sep 4 15:04:38 2014 > New Revision: 217187 > > URL: http://llvm.org/viewvc/llvm-project?rev=217187&view=rev > Log: > MS inline asm: Allow __asm blocks to set a return value > > If control falls off the end of a function after an __asm block, MSVC > assumes that the inline assembly filled the EAX and possibly EDX > registers with an appropriate return value. This functionality is used > in inline functions returning 64-bit integers in system headers, so we > need some amount of compatibility. > > This is implemented in Clang by adding extra output constraints to every > inline asm block, and storing the resulting output registers into the > return value slot. If we see an asm block somewhere in the function > body, we emit a normal epilogue instead of marking the end of the > function with a return type unreachable. > > Normal returns in functions not using this functionality will overwrite > the return value slot, and in most cases LLVM should be able to > eliminate the dead stores. > > Fixes PR17201. > > Reviewed By: majnemer > > Differential Revision: http://reviews.llvm.org/D5177 > > Added: > cfe/trunk/test/CodeGenCXX/ms-inline-asm-return.cpp > Modified: > cfe/trunk/lib/CodeGen/CGStmt.cpp > cfe/trunk/lib/CodeGen/CodeGenFunction.cpp > cfe/trunk/lib/CodeGen/CodeGenFunction.h > cfe/trunk/lib/CodeGen/TargetInfo.cpp > cfe/trunk/lib/CodeGen/TargetInfo.h > cfe/trunk/test/CodeGen/ms-inline-asm.c > > Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGStmt.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu Sep 4 15:04:38 2014 > @@ -1901,7 +1901,19 @@ void CodeGenFunction::EmitAsmStmt(const > } > } > > - unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs(); > + // If this is a Microsoft-style asm blob, store the return registers > (EAX:EDX) > + // to the return value slot. Only do this when returning in registers. > + if (isa<MSAsmStmt>(&S)) { > + const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo(); > + if (RetAI.isDirect() || RetAI.isExtend()) { > + // Make a fake lvalue for the return value slot. > + LValue ReturnSlot = MakeAddrLValue(ReturnValue, FnRetTy); > + CGM.getTargetCodeGenInfo().addReturnRegisterOutputs( > + *this, ReturnSlot, Constraints, ResultRegTypes, > ResultTruncRegTypes, > + ResultRegDests, AsmString, S.getNumOutputs()); > + SawAsmBlock = true; > + } > + } > > for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { > const Expr *InputExpr = S.getInputExpr(i); > @@ -1974,9 +1986,9 @@ void CodeGenFunction::EmitAsmStmt(const > StringRef Clobber = S.getClobber(i); > > if (Clobber != "memory" && Clobber != "cc") > - Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); > + Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); > > - if (i != 0 || NumConstraints != 0) > + if (!Constraints.empty()) > Constraints += ','; > > Constraints += "~{"; > @@ -2035,6 +2047,9 @@ void CodeGenFunction::EmitAsmStmt(const > } > } > > + assert(RegResults.size() == ResultRegTypes.size()); > + assert(RegResults.size() == ResultTruncRegTypes.size()); > + assert(RegResults.size() == ResultRegDests.size()); > for (unsigned i = 0, e = RegResults.size(); i != e; ++i) { > llvm::Value *Tmp = RegResults[i]; > > > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Sep 4 15:04:38 2014 > @@ -39,7 +39,7 @@ CodeGenFunction::CodeGenFunction(CodeGen > CGBuilderInserterTy(this)), > CapturedStmtInfo(nullptr), SanOpts(&CGM.getLangOpts().Sanitize), > IsSanitizerScope(false), CurFuncIsThunk(false), > AutoreleaseResult(false), > - BlockInfo(nullptr), BlockPointer(nullptr), > + SawAsmBlock(false), BlockInfo(nullptr), BlockPointer(nullptr), > LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), > NextCleanupDestIndex(1), FirstBlockInfo(nullptr), > EHResumeBlock(nullptr), > ExceptionSlot(nullptr), EHSelectorSlot(nullptr), > @@ -878,7 +878,7 @@ void CodeGenFunction::GenerateCode(Globa > // C11 6.9.1p12: > // If the '}' that terminates a function is reached, and the value of the > // function call is used by the caller, the behavior is undefined. > - if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && > + if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && > !SawAsmBlock && > !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) { > if (SanOpts->Return) { > SanitizerScope SanScope(this); > > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Sep 4 15:04:38 2014 > @@ -265,6 +265,10 @@ public: > /// In ARC, whether we should autorelease the return value. > bool AutoreleaseResult; > > + /// Whether we processed a Microsoft-style asm block during CodeGen. These > can > + /// potentially set the return value. > + bool SawAsmBlock; > + > const CodeGen::CGBlockInfo *BlockInfo; > llvm::Value *BlockPointer; > > > Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) > +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Thu Sep 4 15:04:38 2014 > @@ -15,6 +15,7 @@ > #include "TargetInfo.h" > #include "ABIInfo.h" > #include "CGCXXABI.h" > +#include "CGValue.h" > #include "CodeGenFunction.h" > #include "clang/AST/RecordLayout.h" > #include "clang/CodeGen/CGFunctionInfo.h" > @@ -593,6 +594,14 @@ public: > return X86AdjustInlineAsmType(CGF, Constraint, Ty); > } > > + void addReturnRegisterOutputs(CodeGenFunction &CGF, LValue ReturnValue, > + std::string &Constraints, > + std::vector<llvm::Type *> &ResultRegTypes, > + std::vector<llvm::Type *> > &ResultTruncRegTypes, > + std::vector<LValue> &ResultRegDests, > + std::string &AsmString, > + unsigned NumOutputs) const override; > + > llvm::Constant * > getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { > unsigned Sig = (0xeb << 0) | // jmp rel8 > @@ -606,6 +615,85 @@ public: > > } > > +/// Rewrite input constraint references after adding some output constraints. > +/// In the case where there is one output and one input and we add one > output, > +/// we need to replace all operand references greater than or equal to 1: > +/// mov $0, $1 > +/// mov eax, $1 > +/// The result will be: > +/// mov $0, $2 > +/// mov eax, $2 > +static void rewriteInputConstraintReferences(unsigned FirstIn, > + unsigned NumNewOuts, > + std::string &AsmString) { > + std::string Buf; > + llvm::raw_string_ostream OS(Buf); > + size_t Pos = 0; > + while (Pos < AsmString.size()) { > + size_t DollarStart = AsmString.find('$', Pos); > + if (DollarStart == std::string::npos) > + DollarStart = AsmString.size(); > + size_t DollarEnd = AsmString.find_first_not_of('$', DollarStart); > + if (DollarEnd == std::string::npos) > + DollarEnd = AsmString.size(); > + OS << StringRef(&AsmString[Pos], DollarEnd - Pos); > + Pos = DollarEnd; > + size_t NumDollars = DollarEnd - DollarStart; > + if (NumDollars % 2 != 0 && Pos < AsmString.size()) { > + // We have an operand reference. > + size_t DigitStart = Pos; > + size_t DigitEnd = AsmString.find_first_not_of("0123456789", > DigitStart); > + if (DigitEnd == std::string::npos) > + DigitEnd = AsmString.size(); > + StringRef OperandStr(&AsmString[DigitStart], DigitEnd - DigitStart); > + unsigned OperandIndex; > + if (!OperandStr.getAsInteger(10, OperandIndex)) { > + if (OperandIndex >= FirstIn) > + OperandIndex += NumNewOuts; > + OS << OperandIndex; > + } else { > + OS << OperandStr; > + } > + Pos = DigitEnd; > + } > + } > + AsmString = std::move(OS.str()); > +} > + > +/// Add output constraints for EAX:EDX because they are return registers. > +void X86_32TargetCodeGenInfo::addReturnRegisterOutputs( > + CodeGenFunction &CGF, LValue ReturnSlot, std::string &Constraints, > + std::vector<llvm::Type *> &ResultRegTypes, > + std::vector<llvm::Type *> &ResultTruncRegTypes, > + std::vector<LValue> &ResultRegDests, std::string &AsmString, > + unsigned NumOutputs) const { > + uint64_t RetWidth = CGF.getContext().getTypeSize(ReturnSlot.getType()); > + > + // Use the EAX constraint if the width is 32 or smaller and EAX:EDX if it > is > + // larger. > + if (!Constraints.empty()) > + Constraints += ','; > + if (RetWidth <= 32) { > + Constraints += "={eax}"; > + ResultRegTypes.push_back(CGF.Int32Ty); > + } else { > + // Use the 'A' constraint for EAX:EDX. > + Constraints += "=A"; > + ResultRegTypes.push_back(CGF.Int64Ty); > + } > + > + // Truncate EAX or EAX:EDX to an integer of the appropriate size. > + llvm::Type *CoerceTy = llvm::IntegerType::get(CGF.getLLVMContext(), > RetWidth); > + ResultTruncRegTypes.push_back(CoerceTy); > + > + // Coerce the integer by bitcasting the return slot pointer. > + ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(), > + CoerceTy->getPointerTo())); > + ResultRegDests.push_back(ReturnSlot); > + > + rewriteInputConstraintReferences(NumOutputs, 1, AsmString); > +} > + > /// shouldReturnTypeInRegister - Determine if the given type should be > /// passed in a register (for the Darwin ABI). > bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, > > Modified: cfe/trunk/lib/CodeGen/TargetInfo.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/TargetInfo.h (original) > +++ cfe/trunk/lib/CodeGen/TargetInfo.h Thu Sep 4 15:04:38 2014 > @@ -15,6 +15,7 @@ > #ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H > #define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H > > +#include "CGValue.h" > #include "clang/AST/Type.h" > #include "clang/Basic/LLVM.h" > #include "llvm/ADT/SmallString.h" > @@ -129,6 +130,14 @@ public: > return Ty; > } > > + /// Adds constraints and types for result registers. > + virtual void addReturnRegisterOutputs( > + CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue, > + std::string &Constraints, std::vector<llvm::Type *> &ResultRegTypes, > + std::vector<llvm::Type *> &ResultTruncRegTypes, > + std::vector<CodeGen::LValue> &ResultRegDests, std::string &AsmString, > + unsigned NumOutputs) const {} > + > /// doesReturnSlotInterfereWithArgs - Return true if the target uses an > /// argument slot for an 'sret' type. > virtual bool doesReturnSlotInterfereWithArgs() const { return true; } > > Modified: cfe/trunk/test/CodeGen/ms-inline-asm.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ms-inline-asm.c?rev=217187&r1=217186&r2=217187&view=diff > ============================================================================== > --- cfe/trunk/test/CodeGen/ms-inline-asm.c (original) > +++ cfe/trunk/test/CodeGen/ms-inline-asm.c Thu Sep 4 15:04:38 2014 > @@ -66,7 +66,7 @@ int t8() { > __asm int 4 > return 10; > // CHECK: t8 > -// CHECK: call void asm sideeffect inteldialect "int $$4\0A\09int $$4", > "~{dirflag},~{fpsr},~{flags}"() > +// CHECK: call i32 asm sideeffect inteldialect "int $$4\0A\09int $$4", > "={eax},~{dirflag},~{fpsr},~{flags}"() > // CHECK: ret i32 10 > } > > @@ -88,10 +88,11 @@ unsigned t10(void) { > } > return j; > // CHECK: t10 > +// CHECK: [[r:%[a-zA-Z0-9]+]] = alloca i32, align 4 > // CHECK: [[I:%[a-zA-Z0-9]+]] = alloca i32, align 4 > // CHECK: [[J:%[a-zA-Z0-9]+]] = alloca i32, align 4 > // CHECK: store i32 1, i32* [[I]], align 4 > -// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr > $1\0A\09mov dword ptr $0, eax", > "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}) > +// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr > $2\0A\09mov dword ptr $0, eax", > "=*m,={eax},*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}) > // CHECK: [[RET:%[a-zA-Z0-9]+]] = load i32* [[J]], align 4 > // CHECK: ret i32 [[RET]] > } > @@ -112,7 +113,7 @@ unsigned t12(void) { > } > return j + m; > // CHECK: t12 > -// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr > $2\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $3\0A\09mov dword ptr > $1, eax", "=*m,=*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, > i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}) > +// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr > $3\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $4\0A\09mov dword ptr > $1, eax", "=*m,=*m,={eax},*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* > %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}) > } > > void t13() { > @@ -319,11 +320,11 @@ int *t30() > { > int *res; > __asm lea edi, results > -// CHECK: lea edi, dword ptr $1 > +// CHECK: lea edi, dword ptr $2 > __asm mov res, edi > // CHECK: mov dword ptr $0, edi > return res; > -// CHECK: "=*m,*m,~{edi},~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}}, [2 x > i32]* @{{.*}}) > +// CHECK: "=*m,={eax},*m,~{edi},~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}}, > [2 x i32]* @{{.*}}) > } > > void t31() { > > Added: cfe/trunk/test/CodeGenCXX/ms-inline-asm-return.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ms-inline-asm-return.cpp?rev=217187&view=auto > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/ms-inline-asm-return.cpp (added) > +++ cfe/trunk/test/CodeGenCXX/ms-inline-asm-return.cpp Thu Sep 4 15:04:38 > 2014 > @@ -0,0 +1,99 @@ > +// RUN: %clang_cc1 %s -emit-llvm -o - -fasm-blocks | FileCheck %s > + > +// Check that we take EAX or EAX:EDX and return it from these functions for > MSVC > +// compatibility. > + > +extern "C" { > + > +long long f_i64() { > + __asm { > + mov eax, 1 > + mov edx, 1 > + } > +} > +// CHECK-LABEL: define i64 @f_i64() > +// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, > $$1\0A\09mov edx, $$1", "=A,~{eax},{{.*}}" > +// CHECK: ret i64 %[[r]] > + > +int f_i32() { > + __asm { > + mov eax, 1 > + mov edx, 1 > + } > +} > +// CHECK-LABEL: define i32 @f_i32() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, > $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}" > +// CHECK: ret i32 %[[r]] > + > +short f_i16() { > + __asm { > + mov eax, 1 > + mov edx, 1 > + } > +} > +// CHECK-LABEL: define signext i16 @f_i16() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, > $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}" > +// CHECK: %[[r_i16:[^ ]*]] = trunc i32 %[[r]] to i16 > +// CHECK: ret i16 %[[r_i16]] > + > +char f_i8() { > + __asm { > + mov eax, 1 > + mov edx, 1 > + } > +} > +// CHECK-LABEL: define signext i8 @f_i8() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, > $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}" > +// CHECK: %[[r_i8:[^ ]*]] = trunc i32 %[[r]] to i8 > +// CHECK: ret i8 %[[r_i8]] > + > +bool f_i1() { > + __asm { > + mov eax, 1 > + mov edx, 1 > + } > +} > +// CHECK-LABEL: define zeroext i1 @f_i1() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, > $$1\0A\09mov edx, $$1", "={eax},~{eax},{{.*}}" > +// CHECK: %[[r_i8:[^ ]*]] = trunc i32 %[[r]] to i8 > +// CHECK: store i8 %[[r_i8]], i8* %{{.*}} > +// CHECK: %[[r_i1:[^ ]*]] = load i1* %{{.*}} > +// CHECK: ret i1 %[[r_i1]] > + > +struct FourChars { > + char a, b, c, d; > +}; > +FourChars f_s4() { > + __asm { > + mov eax, 0x01010101 > + } > +} > +// CHECK-LABEL: define i32 @f_s4() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, > $$0x01010101", "={eax},~{eax},{{.*}}" > +// CHECK: store i32 %[[r]], i32* %{{.*}} > +// CHECK: %[[r_i32:[^ ]*]] = load i32* %{{.*}} > +// CHECK: ret i32 %[[r_i32]] > + > +struct EightChars { > + char a, b, c, d, e, f, g, h; > +}; > +EightChars f_s8() { > + __asm { > + mov eax, 0x01010101 > + mov edx, 0x01010101 > + } > +} > +// CHECK-LABEL: define i64 @f_s8() > +// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, > $$0x01010101\0A\09mov edx, $$0x01010101", "=A,~{eax},{{.*}}" > +// CHECK: store i64 %[[r]], i64* %{{.*}} > +// CHECK: %[[r_i64:[^ ]*]] = load i64* %{{.*}} > +// CHECK: ret i64 %[[r_i64]] > + > +} // extern "C" > + > +int main() { > + __asm xor eax, eax > +} > +// CHECK-LABEL: define i32 @main() > +// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "xor eax, > eax", "={eax},{{.*}}" > +// CHECK: ret i32 %[[r]] > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
