Changeset View
Standalone View
clang/lib/CodeGen/CGCall.cpp
Show First 20 Lines • Show All 2,040 Lines • ▼ Show 20 Lines | if (const MatrixType *Matrix = dyn_cast<MatrixType>(QTy)) | ||||||||||||||||||||||||||||||||
return DetermineNoUndef(Matrix->getElementType(), Types, DL, AI, false); | return DetermineNoUndef(Matrix->getElementType(), Types, DL, AI, false); | ||||||||||||||||||||||||||||||||
if (const ArrayType *Array = dyn_cast<ArrayType>(QTy)) | if (const ArrayType *Array = dyn_cast<ArrayType>(QTy)) | ||||||||||||||||||||||||||||||||
return DetermineNoUndef(Array->getElementType(), Types, DL, AI, false); | return DetermineNoUndef(Array->getElementType(), Types, DL, AI, false); | ||||||||||||||||||||||||||||||||
// TODO: Some structs may be `noundef`, in specific situations. | // TODO: Some structs may be `noundef`, in specific situations. | ||||||||||||||||||||||||||||||||
return false; | return false; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
/// Check if the argument of a function has maybe_undef attribute. | |||||||||||||||||||||||||||||||||
static bool IsArgumentMaybeUndef(const Decl *TargetDecl, | |||||||||||||||||||||||||||||||||
unsigned NumRequiredArgs, unsigned ArgNo) { | |||||||||||||||||||||||||||||||||
const auto *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); | |||||||||||||||||||||||||||||||||
if (!FD) | |||||||||||||||||||||||||||||||||
return false; | |||||||||||||||||||||||||||||||||
// Assume variadic arguments do not have maybe_undef attribute. | |||||||||||||||||||||||||||||||||
if (ArgNo >= NumRequiredArgs) | |||||||||||||||||||||||||||||||||
return false; | |||||||||||||||||||||||||||||||||
// Check if argument has maybe_undef attribute. | |||||||||||||||||||||||||||||||||
if (ArgNo < FD->getNumParams()) { | |||||||||||||||||||||||||||||||||
jdoerfert: Early exists please.
if (!TargetDecl)
return false
no ArgHasMayBeUndefAttr is needed, just… | |||||||||||||||||||||||||||||||||
const ParmVarDecl *Param = FD->getParamDecl(ArgNo); | |||||||||||||||||||||||||||||||||
if (Param && Param->hasAttr<MaybeUndefAttr>()) | |||||||||||||||||||||||||||||||||
return true; | |||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||
Not Done ReplyInline Actions
aaron.ballman: | |||||||||||||||||||||||||||||||||
Not Done ReplyInline Actions
One question I have is whether you ever need to mark the variadic arguments as being maybe undef. e.g., void func(int i, ...); do you need to signal that arguments passed to ... are maybe undef? aaron.ballman: One question I have is whether you ever need to mark the variadic arguments as being maybe… | |||||||||||||||||||||||||||||||||
Not Done ReplyInline ActionsCurrent change assumes variadic arguments will not have "maybe_undef" attribute. If its a function attribute, variadic arguments can inherit them (Have seen such cases in clang codebase). But "maybe_undef" is function argument attribute and I'm not sure on how to add it to variadic arguments. skc7: Current change assumes variadic arguments will not have "maybe_undef" attribute. If its a… | |||||||||||||||||||||||||||||||||
Not Done ReplyInline Actions
That's why I was asking if there will be a need either now or in the future -- is making this a parameter attribute the right design, or should this be a function attribute with positional arguments? (Not that I particularly love that design, but this isn't a user-facing attribute so if it's hard to use, I'm not that worried. I just want to make sure we don't need to add additional attributes in the future in this same space.) aaron.ballman: > Current change assumes variadic arguments will not have "maybe_undef" attribute. If its a… | |||||||||||||||||||||||||||||||||
return false; | |||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||
/// Construct the IR attribute list of a function or call. | /// Construct the IR attribute list of a function or call. | ||||||||||||||||||||||||||||||||
/// | /// | ||||||||||||||||||||||||||||||||
/// When adding an attribute, please consider where it should be handled: | /// When adding an attribute, please consider where it should be handled: | ||||||||||||||||||||||||||||||||
/// | /// | ||||||||||||||||||||||||||||||||
/// - getDefaultFunctionAttributes is for attributes that are essentially | /// - getDefaultFunctionAttributes is for attributes that are essentially | ||||||||||||||||||||||||||||||||
/// part of the global target configuration (but perhaps can be | /// part of the global target configuration (but perhaps can be | ||||||||||||||||||||||||||||||||
/// overridden on a per-function basis). Adding attributes there | /// overridden on a per-function basis). Adding attributes there | ||||||||||||||||||||||||||||||||
/// will cause them to also be set in frontends that build on Clang's | /// will cause them to also be set in frontends that build on Clang's | ||||||||||||||||||||||||||||||||
▲ Show 20 Lines • Show All 2,759 Lines • ▼ Show 20 Lines | for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); | ||||||||||||||||||||||||||||||||
// Insert a padding argument to ensure proper alignment. | // Insert a padding argument to ensure proper alignment. | ||||||||||||||||||||||||||||||||
if (IRFunctionArgs.hasPaddingArg(ArgNo)) | if (IRFunctionArgs.hasPaddingArg(ArgNo)) | ||||||||||||||||||||||||||||||||
IRCallArgs[IRFunctionArgs.getPaddingArgNo(ArgNo)] = | IRCallArgs[IRFunctionArgs.getPaddingArgNo(ArgNo)] = | ||||||||||||||||||||||||||||||||
llvm::UndefValue::get(ArgInfo.getPaddingType()); | llvm::UndefValue::get(ArgInfo.getPaddingType()); | ||||||||||||||||||||||||||||||||
unsigned FirstIRArg, NumIRArgs; | unsigned FirstIRArg, NumIRArgs; | ||||||||||||||||||||||||||||||||
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); | std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); | ||||||||||||||||||||||||||||||||
bool ArgHasMaybeUndefAttr = | |||||||||||||||||||||||||||||||||
IsArgumentMaybeUndef(TargetDecl, CallInfo.getNumRequiredArgs(), ArgNo); | |||||||||||||||||||||||||||||||||
switch (ArgInfo.getKind()) { | switch (ArgInfo.getKind()) { | ||||||||||||||||||||||||||||||||
case ABIArgInfo::InAlloca: { | case ABIArgInfo::InAlloca: { | ||||||||||||||||||||||||||||||||
assert(NumIRArgs == 0); | assert(NumIRArgs == 0); | ||||||||||||||||||||||||||||||||
assert(getTarget().getTriple().getArch() == llvm::Triple::x86); | assert(getTarget().getTriple().getArch() == llvm::Triple::x86); | ||||||||||||||||||||||||||||||||
if (I->isAggregate()) { | if (I->isAggregate()) { | ||||||||||||||||||||||||||||||||
Address Addr = I->hasLValue() | Address Addr = I->hasLValue() | ||||||||||||||||||||||||||||||||
? I->getKnownLValue().getAddress(*this) | ? I->getKnownLValue().getAddress(*this) | ||||||||||||||||||||||||||||||||
: I->getKnownRValue().getAggregateAddress(); | : I->getKnownRValue().getAggregateAddress(); | ||||||||||||||||||||||||||||||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); | ||||||||||||||||||||||||||||||||
case ABIArgInfo::Indirect: | case ABIArgInfo::Indirect: | ||||||||||||||||||||||||||||||||
case ABIArgInfo::IndirectAliased: { | case ABIArgInfo::IndirectAliased: { | ||||||||||||||||||||||||||||||||
assert(NumIRArgs == 1); | assert(NumIRArgs == 1); | ||||||||||||||||||||||||||||||||
if (!I->isAggregate()) { | if (!I->isAggregate()) { | ||||||||||||||||||||||||||||||||
// Make a temporary alloca to pass the argument. | // Make a temporary alloca to pass the argument. | ||||||||||||||||||||||||||||||||
Address Addr = CreateMemTempWithoutCast( | Address Addr = CreateMemTempWithoutCast( | ||||||||||||||||||||||||||||||||
I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); | I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); | ||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = Addr.getPointer(); | |||||||||||||||||||||||||||||||||
llvm::Value *Val = Addr.getPointer(); | |||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
Val = Builder.CreateFreeze(Addr.getPointer()); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = Val; | |||||||||||||||||||||||||||||||||
Not Done ReplyInline ActionsStyle: Val, also below. jdoerfert: Style: `Val`, also below. | |||||||||||||||||||||||||||||||||
I->copyInto(*this, Addr); | I->copyInto(*this, Addr); | ||||||||||||||||||||||||||||||||
} else { | } else { | ||||||||||||||||||||||||||||||||
// We want to avoid creating an unnecessary temporary+copy here; | // We want to avoid creating an unnecessary temporary+copy here; | ||||||||||||||||||||||||||||||||
// however, we need one in three cases: | // however, we need one in three cases: | ||||||||||||||||||||||||||||||||
// 1. If the argument is not byval, and we are required to copy the | // 1. If the argument is not byval, and we are required to copy the | ||||||||||||||||||||||||||||||||
// source. (This case doesn't occur on any common architecture.) | // source. (This case doesn't occur on any common architecture.) | ||||||||||||||||||||||||||||||||
// 2. If the argument is byval, RV is not sufficiently aligned, and | // 2. If the argument is byval, RV is not sufficiently aligned, and | ||||||||||||||||||||||||||||||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | case ABIArgInfo::IndirectAliased: { | ||||||||||||||||||||||||||||||||
NeedCopy = true; | NeedCopy = true; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
if (NeedCopy) { | if (NeedCopy) { | ||||||||||||||||||||||||||||||||
// Create an aligned temporary, and copy to it. | // Create an aligned temporary, and copy to it. | ||||||||||||||||||||||||||||||||
Address AI = CreateMemTempWithoutCast( | Address AI = CreateMemTempWithoutCast( | ||||||||||||||||||||||||||||||||
I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); | I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); | ||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = AI.getPointer(); | llvm::Value *Val = AI.getPointer(); | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
Val = Builder.CreateFreeze(AI.getPointer()); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = Val; | |||||||||||||||||||||||||||||||||
// Emit lifetime markers for the temporary alloca. | // Emit lifetime markers for the temporary alloca. | ||||||||||||||||||||||||||||||||
llvm::TypeSize ByvalTempElementSize = | llvm::TypeSize ByvalTempElementSize = | ||||||||||||||||||||||||||||||||
CGM.getDataLayout().getTypeAllocSize(AI.getElementType()); | CGM.getDataLayout().getTypeAllocSize(AI.getElementType()); | ||||||||||||||||||||||||||||||||
llvm::Value *LifetimeSize = | llvm::Value *LifetimeSize = | ||||||||||||||||||||||||||||||||
EmitLifetimeStart(ByvalTempElementSize, AI.getPointer()); | EmitLifetimeStart(ByvalTempElementSize, AI.getPointer()); | ||||||||||||||||||||||||||||||||
// Add cleanup code to emit the end lifetime marker after the call. | // Add cleanup code to emit the end lifetime marker after the call. | ||||||||||||||||||||||||||||||||
if (LifetimeSize) // In case we disabled lifetime markers. | if (LifetimeSize) // In case we disabled lifetime markers. | ||||||||||||||||||||||||||||||||
CallLifetimeEndAfterCall.emplace_back(AI, LifetimeSize); | CallLifetimeEndAfterCall.emplace_back(AI, LifetimeSize); | ||||||||||||||||||||||||||||||||
// Generate the copy. | // Generate the copy. | ||||||||||||||||||||||||||||||||
I->copyInto(*this, AI); | I->copyInto(*this, AI); | ||||||||||||||||||||||||||||||||
} else { | } else { | ||||||||||||||||||||||||||||||||
// Skip the extra memcpy call. | // Skip the extra memcpy call. | ||||||||||||||||||||||||||||||||
auto *T = llvm::PointerType::getWithSamePointeeType( | auto *T = llvm::PointerType::getWithSamePointeeType( | ||||||||||||||||||||||||||||||||
cast<llvm::PointerType>(V->getType()), | cast<llvm::PointerType>(V->getType()), | ||||||||||||||||||||||||||||||||
CGM.getDataLayout().getAllocaAddrSpace()); | CGM.getDataLayout().getAllocaAddrSpace()); | ||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast( | |||||||||||||||||||||||||||||||||
llvm::Value *Val = getTargetHooks().performAddrSpaceCast( | |||||||||||||||||||||||||||||||||
*this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T, | *this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T, | ||||||||||||||||||||||||||||||||
true); | true); | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
Val = Builder.CreateFreeze(Val); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = Val; | |||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
break; | break; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
case ABIArgInfo::Ignore: | case ABIArgInfo::Ignore: | ||||||||||||||||||||||||||||||||
assert(NumIRArgs == 0); | assert(NumIRArgs == 0); | ||||||||||||||||||||||||||||||||
break; | break; | ||||||||||||||||||||||||||||||||
Show All 37 Lines | case ABIArgInfo::Direct: { | ||||||||||||||||||||||||||||||||
V = Builder.CreateZExt(V, ArgInfo.getCoerceToType()); | V = Builder.CreateZExt(V, ArgInfo.getCoerceToType()); | ||||||||||||||||||||||||||||||||
// If the argument doesn't match, perform a bitcast to coerce it. This | // If the argument doesn't match, perform a bitcast to coerce it. This | ||||||||||||||||||||||||||||||||
// can happen due to trivial type mismatches. | // can happen due to trivial type mismatches. | ||||||||||||||||||||||||||||||||
if (FirstIRArg < IRFuncTy->getNumParams() && | if (FirstIRArg < IRFuncTy->getNumParams() && | ||||||||||||||||||||||||||||||||
V->getType() != IRFuncTy->getParamType(FirstIRArg)) | V->getType() != IRFuncTy->getParamType(FirstIRArg)) | ||||||||||||||||||||||||||||||||
V = Builder.CreateBitCast(V, IRFuncTy->getParamType(FirstIRArg)); | V = Builder.CreateBitCast(V, IRFuncTy->getParamType(FirstIRArg)); | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
V = Builder.CreateFreeze(V); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = V; | IRCallArgs[FirstIRArg] = V; | ||||||||||||||||||||||||||||||||
break; | break; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
// FIXME: Avoid the conversion through memory if possible. | // FIXME: Avoid the conversion through memory if possible. | ||||||||||||||||||||||||||||||||
Address Src = Address::invalid(); | Address Src = Address::invalid(); | ||||||||||||||||||||||||||||||||
if (!I->isAggregate()) { | if (!I->isAggregate()) { | ||||||||||||||||||||||||||||||||
Src = CreateMemTemp(I->Ty, "coerce"); | Src = CreateMemTemp(I->Ty, "coerce"); | ||||||||||||||||||||||||||||||||
Show All 28 Lines | case ABIArgInfo::Direct: { | ||||||||||||||||||||||||||||||||
} else { | } else { | ||||||||||||||||||||||||||||||||
Src = Builder.CreateElementBitCast(Src, STy); | Src = Builder.CreateElementBitCast(Src, STy); | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
assert(NumIRArgs == STy->getNumElements()); | assert(NumIRArgs == STy->getNumElements()); | ||||||||||||||||||||||||||||||||
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { | for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { | ||||||||||||||||||||||||||||||||
Address EltPtr = Builder.CreateStructGEP(Src, i); | Address EltPtr = Builder.CreateStructGEP(Src, i); | ||||||||||||||||||||||||||||||||
llvm::Value *LI = Builder.CreateLoad(EltPtr); | llvm::Value *LI = Builder.CreateLoad(EltPtr); | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
LI = Builder.CreateFreeze(LI); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg + i] = LI; | IRCallArgs[FirstIRArg + i] = LI; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
} else { | } else { | ||||||||||||||||||||||||||||||||
// In the simple case, just pass the coerced loaded value. | // In the simple case, just pass the coerced loaded value. | ||||||||||||||||||||||||||||||||
assert(NumIRArgs == 1); | assert(NumIRArgs == 1); | ||||||||||||||||||||||||||||||||
llvm::Value *Load = | llvm::Value *Load = | ||||||||||||||||||||||||||||||||
CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this); | CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this); | ||||||||||||||||||||||||||||||||
if (CallInfo.isCmseNSCall()) { | if (CallInfo.isCmseNSCall()) { | ||||||||||||||||||||||||||||||||
// For certain parameter types, clear padding bits, as they may reveal | // For certain parameter types, clear padding bits, as they may reveal | ||||||||||||||||||||||||||||||||
// sensitive information. | // sensitive information. | ||||||||||||||||||||||||||||||||
// Small struct/union types are passed as integer arrays. | // Small struct/union types are passed as integer arrays. | ||||||||||||||||||||||||||||||||
auto *ATy = dyn_cast<llvm::ArrayType>(Load->getType()); | auto *ATy = dyn_cast<llvm::ArrayType>(Load->getType()); | ||||||||||||||||||||||||||||||||
if (ATy != nullptr && isa<RecordType>(I->Ty.getCanonicalType())) | if (ATy != nullptr && isa<RecordType>(I->Ty.getCanonicalType())) | ||||||||||||||||||||||||||||||||
Load = EmitCMSEClearRecord(Load, ATy, I->Ty); | Load = EmitCMSEClearRecord(Load, ATy, I->Ty); | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
Load = Builder.CreateFreeze(Load); | |||||||||||||||||||||||||||||||||
IRCallArgs[FirstIRArg] = Load; | IRCallArgs[FirstIRArg] = Load; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
break; | break; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
case ABIArgInfo::CoerceAndExpand: { | case ABIArgInfo::CoerceAndExpand: { | ||||||||||||||||||||||||||||||||
auto coercionType = ArgInfo.getCoerceAndExpandType(); | auto coercionType = ArgInfo.getCoerceAndExpandType(); | ||||||||||||||||||||||||||||||||
Show All 29 Lines | case ABIArgInfo::CoerceAndExpand: { | ||||||||||||||||||||||||||||||||
addr = Builder.CreateElementBitCast(addr, coercionType); | addr = Builder.CreateElementBitCast(addr, coercionType); | ||||||||||||||||||||||||||||||||
unsigned IRArgPos = FirstIRArg; | unsigned IRArgPos = FirstIRArg; | ||||||||||||||||||||||||||||||||
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) { | for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) { | ||||||||||||||||||||||||||||||||
llvm::Type *eltType = coercionType->getElementType(i); | llvm::Type *eltType = coercionType->getElementType(i); | ||||||||||||||||||||||||||||||||
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue; | if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue; | ||||||||||||||||||||||||||||||||
Address eltAddr = Builder.CreateStructGEP(addr, i); | Address eltAddr = Builder.CreateStructGEP(addr, i); | ||||||||||||||||||||||||||||||||
llvm::Value *elt = Builder.CreateLoad(eltAddr); | llvm::Value *elt = Builder.CreateLoad(eltAddr); | ||||||||||||||||||||||||||||||||
if (ArgHasMaybeUndefAttr) | |||||||||||||||||||||||||||||||||
elt = Builder.CreateFreeze(elt); | |||||||||||||||||||||||||||||||||
IRCallArgs[IRArgPos++] = elt; | IRCallArgs[IRArgPos++] = elt; | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
assert(IRArgPos == FirstIRArg + NumIRArgs); | assert(IRArgPos == FirstIRArg + NumIRArgs); | ||||||||||||||||||||||||||||||||
if (tempSize) { | if (tempSize) { | ||||||||||||||||||||||||||||||||
EmitLifetimeEnd(tempSize, AllocaAddr.getPointer()); | EmitLifetimeEnd(tempSize, AllocaAddr.getPointer()); | ||||||||||||||||||||||||||||||||
} | } | ||||||||||||||||||||||||||||||||
▲ Show 20 Lines • Show All 494 Lines • Show Last 20 Lines |
Early exists please.
if (!TargetDecl)
no ArgHasMayBeUndefAttr is needed, just return true/false, etc.