From: Chris Lattner Date: Sun, 3 May 2009 08:21:20 +0000 (+0000) Subject: add support for tying asm operands where the result is smaller than X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a077b5c8631596f8d7a588933a9de5d08e9ba428;p=clang add support for tying asm operands where the result is smaller than the input. This is part of PR3373. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70677 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index aefb3e5f95..fb6d121eef 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -805,9 +805,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector ResultRegDests; std::vector ResultRegQualTys; - - std::vector ResultTypes; - + std::vector ResultRegTypes; + std::vector ResultTruncRegTypes; std::vector ArgTypes; std::vector Args; @@ -832,11 +831,38 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (!Constraints.empty()) Constraints += ','; + // If this is a register output, then make the inline asm return it + // by-value. If this is a memory result, return the value by-reference. if (!Info.allowsMemory() && !hasAggregateLLVMType(OutExpr->getType())) { + Constraints += "=" + OutputConstraint; ResultRegQualTys.push_back(OutExpr->getType()); ResultRegDests.push_back(Dest); - ResultTypes.push_back(ConvertTypeForMem(OutExpr->getType())); - Constraints += "=" + OutputConstraint; + ResultRegTypes.push_back(ConvertTypeForMem(OutExpr->getType())); + ResultTruncRegTypes.push_back(ResultRegTypes.back()); + + // If this output is tied to an input, and if the input is larger, then + // we need to set the actual result type of the inline asm node to be the + // same as the input type. + if (Info.hasMatchingInput()) { + unsigned InputNo = ~0; + for (unsigned i = 0, e = S.getNumInputs(); i != e; ++i) + if (InputConstraintInfos[i].hasTiedOperand() && + InputConstraintInfos[i].getTiedOperand() == i) { + InputNo = i; + break; + } + assert(InputNo != ~0U && "Didn't find matching input!"); + + QualType InputTy = S.getInputExpr(InputNo)->getType(); + QualType OutputTy = OutExpr->getType(); + + uint64_t InputSize = getContext().getTypeSize(InputTy); + if (getContext().getTypeSize(OutputTy) < InputSize) { + // Form the asm to return the value as a larger integer type. + ResultRegTypes.back() = llvm::IntegerType::get((unsigned)InputSize); + } + } + } else { ArgTypes.push_back(Dest.getAddress()->getType()); Args.push_back(Dest.getAddress()); @@ -935,12 +961,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { } const llvm::Type *ResultType; - if (ResultTypes.empty()) + if (ResultRegTypes.empty()) ResultType = llvm::Type::VoidTy; - else if (ResultTypes.size() == 1) - ResultType = ResultTypes[0]; + else if (ResultRegTypes.size() == 1) + ResultType = ResultRegTypes[0]; else - ResultType = llvm::StructType::get(ResultTypes); + ResultType = llvm::StructType::get(ResultRegTypes); const llvm::FunctionType *FTy = llvm::FunctionType::get(ResultType, ArgTypes, false); @@ -951,14 +977,37 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end()); Result->addAttribute(~0, llvm::Attribute::NoUnwind); - if (ResultTypes.size() == 1) { - EmitStoreThroughLValue(RValue::get(Result), ResultRegDests[0], - ResultRegQualTys[0]); + + // Extract all of the register value results from the asm. + std::vector RegResults; + if (ResultRegTypes.size() == 1) { + RegResults.push_back(Result); } else { - for (unsigned i = 0, e = ResultTypes.size(); i != e; ++i) { + for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) { llvm::Value *Tmp = Builder.CreateExtractValue(Result, i, "asmresult"); - EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i], - ResultRegQualTys[i]); + RegResults.push_back(Tmp); + } + } + + for (unsigned i = 0, e = RegResults.size(); i != e; ++i) { + llvm::Value *Tmp = RegResults[i]; + + // If the result type of the LLVM IR asm doesn't match the result type of + // the expression, do the conversion. + if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { + const llvm::Type *TruncTy = ResultTruncRegTypes[i]; + // Truncate the integer result to the right size, note that + // ResultTruncRegTypes can be a pointer. + uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); + Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get((unsigned)ResSize)); + + if (Tmp->getType() != TruncTy) { + assert(isa(TruncTy)); + Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); + } } + + EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i], + ResultRegQualTys[i]); } } diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c index 92ba31baa5..d7309149eb 100644 --- a/test/CodeGen/asm.c +++ b/test/CodeGen/asm.c @@ -60,7 +60,14 @@ unsigned t11(signed char input) { return output; } - +// PR3373 +unsigned char t12(unsigned input) { + unsigned char output; + __asm__("xyz" + : "=a" (output) + : "0" (input)); + return output; +} struct S {