unsigned InputNo;
for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
- if (Input.hasTiedOperand() &&
- Input.getTiedOperand() == i)
+ if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
break;
}
assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
QualType InputTy = S.getInputExpr(InputNo)->getType();
- QualType OutputTy = OutExpr->getType();
+ QualType OutputType = 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(VMContext, (unsigned)InputSize);
+ if (getContext().getTypeSize(OutputType) < InputSize) {
+ // Form the asm to return the value as a larger integer or fp type.
+ ResultRegTypes.back() = ConvertType(InputTy);
}
}
} else {
// that is usually cheaper, but LLVM IR should really get an anyext someday.
if (Info.hasTiedOperand()) {
unsigned Output = Info.getTiedOperand();
- QualType OutputTy = S.getOutputExpr(Output)->getType();
+ QualType OutputType = S.getOutputExpr(Output)->getType();
QualType InputTy = InputExpr->getType();
- if (getContext().getTypeSize(OutputTy) >
+ if (getContext().getTypeSize(OutputType) >
getContext().getTypeSize(InputTy)) {
// Use ptrtoint as appropriate so that we can do our extension.
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg,
llvm::IntegerType::get(VMContext, LLVMPointerWidth));
- unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy);
- Arg = Builder.CreateZExt(Arg,
- llvm::IntegerType::get(VMContext, OutputSize));
+ const llvm::Type *OutputTy = ConvertType(OutputType);
+ if (isa<llvm::IntegerType>(OutputTy))
+ Arg = Builder.CreateZExt(Arg, OutputTy);
+ else
+ Arg = Builder.CreateFPExt(Arg, OutputTy);
}
}
// 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(VMContext, (unsigned)ResSize));
-
- if (Tmp->getType() != TruncTy) {
- assert(isa<llvm::PointerType>(TruncTy));
+
+ // Truncate the integer result to the right size, note that TruncTy can be
+ // a pointer.
+ if (TruncTy->isFloatingPointTy())
+ Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
+ else if (!isa<llvm::PointerType>(TruncTy))
+ Tmp = Builder.CreateTrunc(Tmp, TruncTy);
+ else {
+ uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext,
+ (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
}
}
if (Context.hasSameType(InTy, OutTy))
continue; // All types can be tied to themselves.
- // Int/ptr operands have some special cases that we allow.
- if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
- (InTy->isIntegerType() || InTy->isPointerType())) {
-
- // They are ok if they are the same size. Tying void* to int is ok if
- // they are the same size, for example. This also allows tying void* to
- // int*.
- uint64_t OutSize = Context.getTypeSize(OutTy);
- uint64_t InSize = Context.getTypeSize(InTy);
- if (OutSize == InSize)
- continue;
-
- // If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote it and the asm string won't notice. Check this
- // case now.
- bool SmallerValueMentioned = false;
- for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
- AsmStmt::AsmStringPiece &Piece = Pieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == i+NumOutputs) {
- if (InSize < OutSize) {
- SmallerValueMentioned = true;
- break;
- }
- }
+ // Decide if the input and output are in the same domain (integer/ptr or
+ // floating point.
+ enum AsmDomain {
+ AD_Int, AD_FP, AD_Other
+ } InputDomain, OutputDomain;
+
+ if (InTy->isIntegerType() || InTy->isPointerType())
+ InputDomain = AD_Int;
+ else if (InTy->isFloatingType())
+ InputDomain = AD_FP;
+ else
+ InputDomain = AD_Other;
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == TiedTo) {
- if (InSize > OutSize) {
- SmallerValueMentioned = true;
- break;
- }
+ if (OutTy->isIntegerType() || OutTy->isPointerType())
+ OutputDomain = AD_Int;
+ else if (OutTy->isFloatingType())
+ OutputDomain = AD_FP;
+ else
+ OutputDomain = AD_Other;
+
+ // They are ok if they are the same size and in the same domain. This
+ // allows tying things like:
+ // void* to int*
+ // void* to int if they are the same size.
+ // double to long double if they are the same size.
+ //
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize && InputDomain == OutputDomain &&
+ InputDomain != AD_Other)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote it and the asm string won't notice. Check this
+ // case now.
+ bool SmallerValueMentioned = false;
+ for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
+ AsmStmt::AsmStringPiece &Piece = Pieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == i+NumOutputs) {
+ if (InSize < OutSize) {
+ SmallerValueMentioned = true;
+ break;
}
}
- // If the smaller value wasn't mentioned in the asm string, and if the
- // output was a register, just extend the shorter one to the size of the
- // larger one.
- if (!SmallerValueMentioned &&
- OutputConstraintInfos[TiedTo].allowsRegister())
- continue;
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == TiedTo) {
+ if (InSize > OutSize) {
+ SmallerValueMentioned = true;
+ break;
+ }
+ }
}
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned && InputDomain != AD_Other &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()